mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-17 02:54:19 +00:00
deploy: 3f6eddd5c2
This commit is contained in:
+11
-1
@@ -6629,7 +6629,9 @@ get clock.sync.status
|
||||
<h4 id="view-or-set-the-direct-path-override-for-the-current-remote-client">View or set the direct path override for the current remote client</h4>
|
||||
<p><strong>Usage:</strong>
|
||||
- <code>get outpath</code>
|
||||
- <code>get outpath path</code>
|
||||
- <code>set outpath <hop1_hex,hop2_hex,...></code>
|
||||
- <code>set outpath path</code>
|
||||
- <code>set outpath direct</code>
|
||||
- <code>set outpath clear</code>
|
||||
- <code>set outpath flood</code></p>
|
||||
@@ -6637,8 +6639,16 @@ get clock.sync.status
|
||||
- <code>hopN_hex</code>: Hop hash with <code>2</code>, <code>4</code>, or <code>6</code> hexadecimal characters. Every hop must use the same width.</p>
|
||||
<p><strong>Notes:</strong>
|
||||
- These commands require remote client context and update the caller's ACL entry.
|
||||
- <code>get outpath path</code> reports the reciprocal <code>PAYLOAD_TYPE_PATH</code> received after
|
||||
the caller's latest flood login without changing the selected output route.
|
||||
Because that packet is asynchronous, an immediate query can report
|
||||
<code>> path pending</code>; retry shortly. The observation window expires after one
|
||||
minute, and the captured login path is not automatically selected.
|
||||
- <code>set outpath path</code> copies that observed route to <code>outpath</code> and saves it. It
|
||||
returns an error without changing <code>outpath</code> if no route was received.
|
||||
- <code>direct</code> selects a zero-hop route for a directly reachable caller.
|
||||
- <code>clear</code> forgets the override so normal path discovery can repopulate it.
|
||||
- <code>clear</code> forgets the override, replies <code>> outpath cleared</code>, and allows normal
|
||||
path discovery to repopulate it.
|
||||
- <code>flood</code> forces replies to use flood packets until the client logs in again.</p>
|
||||
<hr />
|
||||
<h4 id="view-or-change-this-nodes-repeat-flag">View or change this node's repeat flag</h4>
|
||||
|
||||
@@ -1818,7 +1818,9 @@ hex characters, and all hops in one path must use the same width. Hex input is
|
||||
case-insensitive. Replies use uppercase hex and retain the commas, so the value
|
||||
can be copied directly into another <code>set outpath</code> or <code>set altpath</code> command.</p>
|
||||
<pre><code class="language-text">get outpath
|
||||
get outpath path
|
||||
set outpath A1B2C3,D4E5F6
|
||||
set outpath path
|
||||
set outpath direct
|
||||
set outpath clear
|
||||
set outpath flood
|
||||
@@ -1832,10 +1834,17 @@ set altpath clear
|
||||
</code></pre>
|
||||
<p>The first CLI word is case-insensitive (<code>set</code>, <code>Set</code>, and <code>SET</code> are the same,
|
||||
as are <code>get</code>, <code>Get</code>, and the other command verbs). Argument case is preserved.</p>
|
||||
<p><code>get outpath path</code> reports the reciprocal path received after the latest flood
|
||||
login without changing <code>outpath</code>. That packet arrives asynchronously, so retry
|
||||
shortly if the first query reports <code>> path pending</code>; the observation window
|
||||
expires after one minute. The login path is not automatically selected.
|
||||
<code>set outpath path</code> copies the observed route into <code>outpath</code> and saves it; it
|
||||
leaves the current route unchanged when no observed route is available.</p>
|
||||
<p><code>set outpath direct</code> sets a zero-hop direct route for a client reachable without
|
||||
repeaters. <code>set outpath clear</code> forgets the override and lets normal path
|
||||
discovery fill it again. <code>set outpath flood</code> forces replies to use flood packets
|
||||
until the client logs in again.</p>
|
||||
repeaters. <code>set outpath clear</code> forgets the override, replies
|
||||
<code>> outpath cleared</code>, and lets normal path discovery fill it again.
|
||||
<code>set outpath flood</code> forces replies to use flood packets until the client logs in
|
||||
again.</p>
|
||||
<p>When <code>outpath</code> is a valid direct path and <code>altpath</code> is also a valid, different
|
||||
direct path, repeater DM replies send two packets: one on <code>outpath</code> and one on
|
||||
<code>altpath</code>. The secondary <code>altpath</code> copy does not create its own direct-retry
|
||||
|
||||
+53
-9
@@ -2594,8 +2594,13 @@ label and stage a different manifest.</p>
|
||||
<pre><code>OTA_GET_MANIFEST: manifest_id[4] want_mask(uint16) # bit k = send manifest fragment k; 0xFFFF = all
|
||||
OTA_MANIFEST: manifest_id[4] frag_idx(1) frag_total(1) bytes[] # up to OTA_MF_FRAG=176 B/frag
|
||||
OTA_REQ: manifest_id[4] { block_idx(uint16) want_mask(uint16) }[1..4]
|
||||
# one or more rows; bit k = send fragment k of that block
|
||||
OTA_DATA: manifest_id[4] block_idx(uint16) frag_off(uint16) data[] # up to OTA_FRAG_DATA=160 B
|
||||
# legacy: bit k requests its 160-byte fragment
|
||||
# v2: bit15=marker, bit14=allow transport DEFLATE, bits0..12=fragment bitmap
|
||||
OTA_DATA legacy: manifest_id[4] block_idx(uint16) frag_off(uint16) data[<=160]
|
||||
OTA_DATA v2: manifest_id[4] block_idx(uint16) descriptor(uint16)
|
||||
stream_id[4] data[<=171]
|
||||
# descriptor: bit15=marker, bit14=DEFLATE, bits13..10=fragment,
|
||||
# bits9..0=complete encoded length minus one
|
||||
OTA_REQ_PROOF: manifest_id[4] block_idx(uint16)
|
||||
OTA_PROOF: manifest_id[4] block_idx(uint16) n_proof(1) proof[] # n_proof x 4 bytes
|
||||
OTA_GET_LEAVES: manifest_id[4] want_mask(uint16) # bit k = send leaves fragment k; 0xFFFF = all
|
||||
@@ -2617,11 +2622,31 @@ OTA_LEAVES: manifest_id[4] frag_idx(1) frag_total(1) bytes[] # up
|
||||
is answering <code>OTA_GET_LEAVES</code> with leaves the node already holds, so any node's firmware can be captured.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Block <-> fragments:</strong> a 1 KB block remains split into self-describing <code>OTA_DATA</code> fragments. <code>frag_off</code> is the
|
||||
byte offset of <code>data</code> within the block, so the global position is <code>block_idx*block_size + frag_off</code> -
|
||||
a fragment is self-placing when returned by the source. The fetcher tracks a
|
||||
per-block slice bitmap and reassembles before requesting the proof.</p>
|
||||
<p><strong>Negotiated 171-byte fragments:</strong> the deployed profile remains unchanged: <code>frag_off</code> is a byte offset and
|
||||
<code>data[]</code> carries at most 160 bytes. A new fetcher marks an <code>OTA_REQ</code> row as v2 and includes all seven legacy
|
||||
bits on its first request. Old sources ignore/mask the high flags and can therefore return a complete legacy
|
||||
block immediately; receipt of an untagged <code>OTA_DATA</code> switches that fetch session to the old geometry. If no
|
||||
v2 data appears by the first adaptive deadline, the fetcher retries with an ordinary legacy mask. New
|
||||
sources answer v2 with a packed descriptor, a repeated 4-byte representation ID, and exactly 171 data bytes
|
||||
except the final fragment. A raw 1 KiB block therefore falls from seven data packets to six. Message type
|
||||
IDs do not change, so multi-hop relays continue to forward request/data/proof packets opaquely with the same
|
||||
priority.</p>
|
||||
</li>
|
||||
<li><strong>Transport-only DEFLATE:</strong> a fetcher sets the v2 DEFLATE-permission bit only when its application includes
|
||||
and configures the decoder. A source may encode each logical block as an independent raw RFC 1951 stream
|
||||
with full stored, fixed-Huffman, and dynamic-Huffman support (<code>BTYPE=0/1/2</code>). Compression is used only when
|
||||
strictly smaller, otherwise the source returns raw v2 data. The
|
||||
receiver inflates to the manifest-derived block length, then performs the unchanged Merkle proof and writes
|
||||
the original bytes to staging. Thus existing <code>.mota</code> containers, signatures, resume markers, and legacy
|
||||
bootloader apply remain unchanged. The 4-byte <code>stream_id</code> is SHA-256:4 of the complete raw or compressed
|
||||
representation and appears in every fragment. A receiver locks <code>{encoding, encoded length, stream_id}</code> for
|
||||
a block, preventing fragments from independently encoded seeders from being mixed. After one sparse retry,
|
||||
a second stalled interval clears the full in-flight window and switches the session to legacy geometry, so
|
||||
a vanished v2 seeder cannot prevent an older source from taking over; proof verification remains unchanged.
|
||||
Every <code>ENABLE_OTA</code> MeshCore application registers the vendored tinf 1.2.1 full raw decoder; its wrapper
|
||||
bounds output to the exact logical block length and rejects truncation, malformed streams, and trailing
|
||||
whole bytes. Builds without OTA do not link the decoder. This application capability is independent of the
|
||||
bootloader because transport data is inflated before the unchanged staged container is written.</li>
|
||||
<li><strong>Adaptive flight size is not signed block size.</strong> The container continues to use 1 KiB Merkle leaves and
|
||||
each slot is one existing 1 KiB block. A clean link changes how many of those blocks one <code>OTA_REQ</code> names:
|
||||
1, then 2, then 3, then the compiled cap. The manifest stores <code>block_size_log2</code>, so 3 KiB is not a valid
|
||||
@@ -2642,7 +2667,8 @@ OTA_LEAVES: manifest_id[4] frag_idx(1) frag_total(1) bytes[] # up
|
||||
half-duplex radios: re-requesting a whole multi-fragment burst let the periodic retry (a transmit) collide
|
||||
with the tail of the in-flight burst and drop the same fragment forever - a hang. Requesting only the hole
|
||||
removes the burst, so there is nothing to collide with. The block/manifest mask matches the 16-bit
|
||||
reassembly bitmap (<=16 fragments/block; 1 KB blocks = 7). <code>OTA_PROOF</code> is a single packet and needs no mask.</li>
|
||||
reassembly bitmap (<=16 fragments/block; legacy 1 KB blocks = 7, raw v2 = 6). <code>OTA_PROOF</code> is a single packet
|
||||
and needs no mask.</li>
|
||||
<li><strong>Data and proof remain separate packets, without a normal extra round trip.</strong> A server retains requested
|
||||
blocks in a bounded descriptor queue, admits at most one response per main-loop pass, and sends one
|
||||
<code>OTA_PROOF</code> after each block's requested fragments. Before admitting that proactive proof, the source leaves
|
||||
@@ -2665,11 +2691,16 @@ OTA_LEAVES: manifest_id[4] frag_idx(1) frag_total(1) bytes[] # up
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>OTA_DATA</code></td>
|
||||
<td><code>OTA_DATA</code> legacy</td>
|
||||
<td>9 B (type+mid4+idx2+off2)</td>
|
||||
<td><code>OTA_FRAG_DATA = 160</code> -> 7 frags per 1 KB block</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>OTA_DATA</code> v2</td>
|
||||
<td>13 B (legacy header + stream ID)</td>
|
||||
<td><code>OTA_FRAG_DATA_V2 = 171</code> -> 6 raw frags per 1 KB block; fewer when compressed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>OTA_MANIFEST</code></td>
|
||||
<td>7 B</td>
|
||||
<td><code>OTA_MF_FRAG = 176</code> -> signed manifest ~ 2 frags</td>
|
||||
@@ -2779,12 +2810,15 @@ a folder destination.</p>
|
||||
drives USB-serial, BLE, a WiFi URL list, an NFS/samba mount, etc. - only <code>read()</code> differs.</p>
|
||||
<pre><code class="language-cpp">struct MotaDesc { // catalog metadata + region offsets (no whole image in RAM)
|
||||
uint8_t mid[4]; uint32_t target_id, fw_version; uint8_t codec_id, flags;
|
||||
uint8_t block_size_log2, source_caps;
|
||||
uint32_t total_size, leaves_off, block_count, payload_off, payload_size;
|
||||
};
|
||||
class MotaSource {
|
||||
virtual uint8_t count(); // # mOTAs offered
|
||||
virtual bool describe(uint8_t idx, MotaDesc& out); // metadata + offsets
|
||||
virtual bool read(uint8_t idx, uint32_t off, uint8_t* buf, uint32_t len); // random-access bytes
|
||||
virtual bool read_deflated_block(uint8_t idx, uint16_t block,
|
||||
uint8_t* buf, uint16_t cap, uint16_t* len); // optional raw RFC 1951
|
||||
};
|
||||
</code></pre>
|
||||
<p>To serve an external mota the node reads its manifest-minus-leaves + <code>leaves[]</code> into RAM (<=4 KB for <=1024
|
||||
@@ -2804,9 +2838,11 @@ response (host -> device): 'm' 's' op(1) status(1) payload... xsum(1 =
|
||||
OP_COUNT 0x01 args: - -> payload: count(1)
|
||||
OP_DESCRIBE 0x02 args: idx(1) -> payload: MotaDesc wire (38 B)
|
||||
OP_READ 0x03 args: idx(1) off(4) len(2) -> payload: len bytes
|
||||
OP_DEFLATE_BLOCK 0x09 args: idx(1) block(2) off(2) len(2)
|
||||
-> payload: total_encoded_len(2) + requested bytes
|
||||
MotaDesc wire (38 B): mid[4] target_id(4) fw_version(4) codec(1) flags(1)
|
||||
total_size(4) leaves_off(4) block_count(4) payload_off(4) payload_size(4)
|
||||
block_size_log2(1) reserved(3)
|
||||
block_size_log2(1) source_caps(1) reserved(2)
|
||||
status: 0 = OK, non-zero = error (out of range / past EOF).
|
||||
</code></pre>
|
||||
<p><code>SerialMotaSource</code> splits logical reads into replies of at most 192 payload
|
||||
@@ -2815,6 +2851,14 @@ normally 1 KiB; requesting either in one transaction can overrun common USB
|
||||
CDC/UART receive rings even though the host successfully wrote the complete
|
||||
reply. Chunking is internal to the transport and does not change <code>OP_READ</code> or
|
||||
the <code>MotaSource</code> random-access contract.</p>
|
||||
<p><code>OP_DEFLATE_BLOCK</code> lets a host-folder source perform the optional transport compression without linking an
|
||||
encoder into the embedded seeder. <code>len=0, off=0</code> queries the exact encoded length; subsequent chunks are at
|
||||
most 190 bytes, keeping the total response payload at 192 bytes. The host independently encodes each manifest
|
||||
payload block as ordinary raw RFC 1951 at level 9. It returns an error for an invalid range, an unsupported
|
||||
operation, or a result that is not smaller than the raw block; <code>SerialMotaSource</code> then serves the ordinary raw
|
||||
v2 representation. A supporting host sets <code>source_caps bit 0</code> in every descriptor. Older hosts leave that
|
||||
formerly-reserved byte zero, so upgraded firmware skips the optional request instead of waiting for an old
|
||||
daemon that silently ignores unknown operations.</p>
|
||||
<p>Manifest fragments are retained as bounded response jobs and admitted one at
|
||||
a time. Their source-side gap follows the active maximum packet airtime and
|
||||
dispatcher duty spacing, clamped to 100-1000 ms. The 100 ms floor protects
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user