syntax = "proto3";

package meshtastic;

/* trunk-ignore(buf-lint/COMPILE) */
import "meshtastic/channel.proto";
import "meshtastic/config.proto";
import "meshtastic/localonly.proto";
import "meshtastic/mesh.proto";
import "meshtastic/telemetry.proto";
import "nanopb.proto";

option csharp_namespace = "Meshtastic.Protobufs";
option go_package = "github.com/meshtastic/go/generated";
option java_outer_classname = "DeviceOnly";
option java_package = "org.meshtastic.proto";
option swift_prefix = "";
option (nanopb_fileopt).include = "<vector>";

/*
 * Position with static location information only for NodeDBLite
 */
message PositionLite {
  /*
   * The new preferred location encoding, multiply by 1e-7 to get degrees
   * in floating point
   */
  sfixed32 latitude_i = 1;

  /*
   * TODO: REPLACE
   */
  sfixed32 longitude_i = 2;

  /*
   * In meters above MSL (but see issue #359)
   */
  int32 altitude = 3;

  /*
   * This is usually not sent over the mesh (to save space), but it is sent
   * from the phone so that the local device can set its RTC If it is sent over
   * the mesh (because there are devices on the mesh without GPS), it will only
   * be sent by devices which has a hardware GPS clock.
   * seconds since 1970
   */
  fixed32 time = 4;

  /*
   * TODO: REPLACE
   */
  Position.LocSource location_source = 5;

  /*
   * Indicates the bits of precision set by the sending node
   */
  uint32 precision_bits = 6;
}

message UserLite {
  /*
   * This is the addr of the radio.
   */
  bytes macaddr = 1 [deprecated = true];

  /*
   * A full name for this user, i.e. "Kevin Hester"
   */
  string long_name = 2;

  /*
   * A VERY short name, ideally two characters.
   * Suitable for a tiny OLED screen
   */
  string short_name = 3;

  /*
   * TBEAM, HELTEC, etc...
   * Starting in 1.2.11 moved to hw_model enum in the NodeInfo object.
   * Apps will still need the string here for older builds
   * (so OTA update can find the right image), but if the enum is available it will be used instead.
   */
  HardwareModel hw_model = 4;

  /*
   * In some regions Ham radio operators have different bandwidth limitations than others.
   * If this user is a licensed operator, set this flag.
   * Also, "long_name" should be their licence number.
   */
  bool is_licensed = 5;

  /*
   * Indicates that the user's role in the mesh
   */
  Config.DeviceConfig.Role role = 6;

  /*
   * The public key of the user's device.
   * This is sent out to other nodes on the mesh to allow them to compute a shared secret key.
   */
  bytes public_key = 7;

  /*
   * Whether or not the node can be messaged
   */
  optional bool is_unmessagable = 9;
}

message NodeInfoLite {
  /*
   * The node number
   */
  uint32 num = 1;

  // Tag 2 was UserLite user; flattened into tags 14..18 (presence via
  //   NODEINFO_BITFIELD_HAS_USER).
  // Tag 3 was PositionLite position; moved to NodeDatabase.positions.
  reserved 2, 3;
  reserved "user", "position";

  /*
   * In-memory SNR of the last received message in dB. Not serialised directly:
   * always zeroed before encode; persisted as snr_q4 = 19 below.
   */
  float snr = 4;

  /*
   * Set to indicate the last time we received a packet from this node
   */
  fixed32 last_heard = 5;

  // Tag 6 was DeviceMetrics device_metrics; moved to NodeDatabase.telemetry.
  reserved 6;
  reserved "device_metrics";

  /*
   * local channel index we heard that node on. Only populated if its not the default channel.
   */
  uint32 channel = 7;

  // Tags 8/10/11 were via_mqtt/is_favorite/is_ignored bools; packed into bitfield.
  reserved 8, 10, 11;
  reserved "via_mqtt", "is_favorite", "is_ignored";

  /*
   * Number of hops away from us this node is (0 if direct neighbor)
   */
  optional uint32 hops_away = 9;

  /*
   * Last byte of the node number of the node that should be used as the next hop to reach this node.
   */
  uint32 next_hop = 12;

  /*
   * Bitfield for storing booleans. See NODEINFO_BITFIELD_* in src/mesh/NodeDB.h.
   */
  uint32 bitfield = 13;

  // Flattened user fields (formerly UserLite). macaddr dropped (deprecated 1.2.11).

  /*
   * A full name for this user, i.e. "Kevin Hester".
   */
  string long_name = 14;

  /*
   * A VERY short name, ideally two characters or an emoji.
   * Suitable for a tiny OLED screen.
   */
  string short_name = 15;

  /*
   * Hardware model the user's device is running.
   */
  HardwareModel hw_model = 16;

  /*
   * The user's role in the mesh.
   */
  Config.DeviceConfig.Role role = 17;

  /*
   * The public key of the user's device, for PKI-based encrypted DMs.
   */
  bytes public_key = 18;

  /*
   * Q4-encoded SNR: dB × 4, sint32 zigzag. Matches RouteDiscovery convention.
   * Encode: snr_q4 = (int32_t)(snr * 4.0f). Decode: snr = snr_q4 / 4.0f.
   * float snr is always zeroed on disk; this field carries all persisted SNR.
   */
  sint32 snr_q4 = 19;
}

