SH2SC-EDT
Self-Healing Hardware and Software Complex for Encrypted Data Transmission
Loading...
Searching...
No Matches
ReceiverNode.ino File Reference

SH2SC-EDT — Receiver Node B ("The Synthesizer") firmware. More...

#include "receiver.h"
#include <LiquidCrystal_AIP31068_I2C.h>
+ Include dependency graph for ReceiverNode.ino:

Go to the source code of this file.

Enumerations

enum  ParseState : uint8_t { WAIT_AA , WAIT_55 , READ_TYPE , READ_PAYLOAD }
 Four-state byte-level frame assembly FSM states. More...
 

Functions

static LiquidCrystal_AIP31068_I2C lcd (RX_LCD_ADDR, RX_LCD_COLS, RX_LCD_ROWS)
 I2C LCD display object (Aip31068, 16×2, address 0x3E).
 
void updateRxDisplay (RxState state, uint16_t seqNum, bool macOk)
 Refresh the RX LCD with the current FSM state and last packet result.
 
static void resetParser ()
 Flush the UART RX FIFO and reset the byte-parser FSM to WAIT_AA.
 
void processReceivedByte (uint8_t inByte)
 Consume one incoming UART byte and advance the frame-assembly FSM.
 
void processHelloBody ()
 Store the received session nonce and install MASTER_PSK into the cipher.
 
void authenticateAndPlay (const DataPacket *pkt)
 Run the full ChaCha20-Poly1305 pipeline; play the note only on MAC success.
 
void processFinPacket (const DataPacket *pkt)
 Authenticate and process a FLAG_FIN session-teardown packet.
 
void startNote (uint16_t frequencyHz, uint16_t durationMs)
 Start non-blocking note playback on the piezo buzzer.
 
void stopNote ()
 Stop the currently playing note and clear the playback flag.
 
static void onRingOscPulse ()
 Ring oscillator ISR — increments pulse counter on each RISING edge.
 
static uint32_t mixEntropy (uint32_t pool, uint32_t bits)
 Single-step cryptographic entropy mixer — rotate-left XOR fold.
 
void generateEntropyPool (uint8_t *outputSeed)
 Harvest 256 bits of hardware entropy and fill outputSeed (RX variant).
 
void rx_setup ()
 Initialise RX hardware, seed the CSPRNG, and display the idle screen.
 
void rx_loop ()
 Execute one non-blocking C2P-ARQ FSM tick for the Receiver node.
 
void setup ()
 Arduino entry point — delegates to rx_setup().
 
void loop ()
 Arduino main loop — delegates to rx_loop().
 

Variables

static const uint16_t universal_notes [NOTE_DICT_SIZE]
 Universal note frequency dictionary for the C2P-ARQ Receiver.
 
static ParseState parseState = WAIT_AA
 Current byte-parser FSM state; reset to WAIT_AA by resetParser().
 
static uint8_t rx_buffer [sizeof(DataPacket)]
 Raw receive buffer sized to hold the largest frame body (DataPacket, 15 bytes).
 
static uint8_t rx_index = 0
 Number of bytes written to rx_buffer for the frame currently being collected.
 
static uint8_t expected_length = 0
 Total expected bytes for the current frame; set in READ_TYPE state.
 
static bool s_sessionActive = false
 Session active flag — set after a valid HelloPacket handshake; cleared on FIN or watchdog timeout.
 
static uint8_t s_sessionNonce [HELLO_NONCE_SIZE]
 12-byte session nonce delivered by the last accepted HelloPacket (FLAG_SYN).
 
static ChaChaPoly s_cipher
 ChaCha20-Poly1305 cipher instance; re-initialised per packet via clear().
 
static uint32_t noteStartMs = 0
 Timestamp (millis()) when the current note started playing.
 
static uint16_t noteLengthMs = 0
 Duration in milliseconds that the current note should sound.
 
static bool isPlayingNote = false
 True while a note is actively sounding; cleared by stopNote().
 
const uint16_t CHK_ERR_DISPLAY_MS = 500
 Duration of the MAC-error message shown on the LCD before returning to idle display.
 
static bool isShowingError = false
 True when the LCD is currently showing a MAC-error message.
 
static uint32_t errorDisplayStart = 0
 Timestamp (millis()) when the MAC-error display was last activated.
 
const uint16_t RX_PARSER_TIMEOUT_MS = 20
 Stale byte accumulation timeout for the byte-level frame parser.
 
