Command line and syntax rework (Syntax_rework branch firmware)

In Bus Pirate v3 single character configuration commands can be mixed with bus syntax commands in any arbitrary way. This was about all we could do on a tiny PIC chip. It just looped over user input and performed the action.

The current Bus Pirate 5 firmware is more advance, but the mix and match of configuration and syntax is limiting what we can do in the future. The goal of this rework is to have a clean separation of commands that configure the Bus Pirate and bus syntax that is used to communicate with a device.

Updated command line

  • Configuration commands - commands that change settings or enable hardware on the Bus Pirate. Examples are w/W (power supply), p/P (pull-ups), m (changing modes), etc. These are entered one per line and have optional arguments.
  • Bus syntax - Simple scripting language for communicating with a device over a bus. Examples are r (read), 0x/0b/0 (write value), a/A/@ (control individual pins), d/D (delays), [/] (start/stop) etc. These are compiled into bytecode, then ‘run’ full speed to best represent real world conditions. To execute syntax, start the line with [ or { or >

Configuration commands

	[CMD_LS]="ls", //list files
	[CMD_CD]="cd", //change dir
	[CMD_MKDIR]="mkdir", //make dir
	[CMD_RM]="rm", //delete file or empty directory
    [CMD_CAT]="cat", //print file contents
    [CMD_MODE]="m", //change mode
    [CMD_PSU_EN]="W", //psu on
    [CMD_RESET]="#", //reset
    [CMD_BOOTLOAD]="$", //enter bootloader
    [CMD_INT_FORMAT]="=", //convert int. formats in bin/hex/dec
    [CMD_INT_INVERSE]="|", //inverse the bit in a byte
    [CMD_HELP]="?", //help menu
    [CMD_CONFIG_MENU]="c", //configuration menu
    [CMD_FREQ_ONE]="f", //measure frequency once
    [CMD_FREQ_CONT]="F", //measure frequency, press space to exit
    [CMD_PWM_CONFIG]="G", //generate a frequency
    [CMD_PWM_DIS]="g", //disable frequency generation
    [CMD_HELP_MODE]="h", //mode specific help
    [CMD_INFO]="i", //bus pirate info
    [CMD_BITORDER_MSB]="l", //msb bit order
    [CMD_BITORDER_LSB]="L", //lbs bit order
    [CMD_DISPLAY_FORMAT]="o", //output display format
    [CMD_PULLUPS_EN]="P", //pull-up on
    [CMD_PULLUPS_DIS]="p", //pull-ups  off
    [CMD_PSU_DIS]="w", //psu off
    [CMD_ADC_CONT]="V", //measure voltage, press space to exit
    [CMD_ADC_ONE]="v", //measure voltage once
    [CMD_SELFTEST]="~", //run self test
    [CMD_AUX_IN]="@", //set pin input and read
    [CMD_AUX_LOW]="a", //set pin low
    [CMD_AUX_HIGH]="A"  //set pin high
  • Some commands accept arguments. A 7 sets IO7 high. f 1 measures frequency on pin one.
  • Commands will show a menu of options if no arguments are provided.
  • Multiple commands can be tied together with the linux operators ; (execute next) || (execute next if previous failed) && (execute next if previous did not fail).

Bus Syntax

                case 'r': cmd=SYN_READ; break; //read
                case '[': cmd=SYN_START; break; //start
                case ']': cmd=SYN_STOP; break; //stop
                case 'd': cmd=SYN_DELAY_US; break; //delay us
                case 'D': cmd=SYN_DELAY_MS; break; //delay ms
                case 'a': cmd=SYN_AUX_LOW; break; //aux low
                case 'A': cmd=SYN_AUX_HIGH; break; //aux HIGH
                case '@': cmd=SYN_AUX_INPUT; break; //aux INPUT
                case 'v': cmd=SYN_ADC; break; //voltage report once
                case 'f': cmd=SYN_FREQ; break; //measure frequency once
  • Writes are decimal/hex/binary numbers (0, 0x or 0b number entry)

These are the bus syntax commands the compiler will accept. Not all commands are implemented, and I have only been testing in SPI mode.

  • Begin the syntax with [, {, or > to tell the Bus Pirate you intend to send data over a bus


If you actually want to use your Bus Pirate, use the latest stable build from here.

If you want to see what I’m working on for the future, I’d love to have some feedback on the experimental firmware. Current status:

  • With an SD card inserted, try the new disk commands: ls, mkdir, cd, rm, cat.
  • Configuration commands have a help option. ls -h to show help.
  • Configuration commands have all been ported to the new system. Things that configure the Bus Pirate are entered one per line. A few will take arguments, but I’m not that far yet. Most will still show a series of menu prompts. Things that used . notation in the previous firmware (‘f.7’ measure frequency on pin 7), are now entered with a space (f 7).
  • Use ; || or && to execute multiple commands on a single line.
  • Bus Syntax must start with [ or { or > (start/CS)
  • Bus Syntax compiles and runs up to 100 commands
  • Bus Syntax can sort of post-process the result to the terminal (incomplete)

It is very much a prototype in progress. I’ll update this post as I get everything implemented.

Download syntax_rework auto builds

  • Much progress.
  • Now connected to the auto build server, grab the latest and greatest from the link above.

Developer tip

"terminal_usb_enable": 0,
"terminal_uart_enable": 1,
"terminal_uart_number": 1,

Debugging intensive work with a USB connection is a nightmare. The terminal IO can instead be put on two IO pins and then connected through the PICO probe auxiliary UART. Be sure to give it a power supply through the vout/vref pin with 3.3volts from the PICO.

  • Open bpconfig.bp on the SD card.
  • Disable the USB. both cannot work together due to some bug I’ve never been able to track down
  • Enable the UART
  • UART0 is on IO4/5. UART1 is on IO0/1. Choose one that doesn’t interfere with the stuff you’re debugging. Debug pins are protected and the Bus Pirate will refuse to reconfigure them.
  • Restart the Bus Pirate

It’s coming together. Use can see the DTTX and DTRX in the status bar - that’s the terminal UART output so I don’t have to worry about USB connections while running the debugger.

D:2 gives a 2ms delay. It’s pretty accurate.

Next up: read, then start/stop. Lots of mode updates to do.


Reads (single) work. CS now works, but this is kind of a hack. I have to tear apart all the modes and add a proper post-process for it.

I’m going to go ahead and write a integer display state machine. All that old code is pretty useless now.


AUX pin functions are working, except I still don’t have the logic for pin conflicts quite right.


Added ;/||/&& to enter multiple commands on a single line. There is an auto build posted. Will update the docs above.

ADC is implemented…

Measurement speed is fixed in latest auto build.


General cleanup. Added ASCII text mode. I’m going to move on to making the output beautiful and getting all the modes to play nice with the new syntax system. I pushed so there should be an auto build.

This rework is approaching usability. I suspect it can be merged into the main branch on Monday for a first “official” release.

1 Like

Im excited to try it out! I got wrapped up the past few days, but I’m going to load the latest after my meeting and take it for a spin. Thank you for all of your hard work and contributions to the community.

I may take a look at the 1-wire integration after I’ve had a chance to see how your structure is setup. A bit ambitious since I have a lot on my plate, but just a thought if I’m able to sneak it in.

I’m also interested in looking at Pulseview and see what it would take to support BPv5. I’m really digging your methodology and the simplistic yet informative approach.

I hope all is well with you and yours! I’ll be around this weekend if you need any testing done. Feel free to message me if I can help. Have a great day and happy hacking!

Thanks man!

Things got a little slow yesterday with some hard faults caused by the new command line parser struct. It worked, but there were some silly compiler warnings. After I chased them out everything fell apart. However today is a new day!

Got it working. I also added commands dump and load for working with EEPROMs. Currently it is a total hack that only supports one eeprom (25LC020A).

The goal is to port the page size list settings info from an established script (perhaps written for the old bus pirate?). I didn’t find one off hand, if anyone knows of one I’d be grateful for the info. Most SPI eeproms follow the 0x02 0x03 write/read instruction convention, but the page size for writing can be drastically different, and also the address method/length. Or maybe all those options are just command arguments?

write sample.txt 16

I’m going to push because I think the worst bugs are gone. There will be an autocompile shortly.

Make them all command line arguments? Then provide a list of EEPROMs and the various params available on the website, so they can be looked up by device. That way the supported device list and the app are not tied together, allowing the list to grow without needing to constantly release new versions of the tooling.

You’re right. As much as I want to make it “put the chip markings in”, it probably needs flags for buffer size, chip size, page alignment and so forth.

I had intended to make arguments order based. Should it be flag based (-d (device name)). It’s a bit of extra work but now is the time to do it.

1 Like

IMHO always flag based, order should never matter. Ideally support both short and long flag names. The flags also make it easier for people to see where they went wrong if they don’t get what they expected.

1 Like


Usage of ./shepherdsvc:
-c, --config string filename for configuration settings (default “./config.toml”)
-d, --debug logger level is debug
–dump-config dump all config values and exit
-v, --version show version information and exit

1 Like

I’ve pushed, there is a new firmware to test. It’s pretty complete now.

Rewrote the output formatting stuff. It now groups nicely in 8 bytes per line (4 in binary output mode). Reads, including multiple reads work. SPI is the only mode I’ve been through. In theory it should work with all modes, but they don’t support output for the post processing yet.

Tim and I had a private message about what to do next. Here’s my thoughts:

opt args system is working ok now, but:

  • Need to consider how to add flags and pass that to lower functions. Currently everything expects order. Maybe a loop and switch in the function? Maybe have the upper opt-args layer loop over all possible flags and put them in the right places?
  • My goal is to get all the prompts and menu logic out of the functions and into a giant struct used by opt args system to do prompting. Currently we have prompt functions that use menu configuration structs, then we have the opt args command struct (commands.c) which defines: The command, up to five parsers to get the trailing opt args, the help text.

Ideally there will be a struct something like:

command_function: what function to run
parsers[0]->parser: (text, int, float, etc)
parsers[0]->menu config: (the text and options functions to show if opt-args are missing or wrong, also min/max valid range, etc) this is currently done in the lower functions
parsers[0]->prompt function: (this could be joined in menu config) that displays the menu and handles validity check (similar to a parser, actually they are the same, just prompt mixes menu logic with parse logic) this is currently done in the lower functions. See PSU or PWM or FREQ.c
parsers[1…4]: up to four more parser sets
help_text: the string for -h

The goal is to move all the prompts and menu config in with the commands and out of the functions that actually do the work. A clean separation, and consistent use of the same parse/prompt/menu functions.

  • The I2C mode uses a PIO script from the PICO sdk. It does not return data high after every other bus transaction. I think this is a simple fix, but I won’t have time to look for a few days.

  • An easter egg game or two. In v3 there was a text adventure. in 5 I guess we could do something with the LCD and button - kind of a simple space shooter where the shooter moves left and right at increasing speeds. The button press shoots at the UFO or asteroid or whatever.

  • A thing I tried to do but dropped for time: When a github account is used for login, create an empty git branch for the account and assign permissions. If the user posts to their branch, the build server will automatically compile, create a forum thread, and start posting all updates there. That way if someone comes in and starts to make lots of contributions, people can ‘follow’ their work and get all the latest. I would have killed for something like that back in the day :slight_smile:

1 Like

I2C is robust and working well. I need to slip in a few more timeouts, then I’ll push code.

There were some pretty drastic changes, so only I2C will be implemented in the firmware until I have a chance to refactor the other protocols.

1 Like