BPIO2 binary mode

Dumb question time - Would this protocol buffer benefit the MicroPython implementation in any way?

1 Like

There has been big movement on the binmodes, but the documentation has not caught up. I will get that out this week.

So, the new Bus Pirates actually support multiple binary interface modes. The v3.x was really tricky and managed to support multiple protocols from a single interface, but over time that got messy.

In the latest firmware, use the binmode command to select the exposed interface. Currently there are binmodes for logic analyzing, a debug mode, and some other odds and ends.

A couple weeks ago @dreg added a v3.x compatibility layer binmode that can handle, I believe, SPI at the moment with I2C possible in the future. It works with flashrom and avrdude. Maybe it will be useful to your existing scripts?

1 Like

Hi! I’m interested in interfacing with binary modes, but I don’t have clear references for sample code or documentation.
My use case is an automated application where I use BP to proxy an I2C communication. My preliminary approach would be this:

  1. connect to first serial console, send the I2C mode command and other configuration (pull ups/power), then issue the binmode command
  2. connect to the second serial console and send the commands for querying I2C registers and/or setting them

I’d wish to be able to implement this as much as possible via machine interface as parsing the first serial console data could be painful (escape codes, etc…), therefore shifting features towards 2. rather than 1. is preferred.

Pointers welcome. Thanks!

2 Likes

In general, binmode is set in the user terminal with the binmode command, then all configuration is done on the second serial port. Binmode command usually totally resets the Bus Pirate (except in the case of the logic analyzers).

@Dreg made a compatibility layer for the old Bus Pirate BBIO1 mode. It has spi but also I think it may have I2C. I’m not sure, we can ask dreg. The docs for the old BBIO1 binmode are here.

The legacy binary SPI mode is still pretty beta and “hacky” :joy:. I’ve just done the bare minimum to make flashrom and avrdude work—it has some hacks, and well… it’s a bit of a mess. I’ll improve it gradually.

My next goal is to get Binmode-legacy-PIO-I2C-mode working—let’s see if I can pull it off! :wink:

Honestly, @raul-klg, I think new devs and scripters should focus on the binary modern mode that @ian is developing and, most importantly, give us feedback on what you need so we can improve it.

I don’t recommend using the legacy binmode yet.

Thanks all!.
So I will lean towards BBIO2. Is there any place where I can get info about the proto details or a code sample?
Also, what is the :q! for exit binmode?

For legacy-bin-mode: re-connect usb. (I am making an exit way)

Thanks again. I cannot pull usb connector, therefore I looked into the firmware code where I saw a BM_RESET_BUSPIRATE identified command. Depending on the firmware version this value is 27(0x1b) or 28(0x1c).For the sake of completeness, I scripted it like this:

echo -en "\x00\x00\x00\x00" > /dev/serial/by-id/usb-Bus_Pirate_Bus_Pirate_5_XXXXXXXXXXXX-if02
echo -en "\x1b" > /dev/serial/by-id/usb-Bus_Pirate_Bus_Pirate_5_XXXXXXXXXXXX-if02

Interesting comment except in the case of the logic analysers.

I’m wondering if a first implementation of BBIO2 would be to support the Bus Syntax which is already common to many modes and then move on to the configuration aspect.

For my use case, I’m happy to do the configuration by hand but I really need a machine to provide the data. Pragmatically, a data-only BBIO2 would do that for me.

1 Like

Ok - proof of concept works. There’s a bug in dirtyproto.c which forwards each octet argument to the command UART (fall-through of BINMODE_DO_COMMAND case)

Nevertheless, I’m seeing plausible I2C coming from Bus Pirate 5 on my logic analyser using binmode 2

using this snippet of Python

class I2cSlaveBusPirate5(I2cSlave):
    """ Currently using a hacky solution of the test framework

        Refer to https://github.com/DangerousPrototypes/BusPirate5-firmware/blob/c2487101ba9411579b6291f0fc42412376d0f8c9/src/binmode/dirtyproto.c
    """
    BM_CONFIG = 30
    BM_WRITE = 31
    BM_START = 32
    BM_STOP = 34
    BM_READ = 36

    def __init__(self, port: str, slave: int):
        self._port = port
        self._slave = slave

    def __enter__(self):
        # Open the binary mode port
        self._binmode = serial.Serial(self._port)
        return self

    def __exit__(self, *_):
        self._binmode.close()
        del self._binmode

    def _start(self):
        self._binmode.write(bytes((self.BM_START,)))
        # Discard result
        self._last_result = self._binmode.read(1)

    def _stop(self):
        self._binmode.write(bytes((self.BM_STOP,)))
        # Discard result
        self._last_result = self._binmode.read(1)

    def _read(self, nack : bool = False) -> int:
        # NACK doesn't appear to be currently supported
        self._binmode.write(bytes((self.BM_READ,)))
        return self._binmode.read(1)[0]

    def _write(self, octet: int) -> bool:
        self._binmode.write(bytes((self.BM_WRITE, octet)))
        # Discard result
        self._last_result = self._binmode.read(1)
        # NACK doesn't appear to be currently supported
        return True


