- 
                Notifications
    
You must be signed in to change notification settings  - Fork 241
 
Companion Radio Protocol
In the examples/companion_radio folder is a firmware project within MeshCore, for a radio to act as companion to external apps, either mobile, web or whatever.
There are two variants: USB and BLE.
Both have a simple protocol consisting of 'frames' described below, where (for simplicity) the frames are delimited by:
- For BLE - a frame is simply a single characteristic value (BLE link layer already does all the integrity checks)
 - For USB - an outbound frame from starts with byte 62 (ASCII '>'), then 2 bytes with frame length (little-endian), followed by actual frame. An inbound frame starts with byte 60 (ASCII '<'), then 2 bytes with frame length, followed by actual frame.
 
NOTE: outbound means radio -> app. inbound means app -> radio.
The companion radio essentially takes the 'server' role, and just responds to requests from the connected app (the 'client').
CMD_APP_START (1)
The app start command should be the first request the app sends to the radio. The radio should respond with a RESP_CODE_SELF_INFO(5)
CMD_GET_CONTACTS (4)
The app sends this request to sync the contacts list. Optionally can encode a 32-bit 'since' param, where radio will only return contacts which have been modified since that timestamp. The radio will send a sequence of frames: RESP_CODE_CONTACTS_START(2), RESP_CODE_CONTACT(3) .. {for each modified/new contact}, RESP_CODE_END_OF_CONTACTS(4).
CMD_GET_DEVICE_TIME (5)
App sends this to receive the clock (as epoch secs, UTC) on the device. Responds with RESP_CODE_CURR_TIME(9) + 32-bit unsigned value.
CMD_SET_DEVICE_TIME (6)
App sends this (with 32-bit unsigned param) to set the clock on the device. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_SEND_SELF_ADVERT (7)
App sends for radio to send an Advertisement packet. (optional byte param value 1, to send flood-mode, otherwise sends zero-hop). Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_SET_ADVERT_NAME (8)
App sends to update the name for this node, as used in the advertisement packets. Request includes the new name (remainder of frame). Responds with RESP_CODE_OK(0)
CMD_SET_ADVERT_LATLON (14)
App sends to update the lat/lon for this node, as used in the advertisement packets. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_SYNC_NEXT_MESSAGE (10)
App sends to get the next text message from the radio's message queue. (these can queue up even while the app is disconnected) If queue is empty, replies with RESP_CODE_NO_MORE_MESSAGES(10). Otherwise, either a RESP_CODE_CONTACT_MSG_RECV(7) or RESP_CODE_CHANNEL_MSG_RECV(8) is returned. After processing these, the app would typically send another CMD_SYNC_NEXT_MESSAGE request to pull the next from queue, etc. Also, app should send this request upon getting the push notification PUSH_CODE_MSG_WAITING(0x83).
CMD_ADD_UPDATE_CONTACT (9)
App sends this either to modify a contact or add a new one. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_REMOVE_CONTACT (15)
App sends this to remove a contact (app provides public key of contact). Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_SHARE_CONTACT (16)
App sends this to share a contact by zero-hop sending original advert packet (app provides public key of contact). Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_EXPORT_CONTACT (17)
(This is for 'business card' support) App sends this to obtain the last raw advert for given contact (pub key follows), OR if no contact specified creates a NEW advert for THIS node. Responds with either RESP_CODE_EXPORT_CONTACT(11) or RESP_CODE_ERR(1)
CMD_IMPORT_CONTACT (18)
App sends this (followed by bytes obtained by CMD_EXPORT_CONTACT) to manually import a contact (usually via a 'business card' exchange). Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1), if successful will then result in PUSH_CODE_ADVERT as if receiving an advert (typically, then trigger the contacts sync as usual to update contacts list)
CMD_SEND_TXT_MSG (2)
App sends to radio for a text message send to a given contact. (DM) Responds with RESP_CODE_SENT(6) + a 32-bit 'expected ACK' code, or RESP_CODE_ERR(1)
CMD_SEND_CHANNEL_TXT_MSG (3)
App sends to radio to send flood-mode text message to a channel. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
CMD_SET_RADIO_PARAMS (11)
App sends to radio to save new radio parameters to its storage. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1).
CMD_SET_RADIO_TX_POWER (12)
App sends to radio to set the radio TX power level. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1).
CMD_RESET_PATH (13)
App sends to radio along with the public key of the contact, to reset the out_path. Responds with either RESP_CODE_OK(0) or RESP_CODE_ERR(1)
These can be pushed to the app at any time:
- PUSH_CODE_ADVERT (0x80) - sent when a new advertisement packet was received. Includes 32-byte public key of node. (for full details, repeat the contacts sync flow described with the CMD_GET_CONTACTS request, ideally passing 'since' param)
 - PUSH_CODE_PATH_UPDATED (0x81) - sent when a contact has received a new path. Includes 32-byte public key of node. (trigger contacts sync flow, as above)
 - PUSH_CODE_SEND_CONFIRMED (0x82) - sent when a matching message ACK is received. Includes 32-bit ACK code, and 32-bit round-trip time in milliseconds.
 - PUSH_CODE_MSG_WAITING (0x83) - sent when a new text message has been received. App should trigger the flow mentioned with the CMD_SYNC_NEXT_MESSAGE request.
 
