@@ -156,7 +156,6 @@ const logScrollContainer = $("logScrollContainer");
156156const logCount = $ ( "logCount" ) ;
157157const logLastTime = $ ( "logLastTime" ) ;
158158const logLastSnr = $ ( "logLastSnr" ) ;
159- const logLastSnrChip = $ ( "logLastSnrChip" ) ;
160159const sessionLogCopyBtn = $ ( "sessionLogCopyBtn" ) ;
161160
162161// RX Log selectors
@@ -166,6 +165,7 @@ const rxLogScrollContainer = $("rxLogScrollContainer");
166165const rxLogCount = $ ( "rxLogCount" ) ;
167166const rxLogLastTime = $ ( "rxLogLastTime" ) ;
168167const rxLogLastRepeater = $ ( "rxLogLastRepeater" ) ;
168+ const rxLogSnrChip = $ ( "rxLogSnrChip" ) ;
169169const rxLogEntries = $ ( "rxLogEntries" ) ;
170170const rxLogExpandArrow = $ ( "rxLogExpandArrow" ) ;
171171const rxLogCopyBtn = $ ( "rxLogCopyBtn" ) ;
@@ -2627,10 +2627,6 @@ function updateLogSummary() {
26272627 if ( count === 0 ) {
26282628 logLastTime . textContent = 'No data' ;
26292629 logLastSnr . textContent = '—' ;
2630- // Hide SNR chip when no entries
2631- if ( logLastSnrChip ) {
2632- logLastSnrChip . classList . add ( 'hidden' ) ;
2633- }
26342630 debugLog ( '[SESSION LOG] Session log summary updated: no entries' ) ;
26352631 return ;
26362632 }
@@ -2646,25 +2642,9 @@ function updateLogSummary() {
26462642 if ( heardCount > 0 ) {
26472643 logLastSnr . textContent = heardCount === 1 ? '1 Repeat' : `${ heardCount } Repeats` ;
26482644 logLastSnr . className = 'text-xs font-mono text-slate-300' ;
2649-
2650- // Find best (highest) SNR from events using Math.max
2651- const bestSnr = Math . max ( ...lastEntry . events . map ( event => event . value ) ) ;
2652-
2653- // Update SNR chip
2654- if ( logLastSnrChip && bestSnr !== - Infinity ) {
2655- const snrClass = getSnrSeverityClass ( bestSnr ) ;
2656- logLastSnrChip . className = `chip-mini ${ snrClass } ` ;
2657- logLastSnrChip . textContent = `${ bestSnr . toFixed ( 2 ) } dB` ;
2658- logLastSnrChip . classList . remove ( 'hidden' ) ;
2659- debugLog ( `[SESSION LOG] Best SNR chip updated: ${ bestSnr . toFixed ( 2 ) } dB (${ snrClass } )` ) ;
2660- }
26612645 } else {
26622646 logLastSnr . textContent = '0 Repeats' ;
26632647 logLastSnr . className = 'text-xs font-mono text-slate-500' ;
2664- // Hide SNR chip when no repeats
2665- if ( logLastSnrChip ) {
2666- logLastSnrChip . classList . add ( 'hidden' ) ;
2667- }
26682648 }
26692649}
26702650
@@ -2735,22 +2715,11 @@ function toggleBottomSheet() {
27352715 if ( sessionLogState . isExpanded ) {
27362716 // Hide status elements, show copy button
27372717 if ( logLastSnr ) logLastSnr . classList . add ( 'hidden' ) ;
2738- if ( logLastSnrChip ) logLastSnrChip . classList . add ( 'hidden' ) ;
27392718 if ( sessionLogCopyBtn ) sessionLogCopyBtn . classList . remove ( 'hidden' ) ;
27402719 debugLog ( '[SESSION LOG] Expanded - showing copy button, hiding status' ) ;
27412720 } else {
27422721 // Show status elements, hide copy button
27432722 if ( logLastSnr ) logLastSnr . classList . remove ( 'hidden' ) ;
2744- if ( logLastSnrChip ) {
2745- // Only show SNR chip if there are repeats (it manages its own visibility)
2746- const count = sessionLogState . entries . length ;
2747- if ( count > 0 ) {
2748- const lastEntry = sessionLogState . entries [ count - 1 ] ;
2749- if ( lastEntry . events . length > 0 ) {
2750- logLastSnrChip . classList . remove ( 'hidden' ) ;
2751- }
2752- }
2753- }
27542723 if ( sessionLogCopyBtn ) sessionLogCopyBtn . classList . add ( 'hidden' ) ;
27552724 debugLog ( '[SESSION LOG] Collapsed - hiding copy button, showing status' ) ;
27562725 }
@@ -2847,6 +2816,10 @@ function updateRxLogSummary() {
28472816 if ( count === 0 ) {
28482817 rxLogLastTime . textContent = 'No data' ;
28492818 rxLogLastRepeater . textContent = '—' ;
2819+ // Hide SNR chip when no entries
2820+ if ( rxLogSnrChip ) {
2821+ rxLogSnrChip . classList . add ( 'hidden' ) ;
2822+ }
28502823 debugLog ( '[PASSIVE RX UI] Summary updated: no entries' ) ;
28512824 return ;
28522825 }
@@ -2856,6 +2829,17 @@ function updateRxLogSummary() {
28562829 rxLogLastTime . textContent = date . toLocaleTimeString ( ) ;
28572830 rxLogLastRepeater . textContent = lastEntry . repeaterId ;
28582831
2832+ // Update SNR chip
2833+ if ( rxLogSnrChip && rxLogState . entries . length > 0 ) {
2834+ const snrClass = getSnrSeverityClass ( lastEntry . snr ) ;
2835+ rxLogSnrChip . className = `chip-mini ${ snrClass } ` ;
2836+ rxLogSnrChip . textContent = `${ lastEntry . snr . toFixed ( 2 ) } dB` ;
2837+ rxLogSnrChip . classList . remove ( 'hidden' ) ;
2838+ debugLog ( `[PASSIVE RX UI] SNR chip updated: ${ lastEntry . snr . toFixed ( 2 ) } dB (${ snrClass } )` ) ;
2839+ } else if ( rxLogSnrChip ) {
2840+ rxLogSnrChip . classList . add ( 'hidden' ) ;
2841+ }
2842+
28592843 debugLog ( `[PASSIVE RX UI] Summary updated: ${ count } observations, last repeater: ${ lastEntry . repeaterId } ` ) ;
28602844}
28612845
@@ -2948,11 +2932,15 @@ function toggleRxLogBottomSheet() {
29482932 if ( rxLogState . isExpanded ) {
29492933 // Hide status, show copy button
29502934 if ( rxLogLastRepeater ) rxLogLastRepeater . classList . add ( 'hidden' ) ;
2935+ if ( rxLogSnrChip ) rxLogSnrChip . classList . add ( 'hidden' ) ;
29512936 if ( rxLogCopyBtn ) rxLogCopyBtn . classList . remove ( 'hidden' ) ;
29522937 debugLog ( '[PASSIVE RX UI] Expanded - showing copy button, hiding status' ) ;
29532938 } else {
29542939 // Show status, hide copy button
29552940 if ( rxLogLastRepeater ) rxLogLastRepeater . classList . remove ( 'hidden' ) ;
2941+ if ( rxLogSnrChip && rxLogState . entries . length > 0 ) {
2942+ rxLogSnrChip . classList . remove ( 'hidden' ) ;
2943+ }
29562944 if ( rxLogCopyBtn ) rxLogCopyBtn . classList . add ( 'hidden' ) ;
29572945 debugLog ( '[PASSIVE RX UI] Collapsed - hiding copy button, showing status' ) ;
29582946 }
@@ -3212,35 +3200,24 @@ function sessionLogToCSV() {
32123200
32133201 if ( sessionLogState . entries . length === 0 ) {
32143202 debugWarn ( '[SESSION LOG] No session log entries to export' ) ;
3215- return 'Timestamp,Latitude,Longitude\n' ;
3203+ return 'Timestamp,Latitude,Longitude,Repeats \n' ;
32163204 }
32173205
3218- // Build CSV header - dynamic based on max number of repeaters
3219- let maxRepeaters = 0 ;
3220- sessionLogState . entries . forEach ( entry => {
3221- if ( entry . events . length > maxRepeaters ) {
3222- maxRepeaters = entry . events . length ;
3223- }
3224- } ) ;
3225-
3226- let header = 'Timestamp,Latitude,Longitude' ;
3227- for ( let i = 1 ; i <= maxRepeaters ; i ++ ) {
3228- header += `,Repeater${ i } _ID,Repeater${ i } _SNR` ;
3229- }
3230- header += '\n' ;
3206+ // Fixed 4-column header
3207+ const header = 'Timestamp,Latitude,Longitude,Repeats\n' ;
32313208
32323209 // Build CSV rows
32333210 const rows = sessionLogState . entries . map ( entry => {
32343211 let row = `${ entry . timestamp } ,${ entry . lat } ,${ entry . lon } ` ;
32353212
3236- // Add repeater data
3237- entry . events . forEach ( event => {
3238- row += `, ${ event . type } , ${ event . value . toFixed ( 2 ) } ` ;
3239- } ) ;
3240-
3241- // Pad with empty cells if this entry has fewer repeaters than max
3242- const missingColumns = ( maxRepeaters - entry . events . length ) * 2 ; // 2 columns per repeater (ID, SNR)
3243- for ( let i = 0 ; i < missingColumns ; i ++ ) {
3213+ // Combine all repeater data into single Repeats column
3214+ // Format: repeaterID(snr)|repeaterID(snr)|...
3215+ if ( entry . events . length > 0 ) {
3216+ const repeats = entry . events . map ( event => {
3217+ return ` ${ event . type } ( ${ event . value . toFixed ( 2 ) } )` ;
3218+ } ) . join ( '|' ) ;
3219+ row += `, ${ repeats } ` ;
3220+ } else {
32443221 row += ',' ;
32453222 }
32463223
@@ -3254,26 +3231,25 @@ function sessionLogToCSV() {
32543231
32553232/**
32563233 * Convert RX Log to CSV format
3257- * Columns: Timestamp,SNR,RSSI,RepeaterID, PathLength,Header
3234+ * Columns: Timestamp,RepeaterID, SNR,RSSI,PathLength
32583235 * @returns {string } CSV formatted string
32593236 */
32603237function rxLogToCSV ( ) {
32613238 debugLog ( '[PASSIVE RX UI] Converting RX log to CSV format' ) ;
32623239
32633240 if ( rxLogState . entries . length === 0 ) {
32643241 debugWarn ( '[PASSIVE RX UI] No RX log entries to export' ) ;
3265- return 'Timestamp,SNR,RSSI,RepeaterID, PathLength,Header \n' ;
3242+ return 'Timestamp,RepeaterID, SNR,RSSI,PathLength\n' ;
32663243 }
32673244
3268- const header = 'Timestamp,SNR,RSSI,RepeaterID, PathLength,Header \n' ;
3245+ const header = 'Timestamp,RepeaterID, SNR,RSSI,PathLength\n' ;
32693246
32703247 const rows = rxLogState . entries . map ( entry => {
32713248 // Handle potentially missing fields from old entries
32723249 const snr = entry . snr !== undefined ? entry . snr . toFixed ( 2 ) : '' ;
32733250 const rssi = entry . rssi !== undefined ? entry . rssi : '' ;
32743251 const pathLength = entry . pathLength !== undefined ? entry . pathLength : '' ;
3275- const formattedHeader = entry . header !== undefined ? '0x' + entry . header . toString ( 16 ) . padStart ( 2 , '0' ) : '' ;
3276- return `${ entry . timestamp } ,${ snr } ,${ rssi } ,${ entry . repeaterId } ,${ pathLength } ,${ formattedHeader } ` ;
3252+ return `${ entry . timestamp } ,${ entry . repeaterId } ,${ snr } ,${ rssi } ,${ pathLength } ` ;
32773253 } ) ;
32783254
32793255 const csv = header + rows . join ( '\n' ) ;
0 commit comments