static uint32_t rxLastByteMs = 0
 Timestamp (millis()) of the most recently received UART byte.
 
const uint32_t NETWORK_GRACE_PERIOD_MS = 3000
 Network grace period added to the last note's duration for the Dynamic Smart Watchdog.
 
static uint32_t current_timeout_limit = 5000
 Current Dynamic Watchdog timeout in milliseconds.
 
static uint32_t last_valid_packet_time = 0
 Timestamp (millis()) of the most recently successfully authenticated DataPacket.
 
static RxState currentState = RxState::WAITING_SYNC_1
 Tracks the current RxState for LCD display updates; independent of the byte-parser FSM.
 
static volatile uint32_t s_ringOscPulses = 0
 Pulse counter incremented by the ring oscillator ISR on INT0 (pin 2).
 

Detailed Description

SH2SC-EDT — Receiver Node B ("The Synthesizer") firmware.

Implements the C2P-ARQ protocol receive side. Responsibilities:

  • Initialise UART at 9600 bps, I2C LCD (Aip31068), and piezo buzzer.
  • Hold the universal note-frequency dictionary (indices 0–20, C4–G#5).
  • Byte-level frame parser FSM: WAIT_AA -> WAIT_55 -> READ_TYPE -> READ_PAYLOAD.
  • processHelloBody(): accept session nonce from HelloPacket, install PSK.
  • authenticateAndPlay(): full ChaCha20-Poly1305 pipeline; note is played only after memcmp(expectedMac, pkt->mac, TRUNCATED_MAC_SIZE) == 0.
  • processFinPacket(): authenticated session teardown with key erasure.
  • Dynamic Smart Watchdog: auto-teardown if TX disappears without FLAG_FIN.
  • Non-blocking buzzer timing via millis().
    Note
    Part of the SH2SC-EDT project. Flash onto the RX Arduino Nano (Node B).

Definition in file ReceiverNode.ino.

Enumeration Type Documentation

◆ ParseState

enum ParseState : uint8_t

Four-state byte-level frame assembly FSM states.

Drives processReceivedByte(). Both HELLO and DATA frames must pass through the 0xAA 0x55 preamble gate before any body bytes are accepted.

Enumerator
WAIT_AA 
WAIT_55 
READ_TYPE 
READ_PAYLOAD 

Definition at line 65 of file ReceiverNode.ino.

Function Documentation

◆ authenticateAndPlay()

void authenticateAndPlay ( const DataPacket pkt)

Run the full ChaCha20-Poly1305 pipeline; play the note only on MAC success.

Authenticate and decrypt a DataPacket (FLAG_DAT); play the note on MAC success.

Pipeline (mirrors TX sendPacket()):

  1. Read seq_num from the packed struct field directly.
  2. Derive per-packet nonce: local copy of s_sessionNonce, then packetNonce[10] ^= (seqNum >> 8), packetNonce[11] ^= seqNum.
  3. clear() -> setKey(MASTER_PSK, 32) -> setIV(packetNonce, 12).
  4. addAuthData({flags, seq_lo, seq_hi}, 3) — 3-byte plaintext AAD.
  5. decrypt(pkt->payload, plaintext, DATA_PAYLOAD_SIZE).
  6. computeTag(expectedMac, 16), then memcmp with truncated 8-byte tag. Security invariant: startNote() is called ONLY after memcmp returns 0. Also bounds-checks noteIndex < NOTE_DICT_SIZE before indexing universal_notes[] to prevent out-of-bounds reads on ATmega328P.
    Parameters
    pktPointer to the fully buffered DataPacket (flags == FLAG_DAT).

Definition at line 327 of file ReceiverNode.ino.

References ACK_BYTE, current_timeout_limit, currentState, DATA_PAYLOAD_SIZE, errorDisplayStart, EXECUTING_ACTION, DataPacket::flags, HELLO_NONCE_SIZE, isShowingError, last_valid_packet_time, lcd(), DataPacket::mac, MASTER_PSK, NACK_BYTE, NETWORK_GRACE_PERIOD_MS, NOTE_DICT_SIZE, DataPacket::payload, resetParser(), REST_INDEX, s_cipher, s_sessionNonce, DataPacket::seq_num, seqNum, startNote(), stopNote(), TRUNCATED_MAC_SIZE, universal_notes, and updateRxDisplay().

Referenced by processReceivedByte().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ generateEntropyPool()

void generateEntropyPool ( uint8_t *  outputSeed)

Harvest 256 bits of hardware entropy and fill outputSeed (RX 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 gathered from six hardware sources (micros() human-timing jitter is omitted — RX has no button):

  1. Ring oscillator on INT0 (pin 2): pulse count over a 2 ms gate.
  2. Uninitialised SRAM bytes at 0x0100 + wordIndex*8 (8 bytes per word).
  3. On-die temperature ADC (channel 8, 1.1 V reference): 8 LSBs per word.
  4. TCNT1 free-running timer snapshot (2 bytes).
  5. A0 white-noise ADC: 8 LSBs per word.
  6. Arduino software PRNG random() (obfuscation layer).

Total execution time: 8 × 2 ms gate ≈ 16 ms (one-shot in rx_setup()).

Parameters
outputSeedPointer to a 32-byte buffer for the entropy pool output. Pass directly to initCSPRNG(); scrub with memset() afterwards.
Note
Invoke once during rx_setup(), before the UART receive loop starts.

Definition at line 545 of file ReceiverNode.ino.

References ENTROPY_RING_OSC_PIN, mixEntropy(), mixEntropy(), onRingOscPulse(), onRingOscPulse(), s_ringOscPulses, and s_ringOscPulses.

Referenced by rx_setup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ lcd()

static LiquidCrystal_AIP31068_I2C lcd ( RX_LCD_ADDR  ,
RX_LCD_COLS  ,
RX_LCD_ROWS   
)
static

I2C LCD display object (Aip31068, 16×2, address 0x3E).

Referenced by authenticateAndPlay(), processFinPacket(), rx_loop(), rx_setup(), and updateRxDisplay().

+ Here is the caller graph for this function:

◆ loop()

void loop ( )

Arduino main loop — delegates to rx_loop().

Definition at line 722 of file ReceiverNode.ino.

References rx_loop().

+ Here is the call graph for this function:

◆ mixEntropy()

static uint32_t mixEntropy ( uint32_t  pool,
uint32_t  bits 
)
inlinestatic

Single-step cryptographic entropy mixer — rotate-left XOR fold.

Rotates pool left by 1 bit, then XORs in bits. Used iteratively by generateEntropyPool() for each entropy source.

Parameters
poolAccumulated entropy pool value.
bitsNew entropy bits to fold in.
Returns
Mixed pool value.

Definition at line 524 of file ReceiverNode.ino.

Referenced by generateEntropyPool().

+ Here is the caller graph for this function:

◆ onRingOscPulse()

static void onRingOscPulse ( )
static

Ring oscillator ISR — increments pulse counter on each RISING edge.

Definition at line 514 of file ReceiverNode.ino.

References s_ringOscPulses.

Referenced by generateEntropyPool().

+ Here is the caller graph for this function:

◆ processFinPacket()

void processFinPacket ( const DataPacket pkt)

Authenticate and process a FLAG_FIN session-teardown packet.

Authenticate a FLAG_FIN teardown packet and close the session on MAC success.

Cryptographic pipeline is identical to authenticateAndPlay() to guarantee that only the legitimate TX (holding MASTER_PSK and s_sessionNonce) can produce a verifiable FIN. A noise-induced FLAG_FIN byte will fail MAC and trigger NACK without touching the session state. Uses discardBuf to receive the zero plaintext — decrypt() MUST run before computeTag() to correctly advance the Poly1305 accumulator. On MAC success: ACK sent, s_sessionNonce zeroed (key erasure), parser reset. On MAC failure: NACK sent, session left active for FIN retransmission.

Parameters
pktPointer to the fully buffered DataPacket (flags == FLAG_FIN).

Definition at line 416 of file ReceiverNode.ino.

References ACK_BYTE, DATA_PAYLOAD_SIZE, FLAG_FIN, HELLO_NONCE_SIZE, lcd(), DataPacket::mac, MASTER_PSK, NACK_BYTE, DataPacket::payload, resetParser(), s_cipher, s_sessionActive, s_sessionNonce, DataPacket::seq_num, seqNum, and TRUNCATED_MAC_SIZE.

Referenced by processReceivedByte().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ processHelloBody()

void processHelloBody ( )

Store the received session nonce and install MASTER_PSK into the cipher.

Handle a fully buffered HelloPacket (FLAG_SYN) from the Transmitter.

Copies rx_buffer[1..12] into s_sessionNonce, calls s_cipher.setKey(MASTER_PSK, 32) to pre-install the key, sets s_sessionActive = true, sends ACK_BYTE, and arms the Dynamic Smart Watchdog with current_timeout_limit = 5000 ms.

Definition at line 290 of file ReceiverNode.ino.

References ACK_BYTE, current_timeout_limit, HELLO_NONCE_SIZE, last_valid_packet_time, MASTER_PSK, rx_buffer, s_cipher, s_sessionActive, and s_sessionNonce.

Referenced by processReceivedByte().

+ Here is the caller graph for this function:

◆ processReceivedByte()

void processReceivedByte ( uint8_t  inByte)

Consume one incoming UART byte and advance the frame-assembly FSM.

Implements the WAIT_AA -> WAIT_55 -> READ_TYPE -> READ_PAYLOAD pipeline. Both HELLO and DATA frames must pass the 0xAA 0x55 preamble gate. On buffer completion, dispatches to processHelloBody(), authenticateAndPlay(), or processFinPacket() as appropriate, then returns to WAIT_AA.

Parameters
inByteByte just read from the UART hardware buffer.

Definition at line 188 of file ReceiverNode.ino.

References authenticateAndPlay(), currentState, expected_length, FLAG_DAT, FLAG_FIN, FLAG_SYN, NACK_BYTE, parseState, processFinPacket(), processHelloBody(), READ_PAYLOAD, READ_TYPE, READING_DATA, READING_HELLO, resetParser(), rx_buffer, rx_index, s_sessionActive, SYNC_BYTE_1, SYNC_BYTE_2, updateRxDisplay(), WAIT_55, WAIT_AA, and WAITING_SYNC_1.

Referenced by rx_loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ resetParser()

static void resetParser ( )
static

Flush the UART RX FIFO and reset the byte-parser FSM to WAIT_AA.

Called on MAC failure or parser timeout to prevent a noise burst that corrupted one frame from also corrupting the preamble detection of the next frame. Reads and discards all bytes in the 64-byte hardware FIFO (Serial.flush() only flushes TX; manual drain is required for RX).

Definition at line 170 of file ReceiverNode.ino.

References currentState, parseState, rx_index, WAIT_AA, and WAITING_SYNC_1.

Referenced by authenticateAndPlay(), processFinPacket(), processReceivedByte(), and rx_loop().

+ Here is the caller graph for this function:

◆ rx_loop()

void rx_loop ( )

Execute one non-blocking C2P-ARQ FSM tick for the Receiver node.

Handles the MAC-error display timer, note-duration timer, Dynamic Smart Watchdog tear-down, non-blocking UART byte reading, and parser timeout. At most one FSM transition per invocation; no delay() calls.

Definition at line 672 of file ReceiverNode.ino.

References CHK_ERR_DISPLAY_MS, current_timeout_limit, currentState, errorDisplayStart, EXECUTING_ACTION, HELLO_NONCE_SIZE, isPlayingNote, isShowingError, last_valid_packet_time, lcd(), noteLengthMs, noteStartMs, parseState, processReceivedByte(), resetParser(), rx_index, RX_PARSER_TIMEOUT_MS, rxLastByteMs, s_sessionActive, s_sessionNonce, stopNote(), updateRxDisplay(), WAIT_AA, and WAITING_SYNC_1.

Referenced by loop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rx_setup()

void rx_setup ( )

Initialise RX hardware, seed the CSPRNG, and display the idle screen.

Initialise RX hardware and seed the CSPRNG. Called once from setup().

Configures UART @ 9600 bps, buzzer pin, I2C LCD, and byte-parser FSM. Harvests 256-bit hardware entropy (~16 ms) and seeds the ChaCha20 CSPRNG. The entropy buffer is scrubbed from the stack immediately after use.

Definition at line 615 of file ReceiverNode.ino.

References BAUD_RATE, currentState, generateEntropyPool(), initCSPRNG(), lcd(), parseState, RX_BUZZER_PIN, rx_index, updateRxDisplay(), WAIT_AA, and WAITING_SYNC_1.

Referenced by setup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ setup()

void setup ( )

Arduino entry point — delegates to rx_setup().

Definition at line 720 of file ReceiverNode.ino.

References rx_setup().

+ Here is the call graph for this function:

◆ startNote()

void startNote ( uint16_t  frequencyHz,
uint16_t  durationMs 
)

Start non-blocking note playback on the piezo buzzer.

Start a non-blocking note playback on the piezo buzzer.

Calls tone(RX_BUZZER_PIN, frequencyHz), records noteStartMs = millis(), and sets isPlayingNote = true. rx_loop() will call stopNote() when (millis() - noteStartMs) >= noteLengthMs. For frequencyHz == 0 (REST), no tone is started and isPlayingNote is still set to handle timing.

Parameters
frequencyHzFrequency in Hz to pass to tone(); 0 = silence.
durationMsDuration in milliseconds to hold the note before calling noTone().

Definition at line 494 of file ReceiverNode.ino.

References isPlayingNote, noteLengthMs, noteStartMs, and RX_BUZZER_PIN.

Referenced by authenticateAndPlay().

+ Here is the caller graph for this function:

◆ stopNote()

void stopNote ( )

Stop the currently playing note and clear the playback flag.

Stop the currently playing note by calling noTone().

Calls noTone(RX_BUZZER_PIN) and sets isPlayingNote = false. Called by rx_loop() when (millis() - noteStartMs) >= noteLengthMs.

Definition at line 506 of file ReceiverNode.ino.

References isPlayingNote, and RX_BUZZER_PIN.

Referenced by authenticateAndPlay(), and rx_loop().

+ Here is the caller graph for this function:

◆ updateRxDisplay()

void updateRxDisplay ( RxState  state,
uint16_t  seqNum,
bool  macOk 
)

Refresh the RX LCD with the current FSM state and last packet result.

Row 0 shows a human-readable RxState label; Row 1 shows SEQ: <seqNum> OK or SEQ: <seqNum> MAC! depending on macOk.

Parameters
stateCurrent RxState to display on LCD row 0.
seqNumLast received sequence number for LCD row 1.
macOktrue if MAC verification passed; false on failure.

Definition at line 138 of file ReceiverNode.ino.

References EXECUTING_ACTION, GOT_DATA, GOT_HELLO, lcd(), READING_DATA, READING_HELLO, s_sessionActive, seqNum, WAITING_FOR_TYPE, WAITING_SYNC_1, and WAITING_SYNC_2.

Referenced by authenticateAndPlay(), processReceivedByte(), rx_loop(), and rx_setup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ CHK_ERR_DISPLAY_MS

const uint16_t CHK_ERR_DISPLAY_MS = 500

Duration of the MAC-error message shown on the LCD before returning to idle display.

Definition at line 96 of file ReceiverNode.ino.

Referenced by rx_loop().

◆ current_timeout_limit

uint32_t current_timeout_limit = 5000
static

Current Dynamic Watchdog timeout in milliseconds.

Updated after every authenticated DataPacket to (last note duration + NETWORK_GRACE_PERIOD_MS). Default 5000 ms until the first DATA packet establishes a note duration.

Definition at line 123 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), processHelloBody(), and rx_loop().

◆ currentState

RxState currentState = RxState::WAITING_SYNC_1
static

Tracks the current RxState for LCD display updates; independent of the byte-parser FSM.

Definition at line 128 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), processReceivedByte(), resetParser(), rx_loop(), and rx_setup().

