()
| 1719 | btn.title = det.available |
| 1720 | ? `HackRF ready${det.board ? ' (' + det.board + ')' : ''} — true-RF waterfall` |
| 1721 | : (det.error || 'Connect a HackRF SDR to enable true-RF waterfall'); |
| 1722 | _wifiFsSyncGates(); |
| 1723 | }).catch(() => {}); |
| 1724 | } |
| 1725 | |
| 1726 | function _wifiSdrStart() { |
| 1727 | const s = _wifiState.sdr; |
| 1728 | if (!s.available) { _wifiDrawWaterfall(); return; } |
| 1729 | s.rows = []; s.seq = 0; s.maxhold = null; s.error = null; |
| 1730 | // Match the SDR band to the analyzer's band selector where it's a real RF |
| 1731 | // band (2.4/5); 'all'/'6' fall back to 2.4. |
| 1732 | s.band = (_wifiState.band === '5') ? '5' : '2.4'; |
| 1733 | fetch('/api/net/sdr/start', { method: 'POST', headers: { 'Content-Type': 'application/json' }, |
| 1734 | body: JSON.stringify({ band: s.band }) }) |
| 1735 | .then(r => r.json()).then(res => { |
| 1736 | if (res && res.error) { s.error = res.error; _wifiDrawWaterfall(); return; } |
| 1737 | if (s.poll) clearInterval(s.poll); |
| 1738 | s.running = true; |
| 1739 | s.poll = setInterval(_wifiSdrPoll, 400); |
| 1740 | }).catch(() => { s.error = 'Failed to start SDR'; _wifiDrawWaterfall(); }); |
| 1741 | } |
| 1742 | |
| 1743 | function _wifiSdrStop() { |
| 1744 | const s = _wifiState.sdr; |
| 1745 | if (s.poll) { clearInterval(s.poll); s.poll = null; } |
| 1746 | s.running = false; |
| 1747 | fetch('/api/net/sdr/stop', { method: 'POST' }).catch(() => {}); |
| 1748 | } |
| 1749 | |
| 1750 | function _wifiSdrPoll() { |
| 1751 | const s = _wifiState.sdr; |
| 1752 | fetch('/api/net/sdr/frames?since=' + s.seq).then(r => r.json()).then(d => { |
| 1753 | if (d.error) s.error = d.error; |
| 1754 | if (d.band_mhz) s.bandMhz = d.band_mhz; |
| 1755 | if (typeof d.floor_dbm === 'number') s.floor = d.floor_dbm; |
| 1756 | if (d.max_hold) s.maxhold = d.max_hold; |
| 1757 | (d.frames || []).forEach(f => { s.seq = f.seq; s.rows.unshift(f.power); }); |
| 1758 | if (s.rows.length > 260) s.rows.length = 260; |
| 1759 | if (_wifiState.view === 'waterfall') _wifiDrawWaterfall(); |
| 1760 | }).catch(() => {}); |
| 1761 | } |
| 1762 |
nothing calls this directly
no test coverage detected