// Modbus driver + point schemas. Companion to bacnet.proto;
// landed alongside ethernet_ip.proto + the registry.proto
// generalization in the multi-protocol parity sweep.
//
// Storage: edge.config KV under
//   driver.modbus.{device_id}     → ModbusDriverConfig
// Cloud-to-edge delivery: ace.edge.cmd.config.update (see
// commands.proto). Registry rows live under registry.{device_id}
// like BACnet — see registry.proto.

syntax = "proto3";

package aerodrome.v1;

// Wire transport. RTU shares the same RTU framing semantics
// regardless of the physical layer (TCP-tunnelled or serial
// gateway); the edge picks the transport-specific implementation
// from this field.
enum ModbusTransport {
  MODBUS_TRANSPORT_UNSPECIFIED = 0;
  MODBUS_TRANSPORT_TCP = 1;
  MODBUS_TRANSPORT_RTU = 2;
}

// Modbus register-set discriminator. Holding + Input cover word-
// width numerics; Coil + Discrete cover single-bit booleans.
// Mismatches between register_type and data_type (e.g. Bool on a
// Holding register) are rejected at validation time on both the
// cloud and edge sides.
enum ModbusRegisterType {
  MODBUS_REGISTER_TYPE_UNSPECIFIED = 0;
  MODBUS_REGISTER_TYPE_HOLDING = 1;
  MODBUS_REGISTER_TYPE_INPUT = 2;
  MODBUS_REGISTER_TYPE_COIL = 3;
  MODBUS_REGISTER_TYPE_DISCRETE = 4;
}

// Value decode hint. The edge reads `register_count` raw 16-bit
// words determined by the type (Int16/Uint16 = 1, Int32/Uint32/
// Float32 = 2, Bool = 1 coil-bit) and decodes per byte/word-order
// inherited from the driver config.
enum ModbusDataType {
  MODBUS_DATA_TYPE_UNSPECIFIED = 0;
  MODBUS_DATA_TYPE_INT16 = 1;
  MODBUS_DATA_TYPE_UINT16 = 2;
  MODBUS_DATA_TYPE_INT32 = 3;
  MODBUS_DATA_TYPE_UINT32 = 4;
  MODBUS_DATA_TYPE_FLOAT32 = 5;
  MODBUS_DATA_TYPE_BOOL = 6;
}

// Address payload for one Modbus point. Carried inside PointDef
// (see registry.proto) — common fields (datapoint_id, intervals,
// writable, timeseries_id) live there so per-protocol address
// messages stay narrow.
message ModbusPointAddress {
  ModbusRegisterType register_type = 1;
  uint32 address = 2;
  ModbusDataType data_type = 3;
}

// Per-device Modbus driver configuration. One row in edge.config
// under driver.modbus.{device_id}.
message ModbusDriverConfig {
  // ULID device handle (26-char Crockford-base32). Matches
  // RegistryConfig.device_id; see Aerodrome's ADR
  // `adr-device-id-handle-vs-identity.md` for the handle-vs-
  // identity split.
  string device_id = 1;

  // Operator-facing label.
  optional string label = 2;

  // Gateway endpoint.
  string host = 3;
  uint32 port = 4;             // 1..=65535
  ModbusTransport transport = 5;

  // Modbus slave / unit id. 1..=247 for RTU per the spec; TCP
  // accepts anything by convention but the cloud validator caps
  // at the same range for consistency.
  uint32 unit_id = 6;

  // Batching ceilings. Modbus spec: 125 holding/input registers
  // per ReadHolding / ReadInput, 2000 coils per ReadCoils. The
  // edge defaults to these maxima; lower values reduce per-
  // request latency on slow gateways.
  uint32 max_registers_per_read = 7;   // 1..=125, default 125
  uint32 max_coils_per_read = 8;       // 1..=2000, default 2000

  // Operator handle into the network attachment this device sits
  // behind (analogous to BacnetDriverConfig.network_id). Modbus
  // attachments are described as ace:NetworkAttachment +
  // modbus:GatewayEndpoint in the Aerodrome graph; on the edge
  // side this is currently informational.
  optional string network_attachment_id = 20;
}
