more complete radio support
This commit is contained in:
@@ -128,6 +128,45 @@ void MeshCoreCompanion::getStats(uint8_t statsType) {
|
||||
uint8_t p[2]; sendPayload(p, mc_cmd_get_stats(p, sizeof(p), statsType));
|
||||
}
|
||||
|
||||
/* ---- contacts ---- */
|
||||
void MeshCoreCompanion::getContacts(uint32_t sinceLastmod) {
|
||||
uint8_t p[5]; sendPayload(p, mc_cmd_get_contacts(p, sizeof(p), sinceLastmod));
|
||||
}
|
||||
void MeshCoreCompanion::addUpdateContact(const mc_contact_t &c) {
|
||||
uint8_t p[1 + 32 + 1 + 1 + 1 + 64 + 32 + 4 + 4 + 4];
|
||||
sendPayload(p, mc_cmd_add_update_contact(p, sizeof(p), &c));
|
||||
}
|
||||
void MeshCoreCompanion::removeContact(const uint8_t pubkey[32]) {
|
||||
uint8_t p[33]; sendPayload(p, mc_cmd_remove_contact(p, sizeof(p), pubkey));
|
||||
}
|
||||
void MeshCoreCompanion::resetPath(const uint8_t pubkey[32]) {
|
||||
uint8_t p[33]; sendPayload(p, mc_cmd_reset_path(p, sizeof(p), pubkey));
|
||||
}
|
||||
void MeshCoreCompanion::shareContact(const uint8_t pubkey[32]) {
|
||||
uint8_t p[33]; sendPayload(p, mc_cmd_share_contact(p, sizeof(p), pubkey));
|
||||
}
|
||||
void MeshCoreCompanion::getContactByKey(const uint8_t pubkey[32]) {
|
||||
uint8_t p[33]; sendPayload(p, mc_cmd_get_contact_by_key(p, sizeof(p), pubkey));
|
||||
}
|
||||
void MeshCoreCompanion::exportContact(const uint8_t pubkey[32]) {
|
||||
uint8_t p[33]; sendPayload(p, mc_cmd_export_contact(p, sizeof(p), pubkey));
|
||||
}
|
||||
void MeshCoreCompanion::importContact(const uint8_t *card, size_t len) {
|
||||
uint8_t p[MC_MAX_PAYLOAD]; sendPayload(p, mc_cmd_import_contact(p, sizeof(p), card, len));
|
||||
}
|
||||
|
||||
/* ---- binary / anonymous requests ---- */
|
||||
void MeshCoreCompanion::sendBinaryReq(const uint8_t dst[32], uint8_t reqType,
|
||||
const uint8_t *data, size_t len) {
|
||||
uint8_t p[MC_MAX_PAYLOAD];
|
||||
sendPayload(p, mc_cmd_send_binary_req(p, sizeof(p), dst, reqType, data, len));
|
||||
}
|
||||
void MeshCoreCompanion::sendAnonReq(const uint8_t dst[32], uint8_t reqType,
|
||||
const uint8_t *data, size_t len) {
|
||||
uint8_t p[MC_MAX_PAYLOAD];
|
||||
sendPayload(p, mc_cmd_send_anon_req(p, sizeof(p), dst, reqType, data, len));
|
||||
}
|
||||
|
||||
/* ---- dispatch ---- */
|
||||
void MeshCoreCompanion::dispatch(const mc_event_t &ev) {
|
||||
if (_onEvent) _onEvent(ev);
|
||||
@@ -151,6 +190,16 @@ void MeshCoreCompanion::dispatch(const mc_event_t &ev) {
|
||||
case MC_RESP_STATS:
|
||||
if (_onStats) _onStats(ev.u.stats);
|
||||
break;
|
||||
case MC_RESP_CONTACT:
|
||||
case MC_PUSH_NEW_ADVERT:
|
||||
if (_onContact2) _onContact2(ev.u.contact);
|
||||
break;
|
||||
case MC_RESP_END_OF_CONTACTS:
|
||||
if (_onContactsDone) _onContactsDone(ev.u.contacts_lastmod);
|
||||
break;
|
||||
case MC_PUSH_BINARY_RESP:
|
||||
if (_onBinaryResp) _onBinaryResp(ev.u.binary_resp);
|
||||
break;
|
||||
case MC_PUSH_MSG_WAITING:
|
||||
if (_autoSync && !_draining) { _draining = true; syncNextMessage(); }
|
||||
break;
|
||||
|
||||
@@ -29,6 +29,9 @@ public:
|
||||
using SelfInfoCb = std::function<void(const mc_self_info_t&)>;
|
||||
using MsgSentCb = std::function<void(const mc_msg_sent_t&)>;
|
||||
using StatsCb = std::function<void(const mc_stats_t&)>;
|
||||
using ContactCb = std::function<void(const mc_contact_t&)>;
|
||||
using ContactsDoneCb = std::function<void(uint32_t /*lastmod*/)>;
|
||||
using BinaryRespCb = std::function<void(const mc_binary_resp_t&)>;
|
||||
using EventCb = std::function<void(const mc_event_t&)>;
|
||||
|
||||
explicit MeshCoreCompanion(Stream &io) : _io(io) {}
|
||||
@@ -61,6 +64,23 @@ public:
|
||||
void drainMessages(); /* start a manual sync-drain loop */
|
||||
void getStats(uint8_t statsType);
|
||||
|
||||
/* ---- contacts ---- */
|
||||
void getContacts(uint32_t sinceLastmod = 0); /* → onContact... then onContactsDone */
|
||||
void addUpdateContact(const mc_contact_t &c);
|
||||
void removeContact(const uint8_t pubkey[32]);
|
||||
void resetPath(const uint8_t pubkey[32]);
|
||||
void shareContact(const uint8_t pubkey[32]);
|
||||
void getContactByKey(const uint8_t pubkey[32]);
|
||||
void exportContact(const uint8_t pubkey[32] = nullptr); /* nullptr = own card */
|
||||
void importContact(const uint8_t *card, size_t len);
|
||||
|
||||
/* ---- binary / anonymous requests ---- */
|
||||
void sendBinaryReq(const uint8_t dst[32], uint8_t reqType,
|
||||
const uint8_t *data = nullptr, size_t len = 0);
|
||||
void sendAnonReq(const uint8_t dst[32], uint8_t reqType,
|
||||
const uint8_t *data = nullptr, size_t len = 0);
|
||||
void requestStatus(const uint8_t dst[32]) { sendBinaryReq(dst, MC_BINARY_REQ_STATUS); }
|
||||
|
||||
/* ---- behaviour ---- */
|
||||
void setAutoSync(bool on) { _autoSync = on; }
|
||||
|
||||
@@ -77,6 +97,9 @@ public:
|
||||
void onSelfInfo(SelfInfoCb cb) { _onSelfInfo = cb; }
|
||||
void onMsgSent(MsgSentCb cb) { _onMsgSent = cb; }
|
||||
void onStats(StatsCb cb) { _onStats = cb; }
|
||||
void onContact(ContactCb cb) { _onContact2 = cb; } /* CONTACT + NEW_ADVERT */
|
||||
void onContactsDone(ContactsDoneCb cb){ _onContactsDone = cb; }
|
||||
void onBinaryResponse(BinaryRespCb cb){ _onBinaryResp = cb; }
|
||||
void onEvent(EventCb cb) { _onEvent = cb; } /* every parsed frame */
|
||||
|
||||
private:
|
||||
@@ -103,6 +126,9 @@ private:
|
||||
SelfInfoCb _onSelfInfo;
|
||||
MsgSentCb _onMsgSent;
|
||||
StatsCb _onStats;
|
||||
ContactCb _onContact2;
|
||||
ContactsDoneCb _onContactsDone;
|
||||
BinaryRespCb _onBinaryResp;
|
||||
EventCb _onEvent;
|
||||
};
|
||||
|
||||
|
||||
@@ -73,6 +73,24 @@ static int parse_contact_text(const uint8_t *b, size_t n, int v3, mc_contact_msg
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Contact record, shared by CONTACT (3) and NEW_ADVERT (0x8A). */
|
||||
static int parse_contact(const uint8_t *b, size_t n, mc_contact_t *c) {
|
||||
/* pubkey32 + type + flags + path_len + path64 + name32 + 3*u32 + u32 */
|
||||
if (n < 32 + 1 + 1 + 1 + 64 + 32 + 4 + 4 + 4) return 0;
|
||||
size_t o = 0;
|
||||
memcpy(c->public_key, b + o, 32); o += 32;
|
||||
c->type = b[o++];
|
||||
c->flags = b[o++];
|
||||
c->out_path_len = b[o++];
|
||||
memcpy(c->out_path, b + o, 64); o += 64;
|
||||
copy_cstring(c->adv_name, sizeof(c->adv_name), b + o, 32); o += 32;
|
||||
c->last_advert = get_u32(b + o); o += 4;
|
||||
c->adv_lat = (int32_t)get_u32(b + o); o += 4;
|
||||
c->adv_lon = (int32_t)get_u32(b + o); o += 4;
|
||||
c->lastmod = get_u32(b + o); o += 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
void mc_rx_init(mc_rx_t *rx) { rx->len = 0; }
|
||||
|
||||
@@ -239,6 +257,84 @@ size_t mc_cmd_get_stats(uint8_t *out, size_t cap, uint8_t stats_type) {
|
||||
out[0] = MC_CMD_GET_STATS; out[1] = stats_type; return 2;
|
||||
}
|
||||
|
||||
/* ---- contacts ---- */
|
||||
size_t mc_cmd_get_contacts(uint8_t *out, size_t cap, uint32_t since_lastmod) {
|
||||
if (since_lastmod > 0) {
|
||||
if (cap < 5) return 0;
|
||||
out[0] = MC_CMD_GET_CONTACTS; put_u32(out + 1, since_lastmod); return 5;
|
||||
}
|
||||
if (cap < 1) return 0;
|
||||
out[0] = MC_CMD_GET_CONTACTS; return 1;
|
||||
}
|
||||
|
||||
/* [code][pubkey:32] */
|
||||
static size_t cmd_key_only(uint8_t *out, size_t cap, uint8_t code, const uint8_t key[32]) {
|
||||
if (cap < 33) return 0;
|
||||
out[0] = code; memcpy(out + 1, key, 32); return 33;
|
||||
}
|
||||
size_t mc_cmd_remove_contact(uint8_t *out, size_t cap, const uint8_t pubkey[32]) {
|
||||
return cmd_key_only(out, cap, MC_CMD_REMOVE_CONTACT, pubkey);
|
||||
}
|
||||
size_t mc_cmd_reset_path(uint8_t *out, size_t cap, const uint8_t pubkey[32]) {
|
||||
return cmd_key_only(out, cap, MC_CMD_RESET_PATH, pubkey);
|
||||
}
|
||||
size_t mc_cmd_share_contact(uint8_t *out, size_t cap, const uint8_t pubkey[32]) {
|
||||
return cmd_key_only(out, cap, MC_CMD_SHARE_CONTACT, pubkey);
|
||||
}
|
||||
size_t mc_cmd_get_contact_by_key(uint8_t *out, size_t cap, const uint8_t pubkey[32]) {
|
||||
return cmd_key_only(out, cap, MC_CMD_GET_CONTACT_BY_KEY, pubkey);
|
||||
}
|
||||
size_t mc_cmd_export_contact(uint8_t *out, size_t cap, const uint8_t pubkey[32]) {
|
||||
if (pubkey == NULL) { if (cap < 1) return 0; out[0] = MC_CMD_EXPORT_CONTACT; return 1; }
|
||||
return cmd_key_only(out, cap, MC_CMD_EXPORT_CONTACT, pubkey);
|
||||
}
|
||||
size_t mc_cmd_import_contact(uint8_t *out, size_t cap, const uint8_t *card, size_t card_len) {
|
||||
size_t total = 1 + card_len;
|
||||
if (cap < total) return 0;
|
||||
out[0] = MC_CMD_IMPORT_CONTACT;
|
||||
if (card_len) memcpy(out + 1, card, card_len);
|
||||
return total;
|
||||
}
|
||||
size_t mc_cmd_add_update_contact(uint8_t *out, size_t cap, const mc_contact_t *c) {
|
||||
size_t total = 1 + 32 + 1 + 1 + 1 + 64 + 32 + 4 + 4 + 4; /* 144 */
|
||||
if (cap < total) return 0;
|
||||
size_t o = 0;
|
||||
out[o++] = MC_CMD_ADD_UPDATE_CONTACT;
|
||||
memcpy(out + o, c->public_key, 32); o += 32;
|
||||
out[o++] = c->type;
|
||||
out[o++] = c->flags;
|
||||
out[o++] = c->out_path_len;
|
||||
memcpy(out + o, c->out_path, 64); o += 64;
|
||||
memset(out + o, 0, 32);
|
||||
{ size_t nl = strlen(c->adv_name); if (nl > 32) nl = 32; memcpy(out + o, c->adv_name, nl); }
|
||||
o += 32;
|
||||
put_u32(out + o, c->last_advert); o += 4;
|
||||
put_u32(out + o, (uint32_t)c->adv_lat); o += 4;
|
||||
put_u32(out + o, (uint32_t)c->adv_lon); o += 4;
|
||||
return o;
|
||||
}
|
||||
|
||||
/* ---- binary / anonymous requests ---- */
|
||||
static size_t cmd_req(uint8_t *out, size_t cap, uint8_t code, const uint8_t dst[32],
|
||||
uint8_t req_type, const uint8_t *data, size_t data_len) {
|
||||
size_t total = 1 + 32 + 1 + data_len;
|
||||
if (cap < total) return 0;
|
||||
size_t o = 0;
|
||||
out[o++] = code;
|
||||
memcpy(out + o, dst, 32); o += 32;
|
||||
out[o++] = req_type;
|
||||
if (data_len) { memcpy(out + o, data, data_len); o += data_len; }
|
||||
return o;
|
||||
}
|
||||
size_t mc_cmd_send_binary_req(uint8_t *out, size_t cap, const uint8_t dst[32],
|
||||
uint8_t req_type, const uint8_t *data, size_t data_len) {
|
||||
return cmd_req(out, cap, MC_CMD_SEND_BINARY_REQ, dst, req_type, data, data_len);
|
||||
}
|
||||
size_t mc_cmd_send_anon_req(uint8_t *out, size_t cap, const uint8_t dst[32],
|
||||
uint8_t req_type, const uint8_t *data, size_t data_len) {
|
||||
return cmd_req(out, cap, MC_CMD_SEND_ANON_REQ, dst, req_type, data, data_len);
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
int mc_parse(const uint8_t *p, size_t len, mc_event_t *ev) {
|
||||
if (len < 1) return 0;
|
||||
@@ -412,7 +508,103 @@ int mc_parse(const uint8_t *p, size_t len, mc_event_t *ev) {
|
||||
ev->u.send_confirmed.round_trip = get_u32(b + 4);
|
||||
return 1;
|
||||
|
||||
case MC_RESP_CONTACTS_START:
|
||||
if (n < 4) return 0;
|
||||
ev->u.contacts_count = get_u32(b);
|
||||
return 1;
|
||||
|
||||
case MC_RESP_CONTACT:
|
||||
case MC_PUSH_NEW_ADVERT:
|
||||
return parse_contact(b, n, &ev->u.contact);
|
||||
|
||||
case MC_RESP_END_OF_CONTACTS:
|
||||
if (n < 4) return 0;
|
||||
ev->u.contacts_lastmod = get_u32(b);
|
||||
return 1;
|
||||
|
||||
case MC_RESP_CONTACT_URI: {
|
||||
size_t dl = n;
|
||||
if (dl > sizeof(ev->u.contact_uri.data)) dl = sizeof(ev->u.contact_uri.data);
|
||||
memcpy(ev->u.contact_uri.data, b, dl);
|
||||
ev->u.contact_uri.len = (uint8_t)dl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case MC_RESP_ADVERT_PATH: {
|
||||
if (n < 5) return 0;
|
||||
ev->u.advert_path.timestamp = get_u32(b);
|
||||
ev->u.advert_path.path_len = b[4];
|
||||
size_t pl = n - 5;
|
||||
if (pl > sizeof(ev->u.advert_path.path)) pl = sizeof(ev->u.advert_path.path);
|
||||
memcpy(ev->u.advert_path.path, b + 5, pl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case MC_RESP_AUTOADD_CONFIG:
|
||||
if (n < 1) return 0;
|
||||
ev->u.autoadd_config = b[0];
|
||||
return 1;
|
||||
|
||||
case MC_RESP_ALLOWED_REPEAT_FREQ: {
|
||||
uint8_t cnt = 0;
|
||||
size_t o = 0;
|
||||
while (o + 8 <= n && cnt < 8) {
|
||||
uint32_t lo = get_u32(b + o), hi = get_u32(b + o + 4);
|
||||
if (lo == 0 && hi == 0) break;
|
||||
ev->u.allowed_freq.pair[cnt].min = lo;
|
||||
ev->u.allowed_freq.pair[cnt].max = hi;
|
||||
cnt++; o += 8;
|
||||
}
|
||||
ev->u.allowed_freq.count = cnt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case MC_PUSH_BINARY_RESP: {
|
||||
if (n < 5) return 0; /* reserved(1) + tag(4) */
|
||||
mc_binary_resp_t *r = &ev->u.binary_resp;
|
||||
/* b[0] reserved */
|
||||
r->tag = get_u32(b + 1);
|
||||
size_t dl = n - 5;
|
||||
if (dl > sizeof(r->data)) dl = sizeof(r->data);
|
||||
memcpy(r->data, b + 5, dl);
|
||||
r->data_len = (uint8_t)dl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case MC_PUSH_CONTACT_DELETED:
|
||||
if (n < 32) return 0;
|
||||
memcpy(ev->u.deleted_key, b, 32);
|
||||
return 1;
|
||||
|
||||
case MC_PUSH_CONTACTS_FULL:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0; /* recognised code byte set in ev->code, body not parsed */
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode a STATUS binary-response payload (see mc_status_t). */
|
||||
int mc_parse_status(const uint8_t *d, size_t len, mc_status_t *s) {
|
||||
if (len < 52) return 0;
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->bat_mv = get_u16(d + 0);
|
||||
s->tx_queue_len = get_u16(d + 2);
|
||||
s->noise_floor = (int16_t)get_u16(d + 4);
|
||||
s->last_rssi = (int16_t)get_u16(d + 6);
|
||||
s->nb_recv = get_u32(d + 8);
|
||||
s->nb_sent = get_u32(d + 12);
|
||||
s->airtime_secs = get_u32(d + 16);
|
||||
s->uptime_secs = get_u32(d + 20);
|
||||
s->sent_flood = get_u32(d + 24);
|
||||
s->sent_direct = get_u32(d + 28);
|
||||
s->recv_flood = get_u32(d + 32);
|
||||
s->recv_direct = get_u32(d + 36);
|
||||
s->full_evts = get_u16(d + 40);
|
||||
s->last_snr_q4 = (int16_t)get_u16(d + 42);
|
||||
s->direct_dups = get_u16(d + 44);
|
||||
s->flood_dups = get_u16(d + 46);
|
||||
s->rx_airtime_secs = get_u32(d + 48);
|
||||
if (len >= 56) { s->recv_errors = get_u32(d + 52); s->has_recv_errors = 1; }
|
||||
return 1;
|
||||
}
|
||||
|
||||
+103
-4
@@ -59,15 +59,37 @@ enum {
|
||||
MC_CMD_SET_DEVICE_TIME = 6,
|
||||
MC_CMD_SEND_SELF_ADVERT = 7,
|
||||
MC_CMD_SET_ADVERT_NAME = 8,
|
||||
MC_CMD_ADD_UPDATE_CONTACT = 9,
|
||||
MC_CMD_SYNC_NEXT_MESSAGE = 10,
|
||||
MC_CMD_SET_RADIO_PARAMS = 11,
|
||||
MC_CMD_SET_TX_POWER = 12,
|
||||
MC_CMD_RESET_PATH = 13,
|
||||
MC_CMD_SET_ADVERT_LATLON = 14,
|
||||
MC_CMD_REMOVE_CONTACT = 15,
|
||||
MC_CMD_SHARE_CONTACT = 16,
|
||||
MC_CMD_EXPORT_CONTACT = 17,
|
||||
MC_CMD_IMPORT_CONTACT = 18,
|
||||
MC_CMD_DEVICE_QUERY = 22,
|
||||
MC_CMD_GET_CONTACT_BY_KEY = 30,
|
||||
MC_CMD_GET_CHANNEL = 31,
|
||||
MC_CMD_SET_CHANNEL = 32,
|
||||
MC_CMD_GET_STATS = 56
|
||||
MC_CMD_SEND_BINARY_REQ = 50,
|
||||
MC_CMD_GET_STATS = 56,
|
||||
MC_CMD_SEND_ANON_REQ = 57
|
||||
};
|
||||
|
||||
/* ---- Binary-request subtypes (SEND_BINARY_REQ data[0]) ---- */
|
||||
enum {
|
||||
MC_BINARY_REQ_STATUS = 0x01,
|
||||
MC_BINARY_REQ_KEEP_ALIVE = 0x02,
|
||||
MC_BINARY_REQ_TELEMETRY = 0x03,
|
||||
MC_BINARY_REQ_MMA = 0x04,
|
||||
MC_BINARY_REQ_ACL = 0x05,
|
||||
MC_BINARY_REQ_NEIGHBOURS = 0x06
|
||||
};
|
||||
/* ---- Anonymous-request subtypes (SEND_ANON_REQ) ---- */
|
||||
enum { MC_ANON_REQ_REGIONS = 0x01, MC_ANON_REQ_OWNER = 0x02, MC_ANON_REQ_BASIC = 0x03 };
|
||||
|
||||
/* ---- Response codes (radio -> app) ---- */
|
||||
enum {
|
||||
MC_RESP_OK = 0,
|
||||
@@ -81,7 +103,7 @@ enum {
|
||||
MC_RESP_CHANNEL_MSG_RECV = 8,
|
||||
MC_RESP_CURR_TIME = 9,
|
||||
MC_RESP_NO_MORE_MESSAGES = 10,
|
||||
MC_RESP_EXPORT_CONTACT = 11,
|
||||
MC_RESP_CONTACT_URI = 11, /* reply to EXPORT_CONTACT */
|
||||
MC_RESP_BATTERY_VOLTAGE = 12,
|
||||
MC_RESP_DEVICE_INFO = 13,
|
||||
MC_RESP_PRIVATE_KEY = 14,
|
||||
@@ -89,7 +111,10 @@ enum {
|
||||
MC_RESP_CONTACT_MSG_RECV_V3 = 16, /* SNR-prefixed variant of code 7 */
|
||||
MC_RESP_CHANNEL_MSG_RECV_V3 = 17, /* SNR-prefixed variant of code 8 */
|
||||
MC_RESP_CHANNEL_INFO = 18,
|
||||
MC_RESP_ADVERT_PATH = 22,
|
||||
MC_RESP_STATS = 24,
|
||||
MC_RESP_AUTOADD_CONFIG = 25,
|
||||
MC_RESP_ALLOWED_REPEAT_FREQ = 26,
|
||||
MC_RESP_CHANNEL_DATA_RECV= 27
|
||||
};
|
||||
|
||||
@@ -108,9 +133,11 @@ enum {
|
||||
MC_PUSH_STATUS_RESP = 0x87,
|
||||
MC_PUSH_LOG_RX_DATA = 0x88,
|
||||
MC_PUSH_TRACE_DATA = 0x89,
|
||||
MC_PUSH_NEW_ADVERT = 0x8A,
|
||||
MC_PUSH_NEW_ADVERT = 0x8A, /* carries a full contact record */
|
||||
MC_PUSH_TELEMETRY = 0x8B,
|
||||
MC_PUSH_BINARY_RESP = 0x8C
|
||||
MC_PUSH_BINARY_RESP = 0x8C,
|
||||
MC_PUSH_CONTACT_DELETED = 0x8F,
|
||||
MC_PUSH_CONTACTS_FULL = 0x90
|
||||
};
|
||||
|
||||
/* ---- Text message subtypes ---- */
|
||||
@@ -183,6 +210,27 @@ size_t mc_cmd_set_radio_params (uint8_t *out, size_t cap, uint32_t freq_hz_x1000
|
||||
uint32_t bw, uint8_t sf, uint8_t cr);
|
||||
size_t mc_cmd_get_stats (uint8_t *out, size_t cap, uint8_t stats_type);
|
||||
|
||||
/* ---- contacts (Phase 2) ---- */
|
||||
/* GET_CONTACTS; pass since_lastmod>0 for a delta sync, or 0 for all. */
|
||||
size_t mc_cmd_get_contacts (uint8_t *out, size_t cap, uint32_t since_lastmod);
|
||||
size_t mc_cmd_remove_contact (uint8_t *out, size_t cap, const uint8_t pubkey[32]);
|
||||
size_t mc_cmd_reset_path (uint8_t *out, size_t cap, const uint8_t pubkey[32]);
|
||||
size_t mc_cmd_share_contact (uint8_t *out, size_t cap, const uint8_t pubkey[32]);
|
||||
size_t mc_cmd_get_contact_by_key(uint8_t *out, size_t cap, const uint8_t pubkey[32]);
|
||||
/* EXPORT_CONTACT; pubkey==NULL exports this node's own card. Reply: CONTACT_URI. */
|
||||
size_t mc_cmd_export_contact (uint8_t *out, size_t cap, const uint8_t pubkey[32]);
|
||||
size_t mc_cmd_import_contact (uint8_t *out, size_t cap, const uint8_t *card, size_t card_len);
|
||||
|
||||
/* ---- binary / anonymous requests (Phase 2) ---- */
|
||||
/* SEND_BINARY_REQ: dst is a full 32-byte key; req_type is MC_BINARY_REQ_*;
|
||||
* data is the type-specific request blob (may be NULL). */
|
||||
size_t mc_cmd_send_binary_req (uint8_t *out, size_t cap, const uint8_t dst[32],
|
||||
uint8_t req_type, const uint8_t *data, size_t data_len);
|
||||
size_t mc_cmd_send_anon_req (uint8_t *out, size_t cap, const uint8_t dst[32],
|
||||
uint8_t req_type, const uint8_t *data, size_t data_len);
|
||||
/* mc_cmd_add_update_contact() and mc_parse_status() are declared below, after the
|
||||
* mc_contact_t / mc_status_t struct definitions they reference. */
|
||||
|
||||
/* ======================================================================== *
|
||||
* Parsed events
|
||||
* ======================================================================== */
|
||||
@@ -267,6 +315,43 @@ typedef struct {
|
||||
} u;
|
||||
} mc_stats_t;
|
||||
|
||||
/* A mesh contact, as parsed from CONTACT (3) / NEW_ADVERT (0x8A) and as built
|
||||
* for ADD_UPDATE_CONTACT. Lat/lon are degrees x 1e6. */
|
||||
typedef struct {
|
||||
uint8_t public_key[32];
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint8_t out_path_len;
|
||||
uint8_t out_path[64];
|
||||
char adv_name[MC_NAME_LEN + 1];
|
||||
uint32_t last_advert;
|
||||
int32_t adv_lat, adv_lon;
|
||||
uint32_t lastmod;
|
||||
} mc_contact_t;
|
||||
|
||||
/* Raw binary response (BINARY_RESPONSE push, 0x8C): a 4-byte tag matching the
|
||||
* MsgSent.expected_ack of the request, plus opaque payload. Decode per the
|
||||
* request type you sent (e.g. mc_parse_status for a STATUS request). */
|
||||
typedef struct {
|
||||
uint32_t tag;
|
||||
uint8_t data_len;
|
||||
uint8_t data[MC_MAX_DATA];
|
||||
} mc_binary_resp_t;
|
||||
|
||||
/* Decoded STATUS binary response (mc_parse_status). */
|
||||
typedef struct {
|
||||
uint16_t bat_mv, tx_queue_len;
|
||||
int16_t noise_floor, last_rssi;
|
||||
uint32_t nb_recv, nb_sent, airtime_secs, uptime_secs;
|
||||
uint32_t sent_flood, sent_direct, recv_flood, recv_direct;
|
||||
uint16_t full_evts;
|
||||
int16_t last_snr_q4; /* divide by 4 for dB */
|
||||
uint16_t direct_dups, flood_dups;
|
||||
uint32_t rx_airtime_secs;
|
||||
uint32_t recv_errors; /* fw v1.12+; see has_recv_errors */
|
||||
int has_recv_errors;
|
||||
} mc_status_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t code; /* response or push code (first payload byte) */
|
||||
union {
|
||||
@@ -278,6 +363,15 @@ typedef struct {
|
||||
mc_self_info_t self_info;
|
||||
mc_msg_sent_t msg_sent; /* MC_RESP_SENT */
|
||||
mc_stats_t stats; /* MC_RESP_STATS */
|
||||
mc_contact_t contact; /* CONTACT (3) / NEW_ADVERT */
|
||||
mc_binary_resp_t binary_resp; /* MC_PUSH_BINARY_RESP */
|
||||
uint32_t contacts_count; /* CONTACTS_START: number to come */
|
||||
uint32_t contacts_lastmod; /* END_OF_CONTACTS: newest lastmod*/
|
||||
uint8_t deleted_key[32]; /* CONTACT_DELETED */
|
||||
uint8_t autoadd_config; /* AUTOADD_CONFIG */
|
||||
struct { uint8_t len; uint8_t data[MC_MAX_DATA]; } contact_uri; /* CONTACT_URI */
|
||||
struct { uint32_t timestamp; uint8_t path_len; uint8_t path[64]; } advert_path;
|
||||
struct { uint8_t count; struct { uint32_t min, max; } pair[8]; } allowed_freq;
|
||||
uint32_t curr_time; /* epoch secs */
|
||||
uint16_t battery_mv;
|
||||
int8_t err_code; /* MC_RESP_ERR (-1 if absent) */
|
||||
@@ -290,6 +384,11 @@ typedef struct {
|
||||
* matching union member filled), 0 if the code is unknown to this build. */
|
||||
int mc_parse(const uint8_t *payload, size_t len, mc_event_t *ev);
|
||||
|
||||
/* Builders/parsers that reference the structs above. */
|
||||
size_t mc_cmd_add_update_contact(uint8_t *out, size_t cap, const mc_contact_t *c);
|
||||
/* Decode a STATUS binary-response payload (resp.data/.data_len). 1 on success. */
|
||||
int mc_parse_status (const uint8_t *data, size_t len, mc_status_t *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user