This file provides a brief summary of how to add a new command to the
bladeRF-cli program.

= Creating a file for the command =

To add a new command, create C file in this directory and add it to the list of
source files in the bladeRF-cli CMakeLists.txt. The entry point of the command
should have a prototype similar to the one shown below for an "mycmd" command:

    int cmd_mycmd(struct cli_state *state, int argc, char **argv);

The first parameter is a pointer to some CLI state information. The remaining
two parameters are similar to what one would expect for a main() function.

The function shall return 0 for success, or one of the CLI_RET_* values defined
in common.h. For all error values EXCEPT CLI_RET_INVAPARAM, the top-level
command handling code will print an appropriate error message; your command
should not print anything.

Use CLI_RET_NARGS for an incorrect number of arguments. Do not use the
CLI_RET_INVAPARAM code in this case.

However, If your command detects that is provided with an invalid parameter, it
should print an error message and return  CLI_RET_INVAPARAM. The rationale is
that only the command's implementation will "know" what is and is not valid,
but the other error codes are sufficiently generic.

Error messages associated with a CLI_RET_INVAPARAM shall be printed using the
cli_err() function, defined in common.h. Generally, you'll want the prefix
argument to cli_err() to be argv[0]. An acceptable alternative is the argument
name that was incorrect, when applicable.

Be sure to include a "\n" at the end of the message passed to cli_err() to
remain consistent with the preferred output format. This function will insert
the desired leading indentation; there is no need to manually prepend this to
the prefix.

Another slightly special case is the handling of libbladeRF error codes. If a
libbladeRF function returns a non-zero error code, set state->last_lib_error to
the error code and return CLI_RET_LIBBLADERF.  This will the top-level command
handling code to look up and print an appropriate error message via
libbladerf_strerror(), instead of cli_strerror().

When printing informational output in your command, prepend and append newlines
to the beginning and end of your output, respectively. Output shall be indented
two spaces. Below is an example:

bladeRF> mycmd arg1 arg2

  Mycmd output line one.
  Additional information on line two.
    Sub-information 1
    Sub-information 2

bladeRF> mycmd badarg1 arg2

  mycmd: badarg1 is invalid because XYZ...

bladeRF>



= Adding the command to cmd.c =

When adding a command to cmd.c, please be sure to maintain the alphabetical
ordering of commands. This includes lists of declarations.

First, add an appropriate DECLARE_CMD(). For the "mycmd" example above, this
would be:

    DECLARE_CMD(mycmd);

Next, add the command name (and optional shortcuts/aliases) that will
invoke your command to list of cmd_names_* declarations. For example,
to invoke the mycmd command with "mycmd" and "m":

    static const char *cmd_names_mycmd[] = { "mycmd", "m", NULL };


Next, add help text for your command in cmd_help.h.in. For the mycmd example,
this might look like:

    #define CLI_CMD_HELPTEXT_mycmd \
        "Usage: mycmd <arg1> <arg2>\n"
        "\n"
        "This is an example command that does such and such.\n"
        "\n"
        "Some more detailed examples and explanations go here.\n"

Finally, added an element to the cmd_table[] array. The fields here consist of:
    * The command names that invoke your command
    * The function to execute
    * A brief one-line description of the function to show in "help" output
    * The command's detailed help text
    * A flag to denote whether the command requires an open device handle
    * A flag to denote whether the command requires the FPGA to be loaded

The requires_device and requires_fpga flags should be set to true if some or
all of the operations provided by the command require the aforementioned items.
This allows the command-agnostic logic to print an appropriate error message
before even attempting to execute the command. The rationale for having these
flags is that it reduces duplicated device handle and FPGA state checks in
numerous commands.

An example element might look like the following, if mycmd were to operate
on a device handle, but not require that the FPGA be loaded:
    {
        FIELD_INIT(.names, cmd_names_mycmd),
        FIELD_INIT(.exec, cmd_mycmd),
        FIELD_INIT(.desc, "Perform such and such operatiions"),
        FIELD_INIT(.help, CLI_CMD_HELPTEXT_mycmd),
        FIELD_INIT(.requires_device, true),
        FIELD_INIT(.requires_fpga, false),
    },
