OpenOCD
Command Development Primer

This page provides a primer for writing commands by introducing hello module.

The full source code used in this example can be found in hello.c, and the Trying These Example Commands section shows how to use it.

A summary of this information can be found in OpenOCD Command API .

Command Handlers

Defining new commands and their helpers is easy. The following code defines a simple command handler that delegates its argument parsing:

COMMAND_HANDLER(handle_hello_command)
{
const char *sep, *name;
int retval = CALL_COMMAND_HANDLER(handle_hello_args);
if (ERROR_OK == retval)
command_print(CMD, "Greetings%s%s!", sep, name);
return retval;
}
const char * name
Definition: armv4_5.c:76
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CALL_COMMAND_HANDLER(name, extra ...)
Use this to macro to call a command helper (or a nested handler).
Definition: command.h:118
#define COMMAND_HANDLER(name)
Always use this macro to define new command handler functions.
Definition: command.h:127
#define ERROR_OK
Definition: log.h:164

Here, the COMMAND_HANDLER macro establishes the function signature, see in command.h by the __COMMAND_HANDLER macro.

The COMMAND_HELPER macro function allows defining functions with an extended version of the base signature. These helper functions can be called (with the appropriate parameters), the CALL_COMMAND_HANDLER macro to pass any e as parameters to the following helper function:

The subsequent blocks of code are a normal C function that can do anything, so only complex commands deserve should use command helper functions. In this respect, this example uses one to demonstrate how – not when – they should be used.

static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name)
{
if (argc > 1)
{
LOG_ERROR("%s: too many arguments", CMD_NAME);
}
if (1 == CMD_ARGC)
{
*sep = ", ";
*name = CMD_ARGV[0];
}
else
*sep = *name = "";
return ERROR_OK;
}
#define CMD_NAME
Use this macro to access the name of the command being handled, rather than accessing the variable di...
Definition: command.h:166
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_HELPER(name, extra ...)
Similar to COMMAND_HANDLER, except some parameters are expected.
Definition: command.h:135
#define LOG_ERROR(expr ...)
Definition: log.h:132

Of course, you may also call other macros or functions, but that extends beyond the scope of this tutorial on writing commands.

Command Registration

Before this new function can be used, it must be registered somehow. For a new module, registering should be done in a new function for the purpose, which must be called from openocd.c:

{
.name = "hello",
.mode = COMMAND_ANY,
.handler = handle_hello_command,
.help = "print a warm greeting",
.usage = "[name]",
},
{
}
};
int hello_register_commands(struct command_context_s *cmd_ctx)
{
return register_commands(cmd_ctx, NULL, handle_command_handlers);
}
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
static int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds)
Register one or more commands in the specified context, as children of parent (or top-level commends,...
Definition: command.h:274
@ COMMAND_ANY
Definition: command.h:42
static const struct command_registration foo_command_handlers[]
Definition: hello.c:40
const struct command_registration hello_command_handlers[]
Export the registration for the hello command group, so it can be embedded in example drivers.
Definition: hello.c:86
const char * name
Definition: command.h:235
#define NULL
Definition: usb.h:16

Note that the "usage" text should use the same EBNF that's found in the User's Guide: literals in 'single quotes', sequences of optional parameters in [square brackets], and alternatives in (parentheses|with|vertical bars), and so forth. No angle brackets.

That's it! The command should now be registered and available to scripts.

Command Chaining

This example also shows how to chain command handler registration, so your modules can "inherit" commands provided by other (sub)modules. Here, the hello module includes the foo commands in the same context that the 'hello' command will be registered.

If the chain field had been put in the 'hello' command, then the foo module commands would be registered under it. Indeed, that technique is used to define the 'foo bar' and 'foo baz' commands, as well as for the example drivers that use these modules.

The code for the 'foo' command handlers can be found in hello.c.

Trying These Example Commands

These commands have been inherited by the dummy interface, faux flash, and testee target drivers. The easiest way to test these is by using the dummy interface.

Once OpenOCD has been built with this example code, the following command demonstrates the abilities that the hello module provides:

openocd -c 'interface dummy' \
-c 'dummy hello' \
-c 'dummy hello World' \
-c 'dummy hello {John Doe}' \
-c 'dummy hello John Doe' # error: too many arguments

If saved in hello.cfg, then running openocd -f hello.cfg should produce the following output before displaying the help text and exiting:

Greetings!
Greetings, World!
Greetings, John Doe!
Error: hello: too many arguments
Runtime error, file "openocd.cfg", line 14:
hello: too many arguments
dummy hello [<name>]
prints a warm welcome
uint8_t dummy[96]
Definition: vdebug.c:23