◆ errorDisplayStart

uint32_t errorDisplayStart = 0
static

Timestamp (millis()) when the MAC-error display was last activated.

Definition at line 100 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), and rx_loop().

◆ expected_length

uint8_t expected_length = 0
static

Total expected bytes for the current frame; set in READ_TYPE state.

Definition at line 78 of file ReceiverNode.ino.

Referenced by processReceivedByte().

◆ isPlayingNote

bool isPlayingNote = false
static

True while a note is actively sounding; cleared by stopNote().

Definition at line 93 of file ReceiverNode.ino.

Referenced by rx_loop(), startNote(), and stopNote().

◆ isShowingError

bool isShowingError = false
static

True when the LCD is currently showing a MAC-error message.

Definition at line 98 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), and rx_loop().

◆ last_valid_packet_time

uint32_t last_valid_packet_time = 0
static

Timestamp (millis()) of the most recently successfully authenticated DataPacket.

Definition at line 125 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), processHelloBody(), and rx_loop().

◆ NETWORK_GRACE_PERIOD_MS

const uint32_t NETWORK_GRACE_PERIOD_MS = 3000

Network grace period added to the last note's duration for the Dynamic Smart Watchdog.

Absorbs the worst-case TX retry storm: MAX_RETRIES × ACK_TIMEOUT_MS = 50 × 50 ms = 2500 ms. Value 3000 ms provides 500 ms margin above that maximum.

