Meshtastic-Android/app/src/main/proto/mesh.proto
2020-02-02 19:20:17 -08:00

249 lines
11 KiB
Protocol Buffer

syntax = "proto3";
// per https://developers.google.com/protocol-buffers/docs/proto3
// We are not placing any of these defs inside a package, because if you do the resulting nanopb version is super verbose
// package mesh;
option java_package = "com.geeksville.mesh";
option java_outer_classname = "MeshProtos";
/**
MESH RADIO PROTOCOL
Old TODO notes on the mesh radio protocol, merge into real docs below...
for each named group we have a pre-shared key known by all group members and wrapped around the device.
you can only be in one group at a time (FIXME?!)
To join the group we read a qr code with the preshared key and ParamsCodeEnum. that gets sent via
bluetooth to the device. ParamsCodeEnum maps to a set of various radio params (regulatory region,
center freq, SF, bandwidth, bitrate, power etc...) so all members of the mesh can have their radios set the same way.
once in that group, we can talk between 254 node numbers.
to get our node number (and announce our presence in the channel) we pick a random node number and
broadcast as that node with WANT-NODENUM(my globally unique name). If anyone on the channel has
seen someone _else_ using that name within the last 24 hrs(?) they reply with DENY-NODENUM.
Note: we might receive multiple denies. Note: this allows others to speak up for some other node
that might be saving battery right now.
Any time we hear from another node (for any message type), we add that node number to the unpickable
list. To dramatically decrease the odds a node number we request is already used by someone.
If no one denies within TBD seconds, we assume that we have that node number. As long as we keep
talking to folks at least once every 24 hrs, others should remember we have it.
Once we have a node number we can broadcast POSITION-UPDATE(my globally unique name, lat, lon, alt,
amt battery remaining). All receivers will use this to a) update the mapping of who is at what
node nums, b) the time of last rx, c) position. If we haven't heard from that node in a while we
reply to that node (only) with our current POSITION_UPDATE state - so that node (presumably just
rejoined the network) can build a map of all participants.
We will periodically broadcast POSITION-UPDATE as needed based on distance moved or a periodic minimum heartbeat.
If user wants to send a text they can SEND_TEXT(dest user, short text message). Dest user is a
node number, or 0xff for broadcast.
*/
/*
Protobuf build instructions:
protoc -I=. --java_out /tmp mesh.proto
To generate Nanopb c code
/home/kevinh/packages/nanopb-0.4.0-linux-x86/generator-bin/protoc --nanopb_out=/tmp -I=app/src/main/proto mesh.proto
Nanopb binaries available here: https://jpa.kapsi.fi/nanopb/download/ use nanopb 0.4.0
*/
// a gps position
message Position {
double latitude = 1;
double longitude = 2;
int32 altitude = 3;
int32 battery_level = 4; // 0-100
/// true if this position came from the GPS inside the esp32 board, false if it was from a helper app on the phone
bool from_hardware = 5;
}
// Times are typically not sent over the mesh, but they will be added to any Packet (chain of SubPacket)
// sent to the phone (so the phone can know exact time of reception)
message Time {
uint64 msecs = 1; // msecs since 1970
}
// a data message to forward to an external app (or possibly also be consumed internally in the case of CLEAR_TEXT and CLEAR_READACK
message Data {
enum Type {
/// A message sent from a device outside of the mesh, in a form the mesh does not understand
SIGNAL_OPAQUE = 0; // NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
/// a simple UTF-8 text message, which even the little micros in the mesh can understand and show on their screen
/// eventually in some circumstances even signal might send messages in this form (see below)
CLEAR_TEXT = 1;
/// a message receive acknowledgement, sent in cleartext - allows radio to show user that a message has been read by the recipient, optional
CLEAR_READACK = 2;
/// Not yet used but eventually:
/// SIGNAL_CLEAR_DATA = 3; // Unencrypted at the signal level, relying on the radio crypt only (to keep size small), but contains Signal control data radios don't care about (ie non text)
}
Type typ = 1; // required
bytes payload = 2; // required
}
// Sent from the phone over bluetooth to set the user id for the owner of this node.
// Also sent from nodes to each other when a new node signs on (so all clients can have this info)
message User {
string id = 1; // a globally unique ID string for this user. In the case of Signal that would mean +16504442323
string long_name = 2; // A full name for this user, i.e. "Kevin Hester"
string short_name = 3; // A VERY short name, ideally two characters. Suitable for a tiny OLED screen
string macaddr = 4; // This is the addr of the radio. Not populated by the phone, but added by the esp32 when broadcasting
}
// Broadcast when a newly powered mesh node wants to find a node num it can use (see document for more
// details)
// FIXME in the initial proof of concept we just skip the entire want/deny flow and just hand pick node numbers at first.
message WantNodeNum {
uint32 desired_nodenum = 1; // The node number we want (note: these WantNodeNum packets are sent from a few special 'unassigned' nodenumbers)
string macaddr = 2; // the unique ID of my node, so that others can descriminate between anyone else who is also accidentially using the same unassigned node number
}
// Sent to a node which has requested a nodenum when it is told it can't have it
// FIXME, should denials be sent as a broadcast also?
// FIXME, how do we handle someone missing the denial and assuming it has the nodenum?
message DenyNodeNum {
string macaddr = 1; // the macaddr of the node we are sending this denial to (so that the recipient can be sure the packet really as desined to them)
}
// The payload portion fo a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library)
message SubPacket {
oneof variant {
Position position = 1;
Time time = 2;
Data data = 3;
User user = 4;
WantNodeNum want_node = 5;
DenyNodeNum deny_node = 6;
}
}
// Note: For simplicity reasons (and that we want to keep over the radio packets very small, we now assume that there is only _one_
// SubPacket in each MeshPacket). That might change in the far future, but for now that's the case.
// A packet sent over our mesh.
// NOTE: this raw payload does not include the from and to addresses, which are stripped off
// and passed into the mesh library code separately.
//message MeshPayload {
// repeated SubPacket subPackets = 3;
//}
// A full packet sent/received over the mesh
message MeshPacket {
int32 from = 1;
int32 to = 2;
// See note above:
// MeshPayload payloads = 4;
SubPacket payload = 3;
}
// Full settings (center freq, spread factor, pre-shared secret key etc...) needed to configure a radio
message RadioConfig {
// FIXME
// If true, radio should not try to be smart about what packets to queue to the phone
bool keep_all_packets = 100;
// If true, we will try to capture all the packets sent on the mesh, not just the ones destined to our node.
bool promiscuous_mode = 101;
}
/**
The bluetooth to device link:
Old BTLE protocol docs from TODO, merge in above and make real docs...
use protocol buffers, and NanoPB
messages from device to phone:
POSITION_UPDATE (..., time)
TEXT_RECEIVED(from, text, time)
OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications)
messages from phone to device:
SET_MYID(id, human readable long, human readable short) (send down the unique ID string used for this node, a human readable string shown for that id, and a very short human readable string suitable for oled screen)
SEND_OPAQUE(dest, payload) (for signal messages or other applications)
SEND_TEXT(dest, text)
Get all nodes() (returns list of nodes, with full info, last time seen, loc, battery level etc)
SET_CONFIG (switches device to a new set of radio params and preshared key, drops all existing nodes, force our node to rejoin this new group)
*/
// Full information about a node on the mesh
message NodeInfo {
int32 num = 1; // the node number
User user = 2;
Position position = 4;
Time last_seen = 5;
}
// 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 {
RadioConfig radio = 1;
repeated NodeInfo node_db = 2;
/// Received packets saved for delivery to the phone
repeated MeshPacket receive_queue = 3;
/// Tells the phone what our node number is, can be -1 if we've not yet joined a mesh.
sint32 my_node_num = 4;
}
// packets from the radio to the phone will appear on the fromRadio characteristic. It will support
// READ and NOTIFY. When a new packet arrives the device will notify? possibly identify instead?
// it will sit in that descriptor until consumed by the phone, at which point the next item in the FIFO
// will be populated. FIXME
message FromRadio {
// The packet num, used to allow the phone to request missing read packets from the FIFO, see our bluetooth docs
uint32 num = 1;
oneof variant {
MeshPacket packet = 2;
/// Tells the phone what our node number is, can be -1 if we've not yet joined a mesh.
sint32 my_node_num = 3;
/// One packet is sent for each node in the on radio DB
NodeInfo node_info = 4;
}
}
// packets/commands to the radio will be written (reliably) to the toRadio characteristic. Once the
// write completes the phone can assume it is handled.
message ToRadio {
// If sent to the radio, the radio will send the phone its full node DB (NodeInfo records)
// Used to populate network info the first time the phone connects to the radio
message WantNodes {
// Empty
}
oneof variant {
MeshPacket packet = 1; // send this packet on the mesh
//
// Rare operations
//
/// phone wants radio to send full node db to the phone, This is typically the first packet sent
/// to the radio when the phone gets a bluetooth connection.
/// The radio will respond by sending back a FromRadio.my_node_num and a series of FromRadio.node_info
WantNodes want_nodes = 100;
RadioConfig set_radio = 101; // set the radio provisioning for this node
User set_owner = 102; // Set the owner for this node
}
}