Adding a new command and source files
This looks like a lot, but this is a really detailed step-by-step. The basics are:
- Add your command and function to the commands struct in file commands.c
- Include your source header in commands.c
- Add your source files to bp5_common in CMakeLists.txt
- Compile!
Add command to commands struct in commands.c
// command configuration
const struct _command_struct commands[]=
{
{"ls",true,&list_dir,T_CMDLN_LS}, //ls
{"cd", true, &change_dir,T_CMDLN_CD},//cd
{"mkdir", true, &make_dir, T_CMDLN_MKDIR},//mkdir
{"rm", true, &storage_unlink, T_CMDLN_RM}, //rm
{"cat", true, &cat, T_CMDLN_CAT}, //cat
First, let’s register our new command so the Bus Pirate knows what it is and what function to run.
- Open
[commands.c](https://github.com/DangerousPrototypes/BusPirate5-firmware/blob/main/commands.c#L30)
- Find
const struct _command_struct commands[]=
{"logic", true, &la_test_args, T_CMDLN_LOGIC }, // "logic"
{"hex", true, &hex, T_CMDLN_HEX }, // "hex"
{"pause", true, &helpers_pause_args, T_HELP_CMD_PAUSE }, // "pause"
{"flash", true, &flash, 0x00 }, // "dump"
};
- Find the bottom of the commands struct, please always add new commands in the last position in the struct for easier merge requests.
{"dummy", true, &dummy_func, 0x00 }
We’re going to add a new command dummy
that demonstrates how to use the command line parser and other useful things.
"dummy"
is the user command typed in the terminal to access this “program”. 8 characters max because we don’t support long file names.true
indicates the command can be used in HiZ mode. Usefalse
for anything that might manipulate IO or power, it should only be used in a protocol mode&dummy_func
is a reference to the function to execute when thedummy
command is typed in the terminal0x00
- the final position configures the help shown when the user entersdummy -h
with the -(h)elp flag.
– 0x00 - do nothing, help is handled indummy_func
–T_MODE_NO_HELP_AVAILABLE
- displays the "no help available message in the currently configured language
– You can add a custom help string to en-us.h, then run json2h.py, which will rebuild the translation files, adding defaults where translations are missing values. This is beyond the scope of this little demo
{"logic", true, &la_test_args, T_CMDLN_LOGIC }, // "logic"
{"hex", true, &hex, T_CMDLN_HEX }, // "hex"
{"pause", true, &helpers_pause_args, T_HELP_CMD_PAUSE }, // "pause"
{"flash", true, &flash, 0x00 }, // "dump"
{"dummy", true, &dummy_func, 0x00 } // "dummy"
};
Here’s how it looks with our dummy
command added to the end of the commands struct
include your source.h in commands.c
#include "helpers.h"
#include "storage.h"
#include "flash.h"
#include "mcu/rp2040.h"
#include "mode/logicanalyzer.h"
Find the include list at the top of commands.c. Add your source header to the bottom of the list.
#include "helpers.h"
#include "storage.h"
#include "flash.h"
#include "mcu/rp2040.h"
#include "mode/logicanalyzer.h"
#include "dummy.h"
Here’s what it looks like if our source is dummy.c and dummy.h. Only the .h file needs to be included.
Add source files to CMakeLists.txt
set(bp5_common
pirate.c pirate.h commands.h commands.c
mode/sump.c mode/sump.h
ui/ui_lcd.c ui/ui_lcd.h rgb.c rgb.h bio.h bio.c
msc_disk.c usb_descriptors.c
Open CMakeLists.txt and add your files to the project:
- Find the bottom of
set(bp5_common
- Add the name of any .c and .h source files you need
mode/logicanalyzer.h mode/logicanalyzer.c
mode/hw2wire.h mode/hw2wire.c mode/hw2wire_pio.h mode/hw2wire_pio.c
dummy.c dummy.h
)
Here we’ve added dummy.c and dummy.h to the project at the end of the bp5_common files.
Using the command line arguments parser
HiZ> dummy -h
usage:
dummy [init|test]
[-b(utton)] [-i(nteger) ] [-f ]
Initialize: dummy init
Test: dummy test
Test, require button press: dummy test -b
Integer, value required: dummy -i 123
Create/write/read file: dummy -f dummy.txt
Kitchen sink: dummy test -b -i 123 -f dummy.txtDummy commands valid in position 1
init Dummy init command
test Dummy test commandDummy flags
-b -b require Bus Pirate button to be pushed. Takes no parameters
-i -i {integer}. Requires integer number parameter
-f -f {file}. Create/write/read {file}. Requires file string parameter
The dummy command is a fast way to get started writing a Bus Pirate command. It walks through command line parsing, file storage, and the button. More to come in the future. Start your project right in this template if you have problems installing your own command.
Type dummy -h
to print the help menu in the latest firmware. Be sure to try in in different modes with the power supply & pull-up resistors on and off.
Command chaining
The Bus Pirate supports command chaining:
- ; - execute commands in order typed, seperated by ;
- && - execute the next command if the previous finished with success
- || - execute the next command if the previous failed
As a developer you do not need to be aware of multiple commands entered on a single command line. The parsing libraries won’t overrun the current command bounds (this is the big huge major update the new command line parser brings).
Now outdated, but still slightly informative
This part is already outdated. I suggest you head straight to the dummy.c template for the latest and greatest.
it is moderately easy to add commands/programs to the bus pirate firmware, and work with command line arguments and parameters and flags. I looked at several ways to do this, I think this is far from the best solution. But, I can get it done without a major code overhaul and it should be easy for a range of skill levels.
Command line structure
HiZ> command text1 text2 -v -f test.tmp
Command line options/arguments/flags can be accessed by position or flag name
Accessing command line by position
bool cmdln_args_string_by_position(uint32_t pos, uint32_t max_len, char *str)
bool cmdln_args_uint32_by_position(uint32_t pos, uint32_t *value)
Values can be extracted by position. This is for commands like mkdir {dir} or cp test.tmp test2.tmp. a uint32t version of the function parses the argument and returns a uint32_t.
command
is position 0- text1 is position 1
- text 2 is position 2
- -v if position 3, but it is MUCH easier to use the flag search function to retrieve flags.
More after I write the dummy.c example
Find by flag and optional value
cmdln_args_find_flag(char flag);
Find a flag without requiring a string or integer parameter.
bool cmdln_args_find_flag_uint32(char flag, command_var_t *arg, uint32_t *value);
bool cmdln_args_find_flag_string(char flag, command_var_t *arg, uint32_t max_len, char *str);
Search for a flag and return string or integer values (required).