Definition at line 116 of file ReceiverNode.ino.

Referenced by authenticateAndPlay().

◆ noteLengthMs

uint16_t noteLengthMs = 0
static

Duration in milliseconds that the current note should sound.

Definition at line 91 of file ReceiverNode.ino.

Referenced by rx_loop(), and startNote().

◆ noteStartMs

uint32_t noteStartMs = 0
static

Timestamp (millis()) when the current note started playing.

Definition at line 89 of file ReceiverNode.ino.

Referenced by rx_loop(), and startNote().

◆ parseState

ParseState parseState = WAIT_AA
static

Current byte-parser FSM state; reset to WAIT_AA by resetParser().

Definition at line 67 of file ReceiverNode.ino.

Referenced by processReceivedByte(), resetParser(), rx_loop(), and rx_setup().

◆ rx_buffer

uint8_t rx_buffer[sizeof(DataPacket)]
static

Raw receive buffer sized to hold the largest frame body (DataPacket, 15 bytes).

HelloPacket (13 bytes) also fits. rx_buffer[0] always holds the flags byte; casting to the appropriate struct pointer gives zero-copy struct access.

Definition at line 74 of file ReceiverNode.ino.

Referenced by processHelloBody(), and processReceivedByte().

◆ rx_index

uint8_t rx_index = 0
static

