|
SH2SC-EDT
Self-Healing Hardware and Software Complex for Encrypted Data Transmission
|
SH2SC-EDT — Transmitter Node A ("The Conductor") firmware. More...
Include dependency graph for TransmitterNode.ino:Go to the source code of this file.
Functions | |
| static LiquidCrystal_AIP31068_I2C | lcd (TX_LCD_ADDR, TX_LCD_COLS, TX_LCD_ROWS) |
| I2C LCD — 16 columns x 2 rows, Aip31068-compatible controller. | |
| bool | readButtonPress () |
| Read and debounce the start button (millis-based falling-edge detector). | |
| static void | drainRxFifo () |
| Discard all bytes currently waiting in the hardware UART RX FIFO. | |
| void | sendHelloPacket () |
| Generate a fresh 12-byte CSPRNG nonce and broadcast it as a FLAG_SYN HelloPacket. | |
| void | sendPacket (uint8_t noteIndex, uint16_t noteDurationMs, uint16_t seqNumber) |
| void | formAndSendPacket (uint8_t note_idx, uint16_t duration_ms) |
| Snapshot the note payload and delegate to sendPacket() for encryption and transmission. | |
| void | updateTxDisplay (TxState state, uint16_t seqNumber, uint8_t retries) |
| Refresh the TX LCD with the current ARQ status and FSM state label. | |
| void | sendFinPacket () |
| Construct and transmit a FLAG_FIN session-teardown packet. | |
| static void | onRingOscPulse () |
| INT0 interrupt service routine — counts ring oscillator rising edges. | |
| static uint32_t | mixEntropy (uint32_t pool, uint32_t bits) |
| One mixing step of the entropy accumulation sponge. | |
| void | generateEntropyPool (uint8_t *outputSeed) |
Harvest 256 bits of hardware entropy and write them to outputSeed (TX variant). | |
| void | suspendSession () |
| Perform an unclean session teardown and enter the Self-Healing reconnect loop. | |
| void | tx_setup () |
| Initialise TX hardware and seed the CSPRNG. Called once from setup(). | |
| void | tx_loop () |
| Execute one non-blocking C2P-ARQ FSM tick. Called repeatedly from loop(). | |
| void | setup () |
| Arduino sketch entry point — delegates to tx_setup(). | |
| void | loop () |
| Arduino sketch main loop — delegates to tx_loop() on every iteration. | |
Variables | |
| static TxState | currentState = TxState::IDLE |
| Active FSM state. | |
| static uint16_t | melodyIndex = 0 |
| Current position in melody[][] (preserved across RECONNECTING). | |
| static uint16_t | seqNum = 0 |
| Packet sequence number (0–65535, wraps). | |
| static uint8_t | retryCount = 0 |
| Consecutive retransmission counter (displayed on LCD). | |
| static uint32_t | ackWaitStart = 0 |
| millis() timestamp when the current ACK-wait window opened. | |
| static uint32_t | lastReconnectAttempt = 0 |
| Auto-reconnect countdown; a new HelloPacket is broadcast when (millis() - lastReconnectAttempt) >= RECONNECT_INTERVAL_MS. | |
| static uint8_t | s_sessionNonce [HELLO_NONCE_SIZE] |
| 96-bit session nonce generated once per button press by sendHelloPacket(). | |
| static ChaChaPoly | s_cipher |
| ChaCha20-Poly1305 cipher instance — re-initialised per packet via clear(). | |
| static uint8_t | pendingNoteIndex = 0 |
| Snapshot of the last transmitted note index — allows retransmission without re-reading PROGMEM. | |
| static uint16_t | pendingNoteDuration = 0 |
| Snapshot of the last transmitted note duration (ms) — allows retransmission without re-reading PROGMEM. | |
| static uint32_t | noteWaitStart = 0 |
| millis() timestamp marking the start of the current WAIT_BETWEEN_NOTES pause. | |
| static bool | btnLastRawState = HIGH |
| Raw digitalRead() result from the previous call. | |
| static bool | btnStableState = HIGH |
| Debounce-confirmed stable button state. | |
| static uint32_t | btnLastChangeMs = 0 |
| millis() timestamp of the last raw state transition. | |
| static volatile uint32_t | s_ringOscPulses = 0 |
| Ring oscillator pulse counter — incremented by the INT0 ISR on pin 2. | |
SH2SC-EDT — Transmitter Node A ("The Conductor") firmware.
Part of the SH2SC-EDT project. Implements the C2P-ARQ protocol. Flash this sketch onto the TX Arduino Nano.
Responsibilities:
Definition in file TransmitterNode.ino.
|
inlinestatic |
Discard all bytes currently waiting in the hardware UART RX FIFO.
Prevents stale NACK bytes — accumulated from noise bursts before the session started — from being misread as responses to the packet that is about to be transmitted. Called at the start of every send function (sendHelloPacket(), sendPacket(), sendFinPacket()) to guarantee that the first byte read after a send is always a fresh response.
Definition at line 104 of file TransmitterNode.ino.
Referenced by sendFinPacket(), sendHelloPacket(), and sendPacket().
Here is the caller graph for this function:| void formAndSendPacket | ( | uint8_t | note_idx, |
| uint16_t | duration_ms | ||
| ) |
Snapshot the note payload and delegate to sendPacket() for encryption and transmission.
High-level wrapper called by the SENDING FSM state.
Stores note_idx and duration_ms as the pending retransmit snapshot so that on NACK or timeout, the FSM can call sendPacket() directly without re-reading PROGMEM.
| note_idx | Note index read from the PROGMEM melody table (0–20 or REST_INDEX=255). |
| duration_ms | Note duration in milliseconds read from the PROGMEM melody table. |
Definition at line 209 of file TransmitterNode.ino.
References pendingNoteDuration, pendingNoteIndex, sendPacket(), and seqNum.
Referenced by tx_loop().
Here is the call graph for this function:
Here is the caller graph for this function:| void generateEntropyPool | ( | uint8_t * | outputSeed | ) |
Harvest 256 bits of hardware entropy and write them to outputSeed (TX variant).
Harvest 256 bits of hardware entropy and write them to outputSeed (RX variant).
Harvest 256 bits of hardware entropy and write them to outputSeed.
Fills outputSeed[32] as 8 independent 32-bit words. Each word is produced by a fresh pass over all seven entropy sources so that a biased source in one iteration is compensated by the others through the rotate-XOR mixing chain. Total execution time: 8 iterations x 2 ms gate = ~16 ms (one-shot cost). This is the TX variant — it includes micros() human-timing jitter from the button press as a seventh source not present on the RX node.
| outputSeed | Pointer to a 32-byte output buffer. Must be valid and writable. Pass directly to initCSPRNG(); scrub afterwards if desired. |
true. Definition at line 345 of file TransmitterNode.ino.
Referenced by tx_setup().
Here is the caller graph for this function:
|
static |
I2C LCD — 16 columns x 2 rows, Aip31068-compatible controller.
Referenced by suspendSession(), tx_setup(), and updateTxDisplay().
Here is the caller graph for this function:| void loop | ( | ) |
Arduino sketch main loop — delegates to tx_loop() on every iteration.
Definition at line 714 of file TransmitterNode.ino.
References tx_loop().
Here is the call graph for this function:
|
inlinestatic |
One mixing step of the entropy accumulation sponge.
Left-rotates pool by 1 bit, then XOR-folds in bits. Left-rotation ensures each bit of the pool eventually influences all others, preventing entropy accumulation from being purely commutative.
| pool | Accumulated entropy pool value from previous iterations. |
| bits | New entropy bits to fold in. |
Definition at line 329 of file TransmitterNode.ino.
Referenced by generateEntropyPool().
Here is the caller graph for this function:
|
static |
INT0 interrupt service routine — counts ring oscillator rising edges.
Definition at line 318 of file TransmitterNode.ino.
References s_ringOscPulses.
Referenced by generateEntropyPool().
Here is the caller graph for this function:| bool readButtonPress | ( | ) |
Read and debounce the start button (millis-based falling-edge detector).
Read and debounce the start button using a millis()-based filter.
Must be called every iteration of loop() so the debounce timer continues accumulating regardless of the active FSM state.
true exactly once per confirmed physical button press; false otherwise. Definition at line 71 of file TransmitterNode.ino.
References btnLastChangeMs, btnLastRawState, btnStableState, DEBOUNCE_DELAY_MS, and TX_BUTTON_PIN.
Referenced by tx_loop().
Here is the caller graph for this function:| void sendFinPacket | ( | ) |
Construct and transmit a FLAG_FIN session-teardown packet.
Construct and transmit the FLAG_FIN session-close packet.
Architecture mirrors sendPacket() exactly: same per-packet nonce derivation (XOR bytes 10–11 with seqNum), same 3-byte AAD (FLAG_FIN + seq_num), same truncated 8-byte Poly1305 MAC. The plaintext payload is all-zeros; the flags byte in the AAD binds the MAC to FLAG_FIN, preventing a bit-flip attack from turning a data packet into a teardown signal. Called from SENDING_FIN; retransmitted on NACK or timeout until MAX_RETRIES is exhausted (which triggers suspendSession()).
Definition at line 266 of file TransmitterNode.ino.
References DATA_PAYLOAD_SIZE, drainRxFifo(), FLAG_FIN, DataPacket::flags, HELLO_NONCE_SIZE, DataPacket::mac, MASTER_PSK, DataPacket::payload, s_cipher, s_sessionNonce, DataPacket::seq_num, seqNum, SYNC_BYTE_1, SYNC_BYTE_2, and TRUNCATED_MAC_SIZE.
Referenced by tx_loop().
Here is the call graph for this function:
Here is the caller graph for this function:| void sendHelloPacket | ( | ) |
Generate a fresh 12-byte CSPRNG nonce and broadcast it as a FLAG_SYN HelloPacket.
Generate a fresh 12-byte CSPRNG session nonce and transmit it as a HelloPacket.
Called once per button press (from IDLE state) and once per reconnect attempt (from RECONNECTING state) — always before any DataPacket is transmitted. Calls drainRxFifo() before writing to the UART to purge stale NACKs. Stores the generated nonce in s_sessionNonce for subsequent per-packet IV derivation by sendPacket() and sendFinPacket().
Definition at line 118 of file TransmitterNode.ino.
References drainRxFifo(), FLAG_SYN, HelloPacket::flags, getSecureRandom32(), HELLO_NONCE_SIZE, HelloPacket::nonce, s_sessionNonce, SYNC_BYTE_1, and SYNC_BYTE_2.
Referenced by tx_loop().
Here is the call graph for this function:
Here is the caller graph for this function:| void sendPacket | ( | uint8_t | noteIndex, |
| uint16_t | noteDurationMs, | ||
| uint16_t | seqNumber | ||
| ) |
Definition at line 142 of file TransmitterNode.ino.
References DATA_PAYLOAD_SIZE, drainRxFifo(), FLAG_DAT, DataPacket::flags, HELLO_NONCE_SIZE, DataPacket::mac, MASTER_PSK, DataPacket::payload, s_cipher, s_sessionNonce, DataPacket::seq_num, SYNC_BYTE_1, SYNC_BYTE_2, and TRUNCATED_MAC_SIZE.
Referenced by formAndSendPacket().
Here is the call graph for this function:
Here is the caller graph for this function:| void setup | ( | ) |
Arduino sketch entry point — delegates to tx_setup().
Definition at line 712 of file TransmitterNode.ino.
References tx_setup().
Here is the call graph for this function:| void suspendSession | ( | ) |
Perform an unclean session teardown and enter the Self-Healing reconnect loop.
Suspend the current C2P-ARQ session and enter the Self-Healing reconnect loop.
Called when retryCount reaches MAX_RETRIES in any WAITING_* FSM state. Unlike a clean FIN close, this is an unclean abort — the receiver vanished without sending FLAG_FIN. Actions performed:
s_sessionNonce via memset() (forward secrecy — the old nonce must not be reused after an unclean close).seqNum and retryCount to 0.melodyIndex — the defining Self-Healing property of SH2SC-EDT; transmission will resume from the exact note of failure on reconnect.TxState::RECONNECTING.lastReconnectAttempt so the first auto-ping fires after a full RECONNECT_INTERVAL_MS, giving the receiver time to reboot. delay(2000) inside this function is the only permitted blocking call outside of setup() — it holds the LCD error message visible to the operator. Definition at line 426 of file TransmitterNode.ino.
References currentState, HELLO_NONCE_SIZE, lastReconnectAttempt, lcd(), RECONNECTING, retryCount, s_sessionNonce, and seqNum.
Referenced by tx_loop().
Here is the call graph for this function:
Here is the caller graph for this function:| void tx_loop | ( | ) |
Execute one non-blocking C2P-ARQ FSM tick. Called repeatedly from loop().
Execute one non-blocking FSM tick for the Transmitter node.
Dispatches to the handler for the active TxState. Each invocation performs at most one FSM transition and returns immediately. No delay() calls are permitted in this function or any callee (except the intentional 2-second error display in suspendSession()).
Definition at line 486 of file TransmitterNode.ino.
References ACK_BYTE, ACK_TIMEOUT_MS, ackWaitStart, currentState, formAndSendPacket(), HELLO_NONCE_SIZE, IDLE, lastReconnectAttempt, MAX_RETRIES, melody, MELODY_LENGTH, melodyIndex, NACK_BYTE, noteWaitStart, pendingNoteDuration, pendingNoteIndex, readButtonPress(), RECONNECT_INTERVAL_MS, RECONNECTING, retryCount, s_sessionNonce, sendFinPacket(), sendHelloPacket(), SENDING, SENDING_FIN, SENDING_HELLO, seqNum, suspendSession(), updateTxDisplay(), WAIT_BETWEEN_NOTES, WAITING_ACK, WAITING_FIN_ACK, and WAITING_HELLO_ACK.
Referenced by loop().
Here is the call graph for this function:
Here is the caller graph for this function:| void tx_setup | ( | ) |
Initialise TX hardware and seed the CSPRNG. Called once from setup().
Initialise TX hardware: UART, I2C LCD, button pin, ring-oscillator entropy.
Initialises UART at BAUD_RATE (9600), configures TX_BUTTON_PIN as INPUT_PULLUP, initialises the I2C LCD, harvests 256-bit hardware entropy with generateEntropyPool(), seeds the ChaCha20 CSPRNG with initCSPRNG(), scrubs the entropy seed buffer from the stack, and sets the initial FSM state to IDLE.
Definition at line 454 of file TransmitterNode.ino.
References BAUD_RATE, currentState, generateEntropyPool(), IDLE, initCSPRNG(), lcd(), retryCount, seqNum, TX_BUTTON_PIN, and updateTxDisplay().
Referenced by setup().
Here is the call graph for this function:
Here is the caller graph for this function:| void updateTxDisplay | ( | TxState | state, |
| uint16_t | seqNumber, | ||
| uint8_t | retries | ||
| ) |
Refresh the TX LCD with the current ARQ status and FSM state label.
Row 0: PKT: <seqNumber> RTY:<retries> (live ARQ visibility for the operator). Row 1: Human-readable FSM state name. Must only be called on FSM state transitions — NOT in a tight loop — to avoid I2C bus saturation.
| state | Current TxState to display on row 1. |
| seqNumber | Current packet sequence number to display on row 0. |
| retries | Current consecutive retry count to display on row 0. |
Definition at line 228 of file TransmitterNode.ino.
References IDLE, lcd(), RECONNECTING, SENDING, SENDING_FIN, SENDING_HELLO, WAIT_BETWEEN_NOTES, WAITING_ACK, WAITING_FIN_ACK, and WAITING_HELLO_ACK.
Referenced by tx_loop(), and tx_setup().
Here is the call graph for this function:
Here is the caller graph for this function:
|
static |
millis() timestamp when the current ACK-wait window opened.
Definition at line 32 of file TransmitterNode.ino.
Referenced by tx_loop().
|
static |
millis() timestamp of the last raw state transition.
Definition at line 63 of file TransmitterNode.ino.
Referenced by readButtonPress().
|
static |
Raw digitalRead() result from the previous call.
Definition at line 61 of file TransmitterNode.ino.
Referenced by readButtonPress().
|
static |
Debounce-confirmed stable button state.
Definition at line 62 of file TransmitterNode.ino.
Referenced by readButtonPress().
|
static |
Active FSM state.
Definition at line 28 of file TransmitterNode.ino.
Referenced by suspendSession(), tx_loop(), and tx_setup().
|
static |
Auto-reconnect countdown; a new HelloPacket is broadcast when (millis() - lastReconnectAttempt) >= RECONNECT_INTERVAL_MS.
Definition at line 35 of file TransmitterNode.ino.
Referenced by suspendSession(), and tx_loop().
|
static |
Current position in melody[][] (preserved across RECONNECTING).
Definition at line 29 of file TransmitterNode.ino.
Referenced by tx_loop().
|
static |
millis() timestamp marking the start of the current WAIT_BETWEEN_NOTES pause.
Definition at line 58 of file TransmitterNode.ino.
Referenced by tx_loop().
|
static |
Snapshot of the last transmitted note duration (ms) — allows retransmission without re-reading PROGMEM.
Definition at line 55 of file TransmitterNode.ino.
Referenced by formAndSendPacket(), and tx_loop().
|
static |
Snapshot of the last transmitted note index — allows retransmission without re-reading PROGMEM.
Definition at line 53 of file TransmitterNode.ino.
Referenced by formAndSendPacket(), and tx_loop().
|
static |
Consecutive retransmission counter (displayed on LCD).
Definition at line 31 of file TransmitterNode.ino.
Referenced by suspendSession(), tx_loop(), and tx_setup().
|
static |
ChaCha20-Poly1305 cipher instance — re-initialised per packet via clear().
Definition at line 50 of file TransmitterNode.ino.
Referenced by sendFinPacket(), and sendPacket().
|
static |
Ring oscillator pulse counter — incremented by the INT0 ISR on pin 2.
volatile to prevent the compiler from caching the value in a register. Definition at line 315 of file TransmitterNode.ino.
Referenced by generateEntropyPool(), and onRingOscPulse().
|
static |
96-bit session nonce generated once per button press by sendHelloPacket().
Per-packet IV derivation:
Erased with memset() in suspendSession() and on WAITING_FIN_ACK success (forward secrecy).
Definition at line 47 of file TransmitterNode.ino.
Referenced by sendFinPacket(), sendHelloPacket(), sendPacket(), suspendSession(), and tx_loop().
|
static |
Packet sequence number (0–65535, wraps).
Definition at line 30 of file TransmitterNode.ino.
Referenced by authenticateAndPlay(), formAndSendPacket(), processFinPacket(), sendFinPacket(), suspendSession(), tx_loop(), tx_setup(), and updateRxDisplay().