NOTE: all uint32 values are Little Endian!
CMD_APP_START {
  code: byte,     // constant: 1
  app_ver: byte,
  reserved: bytes(6),
  app_name: varchar   // remainder of frame 
}
RESP_CODE_SELF_INFO {
  code: byte,   // constant: 5
  type: byte,   // one of ADV_TYPE_*
  tx_power_dbm: byte    // current TX power, in dBm
  max_tx_power: byte,     // max TX power radio supports
  public_key: bytes(32),
  adv_lat: int32,   // advert latitude * 1E6
  adv_lon: int32,   // advert longitude * 1E6
  reserved: int32,
  radio_freq: uint32,    // freq * 1000
  radio_bw: uint32,      // bandwidth(khz) * 1000
  radio_sf: byte,        // spreading factor
  radio_cr: byte,        // coding rate
  name: varchar   // remainder of frame
}
CMD_GET_CONTACTS {
  code: byte,   // constant 4
  (optional) since: uint32,   // the last contact.lastmod value already received
}
RESP_CODE_CONTACTS_START {
  code: byte,   // constant 2
  count: uint32    // total number of contacts
}
RESP_CODE_CONTACT {
  code: byte,    // constant 3
  public_key: bytes(32),
  type: byte,   // one of ADV_TYPE_*
  flags: byte,
  out_path_len: signed-byte,
  out_path: bytes(64),
  adv_name: chars(32),    // advertised  name (null terminated)
  last_advert: uint32,
  adv_lat: int32,    // advertised latitude * 1E6
  adv_lon: int32,    // advertised longitude * 1E6
  lastmod: uint32
}
RESP_CODE_END_OF_CONTACTS {
  code: byte,     // constant 4
  most_recent_lastmod: uint32     // used this for next 'since' param to CMD_GET_CONTACTS
}
CMD_SET_DEVICE_TIME {
  code: byte,   // constant 6
  epoch_secs: uint32
}
RESP_CODE_CURR_TIME {
  code: byte,   // constant 9
  epoch_secs: uint32
}
CMD_SEND_SELF_ADVERT {
  code: byte,   // constant 7
  (optional) type: byte,   // 1 = flood, 0 = zero-hop (default)
}
CMD_SET_ADVERT_NAME {
  code: byte,   // constant 8
  name: varchar   // remainder of frame
}
CMD_SET_ADVERT_LATLON {
  code: byte,    // constant 14
  adv_lat: int32,    // latitude * 1E6
  adv_lon: int32,    // longitude * 1E6
  adv_alt: int32   // OPTIONAL (for future support)
}
CMD_ADD_UPDATE_CONTACT {
  code: byte,   // constant 9
  public_key: bytes(32),
  type: byte,   // one of ADV_TYPE_*
  flags: byte,
  out_path_len: signed-byte,
  out_path: bytes(64),
  adv_name: chars(32),    // null terminated
  last_advert: uint32
  (optional) adv_lat: int32,    // advertised latitude * 1E6
  (optional) adv_lon: int32,    // advertised longitude * 1E6
}
CMD_REMOVE_CONTACT { 
  code: byte,   // constant 15
  public_key: bytes(32)
}
CMD_SHARE_CONTACT { 
  code: byte,   // constant 16
  public_key: bytes(32)
}
CMD_EXPORT_CONTACT {
  code: byte,   // constant 17
  (optional) public_key: bytes(32)   // public key of contact (if omitted, export SELF)
}
RESP_CODE_EXPORT_CONTACT {
  code: byte,   // constant 11
  card_data: bytes   // remainder of frame. ('business card' format as: "meshcore://{hex(card_data)}" )
}
CMD_IMPORT_CONTACT {
  code: byte,   // constant 18
  card_data: bytes   // remainder of frame.
}
CMD_RESET_PATH {
  code: byte,    // constant 13
  public_key: bytes(32)
}
CMD_SEND_TXT_MSG {
  code: byte,   // constant 2
  txt_type: byte,     // one of TXT_TYPE_*  (0 = plain)
  attempt: byte,     // values: 0..3 (attempt number)
  sender_timestamp: uint32,
  pubkey_prefix: bytes(6),     // just first 6 bytes of recipient contact's public key
  text: varchar    // remainder of frame  
}
CMD_SEND_CHANNEL_TXT_MSG {
  code: byte,   // constant 3
  txt_type: byte,     // one of TXT_TYPE_*  (0 = plain)
  channel_idx: byte,     // reserved (0 for 'public')
  sender_timestamp: uint32,
  text: varchar    // remainder of frame
}
RESP_CODE_SENT {
  code: byte,   // constant 6
  type: byte,    // how it was sent: 1 = flood, 0 = direct
  expected_ack_code: bytes(4),
  suggested_timeout: uint32   // estimated round-trip timeout, in milliseconds
}
PUSH_CODE_SEND_CONFIRMED {
  code: byte,     // constant 0x82
  ack_code: bytes(4),
  round_trip: uint32   // milliseconds
}
RESP_CODE_CONTACT_MSG_RECV {
  code: byte,   // constant 7
  pubkey_prefix: bytes(6),     // just first 6 bytes of sender's public key
  path_len: byte,     // 0xFF if was sent direct, otherwise hop count for flood-mode
  txt_type: byte,     // one of TXT_TYPE_*  (0 = plain)
  sender_timestamp: uint32,
  text: varchar    // remainder of frame  
}
RESP_CODE_CHANNEL_MSG_RECV {
  code: byte,   // constant 8
  channel_idx: byte,   // reserved (0 for now, ie. 'public')
  path_len: byte,     // 0xFF if was sent direct, otherwise hop count for flood-mode
  txt_type: byte,     // one of TXT_TYPE_*  (0 = plain)
  sender_timestamp: uint32,
  text: varchar    // remainder of frame  
}
CMD_SET_RADIO_PARAMS {
  code: byte,   // constant 11
  radio_freq: uint32,    // freq * 1000
  radio_bw: uint32,      // bandwidth(khz) * 1000
  radio_sf: byte,        // spreading factor
  radio_cr: byte         // coding rate
}
CMD_SET_RADIO_TX_POWER {
  code: byte,   // constant 12
  tx_power_dbm: byte    // TX power, in dBm
}
adv_type:
- ADV_TYPE_NONE = 0
 - ADV_TYPE_CHAT = 1
 - ADV_TYPE_REPEATER = 2
 - ADV_TYPE_ROOM = 3
 
txt_type:
- TXT_TYPE_PLAIN = 0 // a plain text message
 - TXT_TYPE_CLI_DATA = 1 // a CLI command
 - TXT_TYPE_SIGNED_PLAIN = 2 // plain text, signed by sender