Update the help system to avoid orphan commands

const struct ui_help_options global_commands[] = {
    { 1, "", T_HELP_SECTION_IO }, // work with pins, input, output measurement
    { 0, "w/W", T_HELP_1_21 },    // note that pin functions need power on the buffer
    { 0, "a/A/@ x", T_HELP_COMMAND_AUX },
    { 0, "f x/F x", T_HELP_1_11 },
    { 0, "f/F", T_HELP_1_23 },
    { 0, "g x/G", T_HELP_1_12 },
    { 0, "p/P", T_HELP_1_18 },
    { 0, "v x/V x", T_HELP_1_22 },
    { 0, "v/V", T_HELP_1_10 },

Currently the help menu is hand crafted for a nice look, but results in orphan commands that were added to the firmware without a help entry.

// command configuration
const struct _global_command_struct commands[] = {
    // clang-format off
{ .command="ls",    .allow_hiz=true, .func=&disk_ls_handler, .help_text=0x00 }, // ls T_CMDLN_LS
{ .command="cd",    .allow_hiz=true, .func=&disk_cd_handler, .help_text=0x00 }, // cd T_CMDLN_CD
{ .command="mkdir", .allow_hiz=true, .func=&disk_mkdir_handler, .help_text=0x00 }, // mkdir T_CMDLN_MKDIR
{ .command="rm",    .allow_hiz=true, .func=&disk_rm_handler, .help_text=0x00 }, // rm T_CMDLN_RM

I propose adding a few additional fields to the commands struct to enforce complete listings in the help output and automate the organization under topic headings.

  • Help text T_HELP_ would be moved from global_commands to commands struct
  • Command examples (w/W, a/A/@ x) would move to the command struct. The reason for this is that some commands have a customized/combined display that covers multiple commands in a single line, such as Aux or poWer.
  • A new field that references a topic header ID in a new array. The help would iterate over the topics ID array, looping though the command struct and printing the help for any assigned commands.

This still isn’t perfect, but it does consolidate all the help into the place where you have to tie in the command anyways.

Revisiting this for a few minutes because the orphaned commands just keep increasing.

Syntax help processing

send and receive data in modes using bus syntax
[/{     Start/Start II (mode dependent)
]/}     Stop/Stop II (mode dependent)
123     Write value (decimal)
0x123   Write value (hex)
0b110   Write value (binary)
"abc"   Write string
r       Read
/       Clock high
\       Clock low
^       Clock tick
-       Data high
_       Data low
.       Read data pin state
:       Repeat e.g. r:10
.       Bits to read/write e.g. 0x55.2
d/D     Delay 1 us/MS (d:4 to repeat)
a/A/@.x Set IO.x state (low/HI/READ)
v.x     Measure volts on IO.x
>       Run bus syntax

Bus syntax is handled by the syntax compiler, so these are not technically command line commands. Some are a bit different than normal commands:

  • [/{ Start/Start II (mode dependent)
  • 123 Write value (decimal)
  • “abc” Write string
  • a/A/@.x Set IO.x state (low/HI/READ)

There’s more than one command per line, or the line represents an idea (number/string entry).

**I propose the syntax help is handled by a sererate function from the main help. It will still display identically in the help menu, but it no longer be tied to the structural format of command line command help.

Command help processing

work with pins, input, output measurement
w/W     Power supply (off/ON)
a/A/@ x Set IO x state (low/HI/READ)
f x/F x Measure freq on IOx (once/CONT)
f/F     Monitor freq (off/ON)
g x/G   Generate frequency (off/ON)
p/P     Pull-up resistors (off/ON)
v x/V x Show volts on IOx (once/CONT)
v/V     Show volts all IOs (once/CONT)

This command section has multiple commands on the same line, similar to syntax. Under my proposed approach these would be one entry per command. Instead of:

v x/V x Show volts on IOx (once/CONT)
v/V     Show volts all IOs (once/CONT)

It would become:

v [x] Show volts once on all pins [or IOx only]
V [x] Continuous volt measurement on all pins [or IOx only]

because each command will have a single entry.

Not quite there

struct ui_help_topics {
    uint8_t topic_id;
    const char* description;
};

A struct to hold the list of help topic and heading translation.

enum {
    HELP_TOPIC_IO = 0,
    HELP_TOPIC_CONFIGURE,
    HELP_TOPIC_SYSTEM,
    HELP_TOPIC_FILES,
    HELP_TOPIC_SCRIPT,
    HELP_TOPIC_TOOLS,
    HELP_TOPIC_MODE,
    HELP_TOPIC_SYNTAX,
};

A list of keys to assign commands to a help topic.

const struct ui_help_topics help_topics[] = {
    { HELP_TOPIC_IO, T_HELP_SECTION_IO},
    { HELP_TOPIC_CONFIGURE, T_HELP_SECTION_CONFIGURE},
    { HELP_TOPIC_SYSTEM, T_HELP_SECTION_SYSTEM},
    { HELP_TOPIC_FILES, T_HELP_SECTION_FILES},
    { HELP_TOPIC_SCRIPT, T_HELP_SECTION_SCRIPT},
    { HELP_TOPIC_TOOLS, T_HELP_SECTION_TOOLS},
    { HELP_TOPIC_MODE, T_HELP_SECTION_MODE},
    { HELP_TOPIC_SYNTAX, T_HELP_SECTION_SYNTAX},
};

The list of help topic ids and the translation text.

struct _global_command_struct {
    char command[MAX_COMMAND_LENGTH]; //command line string to execute command
    bool allow_hiz; //allow execution in high impedance mode
    void (*func)(struct command_result* res); //function to execute
    uint32_t help_text; // translation string to show when -h is used, 0x00 = command can manage it's own extended help
   uint32_t help_topic_id; //NEW: which topic to include this command 
   uint32_t help_translation; //NEW: ID of translation entry to display
   char help_topic_command_custom[MAX_COMMAND_LENGTH]; //NEW: if not 0x00, then a custom string to show in the command field of the help, else jsut use the command[]
};

First thought new command struct.

    uint32_t help_text; // translation string to show when -h is used, 0x00 = command can manage it's own extended help
   uint32_t help_topic_id; //NEW: which topic to include this command 
   uint32_t help_translation; //NEW: ID of translation entry to display
   char help_topic_command_custom[MAX_COMMAND_LENGTH]; //NEW: if not 0x00, then a custom string to show in the command field of the help, else jsut use the command[]

I’m leaning towards creating a new extern struct that resides in the command’s code files that is assigned to the command, instead of putting it all in the command struct. That way command behavior can be changed inside the command code by the command author without venturing into commands.c.

More to come…