mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 20:09:17 +00:00
offline queue bump, lossless message sync via ble
This commit is contained in:
+2
-1
@@ -120,9 +120,10 @@ config ZEPHCORE_MAX_CHANNELS
|
||||
|
||||
config ZEPHCORE_OFFLINE_QUEUE_SIZE
|
||||
int "Offline message queue size"
|
||||
default 16
|
||||
default 256
|
||||
help
|
||||
Size of the offline message queue for incoming messages.
|
||||
Arduino MeshCore uses 256 for both T1000-E and Wio Tracker.
|
||||
|
||||
config ZEPHCORE_ACK_TABLE_SIZE
|
||||
int "ACK tracking table size"
|
||||
|
||||
@@ -121,6 +121,7 @@ static bool dle_requested;
|
||||
/* Advertising state */
|
||||
static bool adv_switching = false;
|
||||
static bool adv_is_slow = false;
|
||||
static bool adv_post_disconnect = false; /* skip fast advert after disconnect */
|
||||
|
||||
/* Runtime BLE passkey */
|
||||
static uint32_t ble_passkey = CONFIG_ZEPHCORE_BLE_PASSKEY;
|
||||
@@ -340,6 +341,10 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
|
||||
k_work_cancel_delayable(&tx_drain_work);
|
||||
k_work_cancel_delayable(&overflow_retry_work);
|
||||
|
||||
/* Skip fast advertising on reconnect — go straight to slow.
|
||||
* Prevents tight reconnect flapping loops on flaky links. */
|
||||
adv_post_disconnect = true;
|
||||
|
||||
/* Notify main of BLE disconnection */
|
||||
if (ble_cbs && ble_cbs->on_disconnected) {
|
||||
ble_cbs->on_disconnected();
|
||||
@@ -354,6 +359,16 @@ static void recycled(void)
|
||||
adv_switching, adv_is_slow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (adv_post_disconnect) {
|
||||
/* After disconnect, skip fast advertising — go straight to slow.
|
||||
* Prevents rapid reconnect flapping on flaky BLE links. */
|
||||
adv_post_disconnect = false;
|
||||
LOG_INF("post-disconnect: starting slow advertising directly");
|
||||
adv_slow_work_fn(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("restart advertising");
|
||||
start_adv();
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ CompanionMesh::CompanionMesh(mesh::Radio &radio, mesh::MillisecondClock &ms, mes
|
||||
_offline_queue_head = 0;
|
||||
_offline_queue_tail = 0;
|
||||
_offline_queue_count = 0;
|
||||
_sync_pending = false;
|
||||
memset(_ack_table, 0, sizeof(_ack_table));
|
||||
_ack_next_overwrite = 0;
|
||||
memset(_advert_paths, 0, sizeof(_advert_paths));
|
||||
@@ -392,6 +393,22 @@ bool CompanionMesh::dequeueOfflineMessage(uint8_t *dest, size_t &len)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompanionMesh::peekOfflineMessage(uint8_t *dest, size_t &len)
|
||||
{
|
||||
if (_offline_queue_count == 0) return false;
|
||||
QueuedFrame *f = &_offline_queue[_offline_queue_head];
|
||||
len = f->len;
|
||||
memcpy(dest, f->buf, len);
|
||||
return true; /* head NOT advanced — message stays in queue */
|
||||
}
|
||||
|
||||
void CompanionMesh::confirmOfflineMessage()
|
||||
{
|
||||
if (_offline_queue_count == 0) return;
|
||||
_offline_queue_head = (_offline_queue_head + 1) % OFFLINE_QUEUE_SIZE;
|
||||
_offline_queue_count--;
|
||||
}
|
||||
|
||||
void CompanionMesh::resetContactIterator()
|
||||
{
|
||||
if (_contact_iter_active) {
|
||||
@@ -1677,12 +1694,21 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
}
|
||||
|
||||
case CMD_SYNC_NEXT_MESSAGE: {
|
||||
LOG_INF("CMD_SYNC_NEXT_MESSAGE: queue_count=%d", _offline_queue_count);
|
||||
LOG_INF("CMD_SYNC_NEXT_MESSAGE: queue_count=%d pending=%d",
|
||||
_offline_queue_count, _sync_pending);
|
||||
|
||||
/* Phone asking for next = implicit ACK for the previously-peeked message */
|
||||
if (_sync_pending) {
|
||||
confirmOfflineMessage();
|
||||
_sync_pending = false;
|
||||
}
|
||||
|
||||
uint8_t buf[MAX_FRAME_SIZE];
|
||||
size_t msg_len;
|
||||
if (dequeueOfflineMessage(buf, msg_len)) {
|
||||
LOG_INF("CMD_SYNC_NEXT_MESSAGE: dequeued msg_len=%u type=0x%02x", (unsigned)msg_len, buf[0]);
|
||||
if (peekOfflineMessage(buf, msg_len)) {
|
||||
LOG_INF("CMD_SYNC_NEXT_MESSAGE: peeked msg_len=%u type=0x%02x", (unsigned)msg_len, buf[0]);
|
||||
writeFrame(buf, msg_len);
|
||||
_sync_pending = true; /* will be confirmed on next request or lost on disconnect */
|
||||
} else {
|
||||
LOG_INF("CMD_SYNC_NEXT_MESSAGE: queue empty, sending NO_MORE_MSGS");
|
||||
uint8_t rsp[] = { PACKET_NO_MORE_MSGS };
|
||||
|
||||
@@ -162,9 +162,22 @@ public:
|
||||
|
||||
/**
|
||||
* Reset contact iterator (call when new command received).
|
||||
* Sends PACKET_CONTACT_END if iteration was in progress.
|
||||
*/
|
||||
void resetContactIterator();
|
||||
|
||||
/**
|
||||
* Cancel contact iteration silently (no frame sent).
|
||||
* Call on BLE disconnect — there's nobody to send CONTACT_END to.
|
||||
*/
|
||||
void cancelContactIterator() { _contact_iter_active = false; }
|
||||
|
||||
/**
|
||||
* Cancel pending message sync. Un-ACKed message stays in queue.
|
||||
* Call on BLE disconnect so the message is re-sent on reconnect.
|
||||
*/
|
||||
void cancelSyncPending() { _sync_pending = false; }
|
||||
|
||||
/**
|
||||
* Get BLE device name for advertising.
|
||||
*/
|
||||
@@ -270,6 +283,7 @@ private:
|
||||
int _offline_queue_head;
|
||||
int _offline_queue_tail;
|
||||
int _offline_queue_count;
|
||||
bool _sync_pending; /* true = last peeked message not yet ACKed by phone */
|
||||
|
||||
/* ACK tracking table */
|
||||
struct AckEntry {
|
||||
@@ -328,6 +342,8 @@ private:
|
||||
|
||||
void queueOfflineMessage(const uint8_t *data, size_t len);
|
||||
bool dequeueOfflineMessage(uint8_t *dest, size_t &len);
|
||||
bool peekOfflineMessage(uint8_t *dest, size_t &len);
|
||||
void confirmOfflineMessage();
|
||||
|
||||
void queueContactMessage(const ContactInfo &contact, mesh::Packet *pkt,
|
||||
uint8_t txt_type, uint32_t sender_timestamp, const uint8_t *extra, int extra_len, const char *text);
|
||||
|
||||
@@ -141,11 +141,21 @@ static void ble_on_connected(void)
|
||||
ui_notify(UI_EVENT_BLE_CONNECTED);
|
||||
}
|
||||
|
||||
/* BLE disconnected callback — notify UI */
|
||||
/* BLE disconnected callback — clean up state and notify UI */
|
||||
static void ble_on_disconnected(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_LOG)
|
||||
zephcore_usb_companion_reset_rx();
|
||||
#endif
|
||||
#ifdef ZEPHCORE_LORA
|
||||
/* Silently cancel any in-progress contact iteration.
|
||||
* Without this, reconnect triggers resetContactIterator() which sends
|
||||
* a stale PACKET_CONTACT_END to the NEW connection, confusing the
|
||||
* phone's sync state machine. */
|
||||
companion_mesh_ptr->cancelContactIterator();
|
||||
/* Reset message sync — un-ACKed peeked message stays in queue
|
||||
* and will be re-sent on next CMD_SYNC_NEXT_MESSAGE. */
|
||||
companion_mesh_ptr->cancelSyncPending();
|
||||
#endif
|
||||
ui_notify(UI_EVENT_BLE_DISCONNECTED);
|
||||
}
|
||||
@@ -205,8 +215,10 @@ static void rx_process_work_fn(struct k_work *work)
|
||||
/* Process all queued frames */
|
||||
while (k_msgq_get(zephcore_ble_get_recv_queue(), &f, K_NO_WAIT) == 0) {
|
||||
#ifdef ZEPHCORE_LORA
|
||||
/* Reset contact iterator when new command received */
|
||||
companion_mesh_ptr->resetContactIterator();
|
||||
/* handleProtocolFrame() resets the contact iterator internally
|
||||
* (line 1229) for any non-CMD_GET_CONTACTS command — no need
|
||||
* to call resetContactIterator() here. Doing so sent a stale
|
||||
* PACKET_CONTACT_END before the command was even processed. */
|
||||
if (!companion_mesh_ptr->handleProtocolFrame(f.buf, f.len)) {
|
||||
LOG_DBG("rx_process: unknown cmd 0x%02x len=%u", f.buf[0], (unsigned)f.len);
|
||||
uint8_t err_rsp[] = { 0x01, 0x01 }; /* PACKET_ERROR, ERR_UNSUPPORTED */
|
||||
|
||||
Reference in New Issue
Block a user