Number of bytes written to rx_buffer for the frame currently being collected.

Definition at line 76 of file ReceiverNode.ino.

Referenced by processReceivedByte(), resetParser(), rx_loop(), and rx_setup().

◆ RX_PARSER_TIMEOUT_MS

const uint16_t RX_PARSER_TIMEOUT_MS = 20

Stale byte accumulation timeout for the byte-level frame parser.

If body bytes stop arriving mid-frame for longer than this value, resetParser() is called to prevent a permanently stalled accumulator.

Definition at line 107 of file ReceiverNode.ino.

Referenced by rx_loop().

◆ rxLastByteMs

uint32_t rxLastByteMs = 0
static

Timestamp (millis()) of the most recently received UART byte.

Definition at line 109 of file ReceiverNode.ino.

Referenced by rx_loop().

◆ s_cipher

ChaChaPoly s_cipher
static

ChaCha20-Poly1305 cipher instance; re-initialised per packet via clear().

Definition at line 86 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), processFinPacket(), and processHelloBody().

◆ s_ringOscPulses

volatile uint32_t s_ringOscPulses = 0
static

Pulse counter incremented by the ring oscillator ISR on INT0 (pin 2).

Definition at line 512 of file ReceiverNode.ino.

Referenced by generateEntropyPool(), and onRingOscPulse().

