frb_sifter.protoΒΆ

/**

This is the gRPC protocol definition for the CHORD FRB Grouper-to-Sifter.

Its canonical source is
https://github.com/dstndstn/chord-frb-sifter/blob/main/chord_frb_grpc/frb_sifter.proto

*/

syntax = "proto3";

service FrbSifter {

  // First call - report my configuration.
  // Returns true if good, false otherwise.
  rpc CheckConfiguration (ConfigMessage) returns (ConfigReply) {}

  // Report events from a given time chunk.
  rpc FrbEvents (FrbEventsMessage) returns (FrbEventsReply) {}
}

// Wire-protocol version. This is the single source of truth for the protocol
// version on both the client (grouper) and server (sifter) sides -- both
// reference PROTOCOL_VERSION_CURRENT from the generated stubs, rather than each
// hardcoding their own constant.
//
// proto3 requires every enum to have a zero value; PROTOCOL_VERSION_UNSPECIFIED
// is that placeholder (a ConfigMessage.protocol_version of 0 is therefore
// invalid -- e.g. an old client that never set the field). Bump
// PROTOCOL_VERSION_CURRENT on any incompatible wire-format change.

enum ProtocolVersion {
  PROTOCOL_VERSION_UNSPECIFIED = 0;
  PROTOCOL_VERSION_CURRENT = 3;
}

message ConfigMessage {
  // Wire-protocol version: the client sets this to PROTOCOL_VERSION_CURRENT (see
  // the ProtocolVersion enum above), and the sifter REJECTS the config if it
  // does not match its own PROTOCOL_VERSION_CURRENT. Kept as a uint32 rather
  // than the enum type so an out-of-range value from a newer client round-trips
  // as a plain integer the sifter can report, instead of decoding to the proto3
  // "unknown enum" sentinel.
  
  uint32 protocol_version = 1;

  // Currently, we initialize all 5 of these fields in the main search, but when
  // we send simulated events with 'pirate_frb run_fake_xengine -f -s ...', fields
  // other than 'xengine_yaml' are empty strings (-> yaml null).
  
  string pirate_yaml = 2;
  string xengine_yaml = 3;
  string dedispersion_plan_yaml = 4;
  string grouper_yaml = 5;
  string search_ip_addr = 6;  // for rpc callbacks sifter -> pirate
}

message ConfigReply {
  bool ok = 1;
}

// If there are early triggers, then the event timestamp can be outside
// the EventsMessage range [chunk_fpga_start:chunk_fpga_end]! In this scenario,
// the sifter may receive multiple events (in different chunks) for the same
// FRB, as the pulse crosses different early-trigger frequencies.

message FrbEvent {
  int32 beam_id = 1;
  int64 fpga_timestamp = 2;  // can be outside the chunk, see above!
  float dm = 3;
  float snr = 4;
  float rfi_prob = 5;

  // Currently, these members are set to placeholder values in the main search, but when
  // we send simulated events with 'pirate_frb run_fake_xengine -f -s ...', we do set
  // meaningful values.
  
  float width_ms = 6;
  float subband_freq_lo_MHz = 7;
  float subband_freq_hi_MHz = 8;
}

// When events are sent from the search pipeline, we set from_simulator=false.
// When the fake X-engine simulates pulses "upstream", it sends a parallel sequence
// of events with from_simulator=true. Thus, the sifter can use this flag to
// compare the actual outcome of the search (from_simulator=false) to the
// ideal outcome (from simulator=true).

message FrbEventsMessage {
  bool from_simulator = 1;
  int32 beam_set_id = 2;
  int64 chunk_fpga_start = 3;
  int64 chunk_fpga_end = 4;
  repeated FrbEvent events = 5;

  // Coarse-grained triggers
  // A small array of SNRs, the same length as the beams being handled by this beam_set_id.
  repeated float coarsegrain_snr = 6;
}

message FrbEventsReply {
  bool ok = 1;
  string message = 2;
}