/*
 * This message is never sent over the wire, but it is used for serializing DB
 * state to flash in the device code
 * FIXME, since we write this each time we enter deep sleep (and have infinite
 * flash) it would be better to use some sort of append only data structure for
 * the receive queue and use the preferences store for the other stuff
 */
message DeviceState {
  /*
   * Read only settings/info about this node
   */
  MyNodeInfo my_node = 2;

  /*
   * My owner info
   */
  User owner = 3;

  /*
   * Received packets saved for delivery to the phone
   */
  repeated MeshPacket receive_queue = 5;

  /*
   * A version integer used to invalidate old save files when we make
   * incompatible changes This integer is set at build time and is private to
   * NodeDB.cpp in the device code.
   */
  uint32 version = 8;

  /*
   * We keep the last received text message (only) stored in the device flash,
   * so we can show it on the screen.
   * Might be null
   */
  MeshPacket rx_text_message = 7;

  /*
   * Used only during development.
   * Indicates developer is testing and changes should never be saved to flash.
   * Deprecated in 2.3.1
   */
  bool no_save = 9 [deprecated = true];

  /*
   * Previously used to manage GPS factory resets.
   * Deprecated in 2.5.23
   */
  bool did_gps_reset = 11 [deprecated = true];

  /*
   * We keep the last received waypoint stored in the device flash,
   * so we can show it on the screen.
   * Might be null
   */
  MeshPacket rx_waypoint = 12;

  /*
   * The mesh's nodes with their available gpio pins for RemoteHardware module
   */
  repeated NodeRemoteHardwarePin node_remote_hardware_pins = 13;
}

// Satellite per-node entries; stored alongside the slim NodeInfoLite so nodes
// that never report don't pay the embedded cost.

message NodePositionEntry {
  uint32 num = 1;
  PositionLite position = 2;
}

message NodeTelemetryEntry {
  uint32 num = 1;
  DeviceMetrics device_metrics = 2;
}

message NodeEnvironmentEntry {
  uint32 num = 1;
  EnvironmentMetrics environment_metrics = 2;
}

message NodeStatusEntry {
  uint32 num = 1;
  StatusMessage status = 2;
}

message NodeDatabase {
  /*
   * A version integer used to invalidate old save files when we make
   * incompatible changes This integer is set at build time and is private to
   * NodeDB.cpp in the device code.
   */
  uint32 version = 1;

  /*
   * New lite version of NodeDB to decrease memory footprint
   */
  repeated NodeInfoLite nodes = 2 [(nanopb).callback_datatype = "std::vector<meshtastic_NodeInfoLite>"];

  // Per-NodeNum satellite arrays. Constrained platforms (e.g. STM32WL) omit
  // these via MESHTASTIC_EXCLUDE_*DB build flags.
  repeated NodePositionEntry positions = 3 [(nanopb).callback_datatype = "std::vector<meshtastic_NodePositionEntry>"];
  repeated NodeTelemetryEntry telemetry = 4 [(nanopb).callback_datatype = "std::vector<meshtastic_NodeTelemetryEntry>"];
  repeated NodeStatusEntry status = 5 [(nanopb).callback_datatype = "std::vector<meshtastic_NodeStatusEntry>"];
  repeated NodeEnvironmentEntry environment = 6 [(nanopb).callback_datatype = "std::vector<meshtastic_NodeEnvironmentEntry>"];
}

/*
 * The on-disk saved channels
 */
message ChannelFile {
  /*
   * The channels our node knows about
   */
  repeated Channel channels = 1;

  /*
   * A version integer used to invalidate old save files when we make
   * incompatible changes This integer is set at build time and is private to
   * NodeDB.cpp in the device code.
   */
  uint32 version = 2;
}

/*
 * The on-disk backup of the node's preferences
 */
message BackupPreferences {
  /*
   * The version of the backup
   */
  uint32 version = 1;

  /*
   * The timestamp of the backup (if node has time)
   */
  fixed32 timestamp = 2;

  /*
   * The node's configuration
   */
  LocalConfig config = 3;

  /*
   * The node's module configuration
   */
  LocalModuleConfig module_config = 4;

  /*
   * The node's channels
   */
  ChannelFile channels = 5;

  /*
   * The node's user (owner) information
   */
  User owner = 6;
}
