Repository navigation
LoRa Handshake
The LoRa handshake system prevents multiple nodes from interfering with each other while sending fragmented packets to a hub. Before sending data, a node asks for permission. If the hub is free, it accepts and locks itself to that sender until the current receive cycle finishes or expires.
Without a handshake, multiple nodes can transmit at the same time. That can break packet reassembly because fragments from different nodes arrive together, and it can leave the hub stuck.
The handshake gives one node temporary permission to send while the hub rejects or ignores competing senders.
With the handshake, the node first sends {"handshake":"Request"}. The hub either sends back {"handshake":"Accept"} or ignores the request if it is already occupied. The node only sends data after it receives the accept packet.
- Node calls
send(destinationAddress). - Node sends a handshake request to the hub.
- Hub checks whether it can accept a new sender.
- If free, hub sends a handshake accept response and records the sender address.
- Node receives the accept response and sends its JSON payload.
- Hub clears the handshake state after the receive cycle completes, or when the session times out.
- The hub only allows one active sender at a time.
- Other handshake attempts are ignored while the hub is locked to a sender.
- Timeout cleanup prevents the hub from staying locked forever if a node stops responding.
- The handshake protects fragmented packet reassembly by keeping fragments from different senders separated.
Top-level entry point called by the .ino file. It runs the handshake first. If the handshake or send fails, it returns false.
Attempts the handshake up to 2 times, waiting 10 seconds between failed attempts. It sends a request, waits for an accept packet, and then sends the JSON payload if accepted. If all retries fail, it logs the failure and returns false.
Sends {"handshake":"Request"} to the hub. Returns true if the packet was delivered successfully.
Waits up to 5 seconds for the hub's accept packet. Returns true when Accept is received and false on timeout.
Sends {"handshake":"Accept"} back to the requesting node after the hub decides to accept.
Processes an incoming handshake packet. It verifies that the packet contains a valid Request, sends an accept response, and calls beginHandshake() if the response succeeds. Returns false for malformed packets or failed responses.
Starts a handshake session by storing the node address and current timestamp. The timestamp is later used by clearExpiredHandshake() to detect stale sessions.
Resets all handshake state. It marks the session inactive, clears the peer address, and clears the timestamp. The public receive function calls this after a full receive cycle completes, whether the cycle succeeded or failed.
Checks whether the active session has exceeded HANDSHAKE_TIMEOUT_MS. If the session expired, it clears the handshake and returns true so the hub can accept another sender.
After a packet is received and deserialized, this checks for a handshake key. If one is present, stale sessions are cleared first. If another node already owns the active handshake, the packet is dropped and FragReceiveStatus::Incomplete is returned. Otherwise, the request is handled and the function returns FragReceiveStatus::HandshakeAccepted on success or FragReceiveStatus::Error for malformed handshake packets.