From 164f938982fa41a95f6bd0ab16d99398aff133f6 Mon Sep 17 00:00:00 2001 From: Dorian Date: Tue, 14 Apr 2026 10:40:28 -0400 Subject: [PATCH] fix(mesh): route DM-via-channel on channel 0 (channel 1 unsupported) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firmware rejected send_channel_text(1, ...) with "Unsupported command" because channel 1 isn't configured on the device. Revert to channel 0 for the DM wrapper — the 0xD1 marker + dest_prefix header still disambiguates DMs from plain public-channel text. Also revert Mesh.vue publicChannel back to index 0 so user-typed broadcasts target the same (only) working channel. Co-Authored-By: Claude Opus 4.6 (1M context) --- core/archipelago/src/mesh/listener/session.rs | 6 +++--- neode-ui/src/views/Mesh.vue | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/archipelago/src/mesh/listener/session.rs b/core/archipelago/src/mesh/listener/session.rs index af449343..9ca361bd 100644 --- a/core/archipelago/src/mesh/listener/session.rs +++ b/core/archipelago/src/mesh/listener/session.rs @@ -309,7 +309,7 @@ async fn handle_send_command( // payload with a recipient pubkey-prefix header so the // receiver side can tell it apart from normal channel text. let wrapped = wrap_dm_via_channel(&dest_pubkey_prefix, &payload); - if let Err(e) = device.send_channel_text(1, &wrapped).await { + if let Err(e) = device.send_channel_text(0, &wrapped).await { *consecutive_write_failures += 1; warn!(failures = *consecutive_write_failures, "Failed to send DM via channel: {}", e); } else { @@ -350,7 +350,7 @@ async fn handle_send_command( // Single frame — wraps under 160B. 160 − 7 wrapper − some // safety margin leaves ≈133 bytes for the base64 payload. let wrapped = wrap_dm_via_channel(&dest_pubkey_prefix, encoded.as_bytes()); - if let Err(e) = device.send_channel_text(1, &wrapped).await { + if let Err(e) = device.send_channel_text(0, &wrapped).await { *consecutive_write_failures += 1; warn!(failures = *consecutive_write_failures, "Failed to send raw DM-via-channel: {}", e); } else { @@ -378,7 +378,7 @@ async fn handle_send_command( for (idx, chunk) in chunks.iter().enumerate() { let frame = format!("MC{:02x}{:02x}{:02x}{}", msg_id, idx as u8, total, chunk); let wrapped = wrap_dm_via_channel(&dest_pubkey_prefix, frame.as_bytes()); - if let Err(e) = device.send_channel_text(1, &wrapped).await { + if let Err(e) = device.send_channel_text(0, &wrapped).await { *consecutive_write_failures += 1; warn!(failures = *consecutive_write_failures, chunk = idx, "Chunk DM-via-channel send failed: {}", e); break; diff --git a/neode-ui/src/views/Mesh.vue b/neode-ui/src/views/Mesh.vue index 9398f5c2..55d146f4 100644 --- a/neode-ui/src/views/Mesh.vue +++ b/neode-ui/src/views/Mesh.vue @@ -41,7 +41,7 @@ let pollInterval: ReturnType | null = null // + RF region. Slot 1 is set by archipelago first-boot to a hash derived // from the channel_name, so all archipelago nodes are guaranteed on the // same channel regardless of region. -const publicChannel = { index: 1, name: 'Public' } +const publicChannel = { index: 0, name: 'Public' } // Channel contact_id convention: matches backend u32::MAX - channel_index function channelContactId(channelIndex: number): number {