ProtoBuf for controlling BP5

Continuing the discussion from Programmatic control of BP5:


7 thoughts for anyone thinking of taking this on

Current thoughts for anyone that might take this up:

  1. First, I recommend waiting until the major parsing update for commands / options is done. It’s expected that will result in a well-defined structure with explicit listing of all the options for commands, etc. … which is 95% of the work. Converting one of those commands to a protobuf message, testing, and incrementally add additional messages then becomes much easier.

  2. Consider use of nanopb … which uses the ZLIB license and seems to be actively developed. There’s also a list of third-party options for various languages, in case a better option appears.

  3. All fields in the .proto should have explicit presence. Generally, this means every field should be explicitly optional or repeated.

  4. Check out the great examples

  5. CAUTION: nanopb’s options include fixed-length options, but there are caveates! See Nanopb: Basic concepts for additional details.
    CRITICALLY, do NOT use fixed_count on any non-LEAF messages (messages that do not contain other messages). See second Note in the decoder implementation details:

Note: The decoder only keeps track of one fixed_count repeated field at a time. Usually this it not an issue because all elements of a repeated field occur end-to-end. Interleaved array elements of several fixed_count repeated fields would be a valid protobuf message, but would get rejected by nanopb decoder with error "wrong size for fixed count field" .

  1. Read about versioning best practices before working on this. Non-exhaustive examples:

  2. Start small … get the infrastructure in place with some test requests / responses.


Entirely untested off-the-cuff concept

// BusPirate.proto file
syntax = "proto3"
import "nanopb.proto" // custom nanopb options directly inline

package com.buspirate.protobuf;

message BP5_test_request {
    optional bool ignored = 1 [default = 0];
}
message BP5_test_response1 {
    optional uint64 ticks = 1 [default = 0]; // monotonically increasing
}
message BP5_test_response2 {
    optional uint32 major = 1 [deafult = 0]; // "version core"
    optional uint32 minor = 2 [default = 0]; // "version core"
    optional uint32 patch = 3 [default = 0]; // "version core"
    repeated string prerelease = 4; // after version core, optional hyphen followed by a series of dot-separated identifiers [0-9A-Za-z-], this would hold that array of identifiers
    repeated string metadata = 5; // version core and optional prerelease, optional plus sign followed by a series of dot-separated identifiers [0-9A-Za-z-], this would hold that array of identifiers
};

message BP5_request {
    // Only one request at a time
    oneof request {
        // don't use 1-15 for test cases!
        bool ignored = 19000;
        BP5_test_request test1 = 19001;
        BP5_test_request test2 = 19002;
    }
}