if __name__ == '__main__':
    with I2cSlaveBusPirate5('COM26', 0x55) as i2c:
        print(i2c.writereg(b'h', b'ello'))
        print(i2c.readreg(b'', 5))

1 Like

Thank you for sharing the code. I will test it. Dirtyproto is more a collection of functions that would attach to a protocol layer, I’m not sure how reliable it is on it’s own.

If you will be around for a bit (few days or a week), I’m happy to dig in and start prototyping a real universal binary mode. I’ve been messing with protocol buffers. I still think it is overkill, but it seems the best way to provide instant tooling to the most people.

You also could consider flatbuffers: GitHub - google/flatbuffers: FlatBuffers: Memory Efficient Serialization Library

1 Like

Oh wow, yeah, that’s much more our speed. I will start on this tomorrow.

1 Like

If using that library, at the minimum, add a few fields at the head for versioning / structure type definition, as it has no built-in support.

Also … you will still need to frame this when it’s sent … else you cannot know where the start of the structure is. COBS was recommended earlier for protobuf, and seems appropriate here also.

Otherwise, it seems like a low-overhead option. Nice find!

NOTE: The docs say, in one spot, about the structure definition:

… a message wrapper with a union of tables holding buffer for a specific message type …

This seems like a good design … essentially first byte(s) indicate version and message type, followed by a union for the various message types.

See document example / test case for unions.

2 Likes

Good recall. I’ll start with getting the flat buffer going, then we can look into consistent framing.

Read through the docs. I’ll start with a simple hack that uses flat buffer to do a bulk i2c operation.

Start
Send one or more bytes
Read one or more bytes
Stop

And then a full transaction:
Start
Send x bytes
Read x bytes
If sent restart
Send x bytes
Read x bytes
Stop

(Edit: Sorry I didn’t intend this to be long!)

To throw another use case into the pot, I’m quite interested in writing a Rust HAL for the Bus Pirate, largely so that Rust programs could “speak through” the BP to connected devices. This is very useful for driver development, or to use device drivers in programs that run on the host computer.

Typically Rust HALs target a family of microcontrollers and run directly on the device (eg, rp-hal or embassy-rp for the RP2xx0), but there are others that target USB interfaces, such as the FTDI embedded HAL for the FT232H and friends, or my own mcp2221-hal for the MCP2221.

How these HALs are implemented doesn’t really matter: device HALs manipulate registers, the FTDI HAL wraps the (proprietary?) FTDI drivers, and the MCP2221 HAL uses USB HID.

What’s important is being able to meet the interfaces (“traits”) of embedded-hal. These allow drivers to run across microcontrollers without modification, as the drivers target (only) these interfaces.

To be specific, for a Bus Pirate HAL I’d like to be able to implement at least the following (the links for each document their interface contracts but there are probably no surprises):

This would let someone, for instance, wire up an I2C device to the BP and immediately use it with an existing driver. Or, conversely, write a driver that could then be used by microcontroller firmware without modification.

There are also other interfaces that could be implemented (eg, PWM), and a HAL isn’t restricted to only these interfaces.

I’ve got plenty of spare time at the moment and I’m happy to help in whatever way I can.

1 Like

The reply dots were ticking for a while :slight_smile:

That sounds like a very good foundation to mimic. The old BBIO1 was just an ad hoc build out with little attention to design. I’ve very much not wanted to make the same mess again. If someone has thought this through, let’s start there!

2 Likes

Read the trait definitions for i2c, spibus, and the input pins. Very nice, especially like how explicit the i2c events contract is … makes it easy to reason about what occurs, and what’s needed to implement.

I’d love to see this when it’s ready! It’d be awesome to be able to fuzz hardware from multiple languages (including Rust). Extra bonus points if this re-uses / abuses main buspirate firmware. :wink:

Let’s say that the BBIO2 binary mode ends up using flatbuffers. Flatbuffers provides a Rust interface, and I’m quite sure there’s a COBS packetization crate. Thus, if I’m understanding correctly, the Rust hal could be entirely on the host (PC) side. Is that accurate?

1 Like

Yeah, that’s what I had in mind. The needed functionality gets exposed by the Bus Pirate, a program on the host uses the HAL (as a library) to perform whatever meaningful operation, and the HAL takes care of the details of packaging up the command and reading the response.

2 Likes