Trident IoT Zigbee SDK
 
Loading...
Searching...
No Matches
Zigbee Command Line Interface

Back to Trident IoT SDK

Overview


The Trident Zigbee Command Line Interface (CLI) provides a way to interact with a device through a hierarchical, table driven, extensible interface. Many CLI commands are pre-defined for the Zigbee stack and for the services and ZCL plugins. Custom, user defined tables can easily be created to add project specific CLI functionality.

The most common physical interface for the CLI is through a UART, but there are other ways of capturing character strings and passing them to the CLI for parsing. One of these is the Trident Zigbee Remote CLI manufacturer specific cluster. This allows remote interaction with the CLI on a specific device through the Zigbee network rather than with a physical UART connection.

Note
The CLI supports up and down arrow command history scrolling and left and right arrow command editing

How It Works


Command Strings

The CLI is based on standard argc and argv parsing as well as optarg. argc is an integer that contains the count of the space delimited arguments passed to the CLI parser, and argv is an array of char strings, with each element being an argument. For example, the string "this is a test" will result in argc == 4, and argv being

Arg Parsing
argv[0] "this"
argv[1] "is"
argv[2] "a"
argv[3] "test"

optarg allows parsing of command arguments. The CLI uses the short form of options to keep command strings as short as possible. A command with an option will look like "send -a 0x1234". In this case, the command is "send", "-a" is an option, and 0x1234 is the argument for the "-a" option. Not all commands require options, and many commands have optional options. Also, not all command options require arguments.

Existing commands will provide a "usage" help string if they are missing required options or if the -h option is provided. Here is the usage string for the "send" command:

test> send -h
usage: send -a short addr [-d dest ep <default 1>] [-s src ep <default 1>] [-e aps encrypt <default don't aps encrypt>] [-n no aps ack <default aps ack>]

Usage string syntax puts optional options inside [] and default values of option arguments inside <>.

Command Tables

The CLI uses tables to define command strings, the function to invoke on a command string match, and a description string to display when there are no matches. Here is part of the general_commands table, which is the root table of the CLI:

TR_CLI_COMMAND_TABLE(general_commands) =
{
{ "info", cli_cmd_info, "Print device information" },
{ "reset", cli_cmd_reset, "Reset the device" },
{ "version", cli_cmd_version, "Display the stack version" },
.
.
.
TR_CLI_COMMAND_TABLE_END
};

Each table entry constitutes a CLI command. In the example above, "info" is the string that the CLI will try and match, cli_cmd_info is the function to invoke when a match is made, and "Print device information" is the description to show for that command.

Command Matching

The CLI is implemented with "exact or least character match" on command strings. This requires fewer characters in the command string input than exact match only, and has advantages when using a non-UART interface.

  • Exact match will succeed only when all characters and the string length of the command string match a command string in the table.
  • Least character match will succeed when the characters in the command string match the first n characters in the table and there is only 1 match in the table. An example of "exact or least character match" is shown below.
TR_CLI_COMMAND_TABLE(example_commands) =
{
{ "reset", cli_cmd_reset, "Reset the device" },
{ "reset_test", cli_cmd_reset_test, "Test the reset function" },
{ "reset_uart", cli_cmd_reset_uart, "Reset the UART" },
TR_CLI_COMMAND_TABLE_END
};
Command String Entered Command Matched Function Called
"reset" "reset" cli_cmd_reset
"reset_u" "reset_uart" cli_cmd_reset_uart
"reset_" no match commands and descriptions will be printed

Table Hierarchy

The CLI command table structure supports hierarchy or nested commands, resulting in command strings that simply point to a sub-table for further matching. Below is an example of nested commands.

TR_CLI_COMMAND_TABLE(example_commands) =
{
{ "info", cli_cmd_info, "Print device information" },
{ "version", cli_cmd_version, "Display the stack version" },
{ "reset", TR_CLI_SUB_COMMANDS, TR_CLI_SUB_COMMAND_TABLE(reset_commands) },
TR_CLI_COMMAND_TABLE_END
};

In the above table, the command string "reset" will pass the next argument in the command string to the reset_commands table for matching. If the reset_commands table looks like this:

TR_CLI_COMMAND_TABLE(reset_commands) =
{
{ "device", cli_cmd_reset, "Reset the device" },
{ "test", cli_cmd_reset_test, "Test the reset function" },
{ "uart", cli_cmd_reset_uart, "Reset the UART" },
TR_CLI_COMMAND_TABLE_END
};

then entering a command string of "reset" or just "res" will print the commands and their descriptions like this:

test> reset
device Reset the device
test Test the reset function
uart Reset the UART

With the sub-table, the command string matching will look like this:

Command String Entered Command Matched Function Called
"reset dev" "device" cli_cmd_reset
"reset test" "test" cli_cmd_reset_test
"reset u" "uart" cli_cmd_reset_uart

CLI Configuration


Configuring The UART

The UART configuration is done in the project tr_hal_config.h file. This is uniqe per project build target. In this file you must set the UART to be used as well as the pins for UART TX and RX. For the DKNCM11 development board, the follwing UART pin configuration should be used:

#define UART_DBG_PORT_ID 0
#define GPIO_UART_DBG_RX 16
#define GPIO_UART_DBG_TX 17

By default, the CLI UART (aka debug port) is configured as:

UART Port Settings
Baud Rate 115,200
Parity none
Data Bits 8
Stop Bits 1

Setting The Prompt

The CLI prompt can be configured in the tr_plugin_config.h file which is unique per project. Refer to the Command Line Interface (CLI) services plugin for the settings.

CLI User Extension


Refer to the Door Lock SZED sample app project for an example of a user extension of the CLI. The custom command table implementation is in src/lock_cli.c.

Configuration

Custom user command tables are enabled by defining the following macros in the project tr_plugin_config.h file.

Macro Name Value Matched Function
#define CUSTOM_CLI_COMMANDS_ENABLE
Enable the custom command table
#define CUSTOM_CLI_TOPLEVEL
"cmd_string" Define the top level command string for the custom CLI command table

Creating Command Tables

The custom command tables take the following format:

TR_CLI_COMMAND_TABLE(custom_cli_commands) =
{
{ "cmd_string", command_function, "Command description" },
.
.
{ "subcommand", TR_CLI_SUB_COMMANDS, TR_CLI_SUB_COMMAND_TABLE(name_of_subcommand_table) },
TR_CLI_COMMAND_TABLE_END
};

TR_CLI_COMMAND_TABLE is a macro used to begin the declaration of the table. The root user custom command table name must be custom_cli_commands. Command table entries can be added as needed, including adding sub-command tables as shown in Table Hierarchy. The command table(s) must be terminated with TR_CLI_COMMAND_TABLE_END. Command strings may include "-" and/or "_" and other special characters, but cannot have a space in them.

Writing CLI Functions

CLI functions take the form of:

zb_int_t command_function(zb_int_t argc,
zb_char_t *argv[])

As stated in Command Strings, argc has a value equal to the number of arguments passed to the CLI function handler, and *argv[] holds the arguments. These arguments are intended to be formatted as short options with optional arguments that can be parsed by optarg. An API, tr_cli_get_option() is available to parse options and arguments that are passed to CLI functions. tr_dec_or_hex_string_to_int() is available to convert hex or decimal strings into integers up to 64 bits long.

uint8_t tr_cli_get_option(int argc,
char *argv[],
char *opt_string,
char **ret_arg);

To use this API, pass in argc and *argv[], a pointer to a string containing the option you are looking for, and a pointer to a pointer for the API to return the argument for the specified option. Examples of this API with and without option arguments can be seen in the Door Lock SZED sample app project, src/lock_cli.c.

Here is an example CLI function from that file:

// user add
zb_int_t cli_lock_user_add_command(zb_int_t argc,
zb_char_t *argv[])
{
zb_uint8_t user = 255;
zb_int_t ret_val = ZB_TRUE;
zb_char_t *option_argument;
// get the user
if (tr_cli_get_option(argc, argv, "u:", &option_argument))
{
user = tr_dec_or_hex_string_to_int(option_argument);
}
else
{
ret_val = ZB_FALSE;
}
// get the code
if (tr_cli_get_option(argc, argv, "c:", &option_argument))
{
pin_code[0] = strlen(option_argument);
memcpy(&pin_code[1], option_argument, pin_code[0] + 1);
}
else
{
ret_val = ZB_FALSE;
}
// get the status
if (tr_cli_get_option(argc, argv, "s:", &option_argument))
{
status = tr_dec_or_hex_string_to_int(option_argument);
}
// get the type
if (tr_cli_get_option(argc, argv, "t:", &option_argument))
{
type = tr_dec_or_hex_string_to_int(option_argument);
}
// help option
if (tr_cli_get_option(argc, argv, "h", &option_argument))
{
ret_val = ZB_FALSE;
}
if (ret_val)
{
tr_core_printf("add user: ");
{
tr_core_printf("success\n");
}
else
{
tr_core_printf("failed\n");
}
}
else
{
tr_core_printf("usage: lock user add -u user id -c \"code\" [-s status <default 0>] [-t type <default 0>]\n");
}
return 0;
}
#define TR_DOOR_LOCK_SERVER_MAX_PIN_LEN
Definition tr_plugin_config.h:96
@ TR_ZCL_DOOR_LOCK_USER_STATUS_OCCUPIED_ENABLED
Definition tr_zcl_type.h:704
@ TR_ZCL_DOOR_LOCK_USER_TYPE_UNRESTRICTED
Definition tr_zcl_type.h:711
@ TR_ZCL_DOOR_LOCK_SET_PIN_OR_ID_STATUS_SUCCESS
Definition tr_zcl_type.h:665
tr_door_lock_set_pin_or_id_status_t tr_door_lock_server_add_user(zb_uint16_t user, tr_door_lock_user_status_t status, tr_door_lock_user_type_t type, zb_char_t *pin_code)
API used to add a user to the table.
#define tr_core_printf(...)
Definition tr_debug_print.h:69
zb_uint8_t pin_code[]
Definition tr_door_lock_server.h:30
tr_door_lock_user_status_t status
Definition tr_door_lock_server.h:19
tr_door_lock_user_type_t type
Definition tr_door_lock_server.h:20

Option arguments can be strings or values. Strings may be enclosed in double quotes "<string>" but that is not a requirement since all arguments are strings by default. Values can be either decimal or hex. Hex values are prefixed with 0x and are case insensitive. The tr_cli_get_option() API will return 1 if the option request is satisfied. That is just a fancy way of saying that if the option didn't require an agrument, it was present. If it required an argument, then an argument was given. This makes it easy write CLI commands with mandatory and optional options and mandatory and optional arguments. Upon return from tr_cli_get_option(), option_argument will be pointing to the string that was entered by the user. That string can be converted into a value with the API tr_dec_or_hex_string_to_int(option_argument);

From the example above, the call

tr_cli_get_option(argc, argv, "u:", &option_argument)

expects a -u followed by a numeric value. The value entered is returned with

user = tr_dec_or_hex_string_to_int(option_argument);

Similarly, the call

tr_cli_get_option(argc, argv, "c:", &option_argument)

expects a -c followed by a string value. Upon return from tr_cli_get_option(), option_argument will be pointing to the string entered by the user and it can be processed in place using standard string functions.

Note
All provided CLI commands use the -h option to print the usage string. This option does not take an argument

Remote CLI


The Remote CLI Server plugin allows command strings to be received over the air via Zigbee packets. The command strings are passed to the CLI for parsing just like UART command strings are. The output from the CLI command execution is then packaged up and sent back out over Zigbee. The Remote CLI Client plugin is used to send remote CLI commands to a node on the Zigbee network. This feature provides powerful field debug capability, especially if the product vendor created custom commands to extend the CLI for thier specific use cases.