1/* Sample messages only. No audio decoder, network, or persistent log. */ 2(() => { 3 "use strict"; 4 const stations = [ 5 ["K1JT", "FN31", 356, -15], ["W3LPL", "FN20", 822, -8], 6 ["VE3EJ", "EN82", 1076, -4], ["G4ABC", "IO91", 1456, -12], 7 ["JA1ABC", "PM95", 1860, -20], ["VK2ABC", "QF56", 2226, -17], 8 ["N6RV", "DM03", 2336, -7], ["PY2AA", "GG66", 2856, -14] 9 ]; 10 class DemoDecoder { 11 constructor() { this.history = []; this.roster = new Map(); this.lastSlot = null; this.cycles = 0; this.mode = "FT8"; } 12 advance(seconds, home = {}) { 13 const mode = window.dccDemoStation?.mode || "FT8"; 14 const period = window.dccDemoStation?.period || 15; 15 const ready = window.dccDemoStation?.rxReady || 13.2; 16 if (this.mode !== mode) { this.mode = mode; this.history = []; this.roster.clear(); this.lastSlot = null; this.cycles = 0; } 17 const slot = Math.floor((seconds - ready) / period); 18 if (slot === this.lastSlot) return null; 19 this.lastSlot = slot; 20 this.cycles++; 21 const utc = new Date(slot * period * 1000).toISOString().slice(11, 19).replaceAll(":", ""); 22 const latest = stations.flatMap(([call, grid, audio_hz, base], index) => { 23 if (home.receiving === false) return []; 24 if ((slot % 2 + 2) % 2 !== index % 2) return []; 25 const phase = ((Math.floor(slot / 2) + index) % 4 + 4) % 4; 26 const db = base + ((slot + index) % 5 + 5) % 5 - 2; 27 const messages = mode === "WSPR" ? Array(4).fill(`${call} ${grid} ${index % 2 ? 30 : 37}`) : ["JS8", "PSK31", "RTTY"].includes(mode) 28 ? [`CQ CQ DE ${call} ${call} ${grid} K`, `${call}: HELLO FROM ${grid}`, `${call}: RST 599 THANKS FOR THE CALL`, `${call}: GOOD DX 73`] 29 : [`CQ ${call} ${grid}`, `W1ABC ${call} -08`, `W1ABC ${call} R-10`, `W1ABC ${call} RR73`]; 30 const row = {call, grid, audio_hz: mode === "WSPR" ? 1410 + index*8 : audio_hz, db, dt: (index % 3 - 1) / 10, 31 utc, message: messages[phase], is_cq: mode !== "WSPR" && phase === 0, status: mode === "WSPR" ? "Beacon" : phase === 0 ? "CQ" : "QSO", 32 mode, period_seconds: period, period_index: slot, worked: false, received_at: slot * period + ready}; 33 this.roster.set(call, row); 34 return [row]; 35 }); 36 this.history = [...latest, ...this.history].slice(0, 80); 37 return {decodes: this.history, latest_cycle: latest, 38 roster: [...this.roster.values()].map(row => ({...row, 39 seen_seconds: Math.max(0, seconds - row.received_at), 40 seen: seconds - row.received_at < period ? "Now" : `${period} sec`})), 41 status: {demo: true, mode, period_seconds: period, enabled: true, cycles_completed: this.cycles, 42 last_message_count: latest.length, station_call: home.call || "N0CALL", station_grid: home.grid || "FN31"}}; 43 } 44 } 45 window.DccDemoDecoder = DemoDecoder; 46})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.