|
| 1 | +flowchart TD |
| 2 | + subgraph INIT["🔌 ON CONNECT"] |
| 3 | + A[BLE Connection Established] --> B[Start Unified RX Listening<br/>Register LogRxData handler] |
| 4 | + B --> B2[Initialize rxBatchBuffer Map<br/>Empty - ready for tracking] |
| 5 | + end |
| 6 | + |
| 7 | + subgraph RECEIVE["📻 RECEIVE FROM MESH"] |
| 8 | + C[/"Radio receives packet<br/>from repeater"/] --> D[/"BLE pushes LogRxData event<br/>{lastSnr, lastRssi, raw}"/] |
| 9 | + end |
| 10 | + |
| 11 | + subgraph UNIFIED["🔀 UNIFIED RX HANDLER"] |
| 12 | + D --> E{Header = 0x15? <br/>GroupText} |
| 13 | + E -->|NO| E_IGNORE[/"🚫 IGNORE"/] |
| 14 | + E -->|YES| F{Payload ≥ 3 bytes?} |
| 15 | + F -->|NO| F_IGNORE[/"🚫 IGNORE"/] |
| 16 | + F -->|YES| G{Session Log<br/>Tracking Active? <br/>10s window after TX} |
| 17 | + end |
| 18 | + |
| 19 | + subgraph SESSION_LOG["📋 SESSION LOG TRACKING (Echo Detection)"] |
| 20 | + G -->|YES| H[Delegate to Session Log Handler] |
| 21 | + H --> I{Channel hash<br/>matches? } |
| 22 | + I -->|NO| I_PASS[Pass to Passive RX] |
| 23 | + I -->|YES| J[Decrypt message content] |
| 24 | + J --> K{Message matches<br/>our sent ping?} |
| 25 | + K -->|NO| K_PASS[Pass to Passive RX] |
| 26 | + K -->|YES| L{Path length > 0?} |
| 27 | + L -->|NO| L_IGNORE[/"🚫 Direct TX, not echo"/] |
| 28 | + L -->|YES| M["✅ ECHO DETECTED! <br/>Extract FIRST hop repeater ID"] |
| 29 | + M --> N[Track in repeaters Map<br/>Update SNR if better<br/>Update UI chips live] |
| 30 | + N --> O[/"Done - wait for next event"/] |
| 31 | + end |
| 32 | + |
| 33 | + subgraph PASSIVE["👁️ PASSIVE RX PROCESSING"] |
| 34 | + G -->|NO| P[Passive RX Processing] |
| 35 | + I_PASS --> P |
| 36 | + K_PASS --> P |
| 37 | + P --> Q{Path length > 0? } |
| 38 | + Q -->|NO| Q_IGNORE[/"🚫 Direct TX, skip"/] |
| 39 | + Q -->|YES| R["Extract LAST hop<br/>(direct repeater) e.g., '92'"] |
| 40 | + R --> S{GPS fix<br/>available?} |
| 41 | + S -->|NO| S_SKIP[/"⚠️ Skip entry"/] |
| 42 | + S -->|YES| T["📝 ADD TO RX LOG UI<br/>{repeaterId, snr, lat, lon, timestamp}"] |
| 43 | + T --> U[Update RX Log UI<br/>Summary bar + entry chips] |
| 44 | + end |
| 45 | + |
| 46 | + subgraph BATCH_TRACK["📦 BATCH TRACKING FOR API"] |
| 47 | + U --> V{Batch exists for<br/>this repeater?} |
| 48 | + |
| 49 | + V -->|NO| W["🆕 CREATE NEW BATCH<br/>{<br/> firstLocation: {lat, lng}<br/> firstTimestamp: now()<br/> samples: []<br/> timeoutId: null<br/>}"] |
| 50 | + W --> X["⏰ Set 30s timeout<br/>for this repeater"] |
| 51 | + X --> Y[Store in rxBatchBuffer] |
| 52 | + |
| 53 | + V -->|YES| Z[Get existing batch] |
| 54 | + |
| 55 | + Y --> AA["➕ ADD SAMPLE<br/>{snr, location, timestamp}"] |
| 56 | + Z --> AA |
| 57 | + |
| 58 | + AA --> BB["📏 Calculate distance from<br/>firstLocation to current"] |
| 59 | + BB --> CC{Distance ≥ 25m?} |
| 60 | + CC -->|NO| DD[/"Continue collecting<br/>Wait for next event"/] |
| 61 | + end |
| 62 | + |
| 63 | + subgraph FLUSH_DIST["🔔 FLUSH: DISTANCE TRIGGER"] |
| 64 | + CC -->|YES| EE["Distance threshold met! "] |
| 65 | + EE --> FLUSH_START |
| 66 | + end |
| 67 | + |
| 68 | + subgraph FLUSH_TIME["🔔 FLUSH: TIMEOUT TRIGGER"] |
| 69 | + TIMEOUT[/"⏰ 30s Timer Expires"/] --> FF["Timeout for repeater"] |
| 70 | + FF --> FLUSH_START |
| 71 | + end |
| 72 | + |
| 73 | + subgraph FLUSH_END["🔔 FLUSH: SESSION END"] |
| 74 | + DISCONNECT[/"🔌 Disconnect Signal"/] --> GG["Flush ALL batches"] |
| 75 | + GG --> HH["Iterate all repeaters<br/>in rxBatchBuffer"] |
| 76 | + HH --> FLUSH_START |
| 77 | + end |
| 78 | + |
| 79 | + subgraph FLUSH_PROCESS["📤 FLUSH BATCH PROCESS"] |
| 80 | + FLUSH_START[Get batch from buffer] --> II[Clear timeout if exists] |
| 81 | + II --> JJ["📊 AGGREGATE SAMPLES<br/>━━━━━━━━━━━━━━━━━━━━<br/>snr_avg = mean(samples.snr)<br/>snr_max = max(samples.snr)<br/>snr_min = min(samples.snr)<br/>sample_count = length<br/>duration = end - start"] |
| 82 | + |
| 83 | + JJ --> KK["📦 BUILD API ENTRY<br/>━━━━━━━━━━━━━━━━━━━━<br/>{<br/> repeater_id: '92'<br/> location: firstLocation<br/> snr_avg: 10.25<br/> snr_max: 12.5<br/> snr_min: 8.0<br/> sample_count: 5<br/> timestamp_start<br/> timestamp_end<br/> trigger: 'distance'<br/>}"] |
| 84 | + |
| 85 | + KK --> LL{session_id<br/>available?} |
| 86 | + LL -->|NO| LL_WARN[/"⚠️ Cannot post: <br/>no session_id"/] |
| 87 | + LL -->|YES| MM["Build payload: <br/>{session_id, entries: [entry]}"] |
| 88 | + |
| 89 | + MM --> NN["📡 QUEUE API POST<br/>━━━━━━━━━━━━━━━━━━━━<br/>🚧 DEBUG: console.log()<br/>🚀 PROD: POST to API"] |
| 90 | + |
| 91 | + NN --> OO[Remove batch from<br/>rxBatchBuffer] |
| 92 | + LL_WARN --> OO |
| 93 | + OO --> PP[/"Batch cleared for repeater"/] |
| 94 | + end |
| 95 | + |
| 96 | + subgraph LOOP["🔄 CONTINUOUS LISTENING"] |
| 97 | + O --> WAIT[/"⏳ Wait for next rx_log event"/] |
| 98 | + DD --> WAIT |
| 99 | + PP --> WAIT |
| 100 | + E_IGNORE --> WAIT |
| 101 | + F_IGNORE --> WAIT |
| 102 | + L_IGNORE --> WAIT |
| 103 | + Q_IGNORE --> WAIT |
| 104 | + S_SKIP --> WAIT |
| 105 | + WAIT --> C |
| 106 | + end |
| 107 | + |
| 108 | + subgraph CLEANUP["🧹 ON DISCONNECT - FULL CLEANUP"] |
| 109 | + DISCONNECT --> DC1[Flush all pending batches] |
| 110 | + DC1 --> DC2[Stop unified RX listening] |
| 111 | + DC2 --> DC3[Clear RX log entries] |
| 112 | + DC3 --> DC4[Clear rxBatchBuffer] |
| 113 | + DC4 --> DC5[Cancel all pending timeouts] |
| 114 | + end |
| 115 | + |
| 116 | + B2 --> C |
| 117 | + X -.->|"30s later"| TIMEOUT |
| 118 | + |
| 119 | + style INIT fill:#e3f2fd |
| 120 | + style RECEIVE fill:#fff8e1 |
| 121 | + style UNIFIED fill:#f3e5f5 |
| 122 | + style SESSION_LOG fill:#e8f5e9 |
| 123 | + style PASSIVE fill:#fce4ec |
| 124 | + style BATCH_TRACK fill:#e0f2f1 |
| 125 | + style FLUSH_DIST fill:#ffecb3 |
| 126 | + style FLUSH_TIME fill:#ffecb3 |
| 127 | + style FLUSH_END fill:#ffcdd2 |
| 128 | + style FLUSH_PROCESS fill:#e8eaf6 |
| 129 | + style LOOP fill:#eceff1 |
| 130 | + style CLEANUP fill:#ffebee |
0 commit comments