◆ s_sessionActive

bool s_sessionActive = false
static

Session active flag — set after a valid HelloPacket handshake; cleared on FIN or watchdog timeout.

Definition at line 81 of file ReceiverNode.ino.

Referenced by processFinPacket(), processHelloBody(), processReceivedByte(), rx_loop(), and updateRxDisplay().

◆ s_sessionNonce

uint8_t s_sessionNonce[HELLO_NONCE_SIZE]
static

12-byte session nonce delivered by the last accepted HelloPacket (FLAG_SYN).

Definition at line 83 of file ReceiverNode.ino.

Referenced by authenticateAndPlay(), processFinPacket(), processHelloBody(), and rx_loop().

◆ universal_notes

const uint16_t universal_notes[NOTE_DICT_SIZE]
static
Initial value:
= {
262,
277,
294,
311,
330,
349,
370,
392,
415,
440,
466,
494,
523,
554,
587,
622,
659,
698,
740,
784,
831
}

Universal note frequency dictionary for the C2P-ARQ Receiver.

Maps an encoded note index (0–20) sent by Transmitter Node A to the corresponding buzzer frequency in Hz. The RX node has no knowledge of which melody is playing — it only translates index -> frequency. Index layout (chromatic scale, C4 … G#5):

0=C4 1=C#4 2=D4 3=D#4 4=E4 5=F4 6=F#4 7=G4
8=G#4 9=A4 10=A#4 11=B4 12=C5 13=C#5 14=D5 15=D#5
16=E5 17=F5 18=F#5 19=G5 20=G#5

REST_INDEX (255) means silence — handled separately in authenticateAndPlay().

Definition at line 33 of file ReceiverNode.ino.

Referenced by authenticateAndPlay().