@@ -19,9 +19,10 @@ <h1>Chords-Python Applications</h1>
19
19
< p > {{ message }}</ p >
20
20
</ div >
21
21
{% endif %}
22
-
22
+ <!-- Container for LSL and NPG stream control buttons -->
23
23
< div class ="controls-container ">
24
24
< div class ="controls ">
25
+ <!-- Button to start LSL Stream, disabled if already running or if NPG is running -->
25
26
< button id ="start_lsl_button "
26
27
class ="{% if lsl_started %}running{% else %}not-running{% endif %} "
27
28
onclick ="showCSVConfirmation() "
@@ -30,6 +31,7 @@ <h1>Chords-Python Applications</h1>
30
31
</ button >
31
32
</ div >
32
33
< div class ="controls ">
34
+ <!-- Button to start NPG Stream, disabled if already running or if LSL is running -->
33
35
< button id ="start_npg_button "
34
36
class ="{% if npg_started %}running{% else %}not-running{% endif %} "
35
37
onclick ="showNPGPopup() "
@@ -50,7 +52,7 @@ <h1>Chords-Python Applications</h1>
50
52
</ form >
51
53
</ div >
52
54
</ div >
53
-
55
+ <!-- App buttons (disabled until either one of stream is active) -->
54
56
< div class ="app-buttons {% if not (lsl_started or npg_started) %}disabled-apps{% endif %} ">
55
57
<!-- Row 1: ECG, EMG, EOG, EEG -->
56
58
< div class ="row ">
@@ -78,7 +80,7 @@ <h1>Chords-Python Applications</h1>
78
80
</ form >
79
81
</ div >
80
82
81
- <!-- Row 2: Game, GUI, Keystroke, CSVPlotter -->
83
+ <!-- Row 2: Tug of War Game,EEG Beetle Game, GUI, Keystroke, CSVPlotter -->
82
84
< div class ="row ">
83
85
< form action ="/run_app " method ="POST ">
84
86
< button type ="submit " name ="app_name " value ="game "
@@ -114,10 +116,13 @@ <h1>Chords-Python Applications</h1>
114
116
<!-- NPG Device Selection Popup -->
115
117
< div id ="npgDevicePopup ">
116
118
< h3 > Select NPG Device</ h3 >
119
+ <!-- Status message for scanning status or connection updates -->
117
120
< div id ="npgPopupStatus "> Ready to scan devices</ div >
121
+ <!-- Device list area where detected devices will be listed -->
118
122
< div id ="npgDeviceList ">
119
123
< p > Click "Scan Devices" to begin</ p >
120
124
</ div >
125
+ <!-- Buttons for scanning, connecting, or canceling the device selection -->
121
126
< div class ="npg-popup-buttons ">
122
127
< button class ="npg-popup-btn " id ="scanDevicesBtn " onclick ="scanNPGDevices() "> Scan Devices</ button >
123
128
< button class ="npg-popup-btn npg-connect-btn " id ="npgConnectBtn " disabled onclick ="connectToDevice() "> Connect</ button >
@@ -126,10 +131,11 @@ <h3>Select NPG Device</h3>
126
131
</ div >
127
132
128
133
< script >
129
- let selectedDevice = null ;
130
- let connectionCheckInterval = null ;
131
- let eventSource ;
134
+ let selectedDevice = null ; // Store the selected device address
135
+ let connectionCheckInterval = null ; // Used to repeatedly check connection status
136
+ let eventSource ; // EventSource for server-sent events for real-time updates
132
137
138
+ // Function to display the NPG device selection popup
133
139
function showNPGPopup ( ) {
134
140
document . getElementById ( 'npgDevicePopup' ) . style . display = 'block' ;
135
141
document . getElementById ( 'csvConfirmationPopup' ) . style . display = 'none' ;
@@ -139,6 +145,7 @@ <h3>Select NPG Device</h3>
139
145
selectedDevice = null ;
140
146
}
141
147
148
+ // Function to hide the NPG popup and stop connection checks
142
149
function hideNPGPopup ( ) {
143
150
document . getElementById ( 'npgDevicePopup' ) . style . display = 'none' ;
144
151
if ( connectionCheckInterval ) {
@@ -147,11 +154,13 @@ <h3>Select NPG Device</h3>
147
154
}
148
155
}
149
156
157
+ // Function to fetch and list available NPG devices from backend
150
158
async function scanNPGDevices ( ) {
151
159
const statusDiv = document . getElementById ( 'npgPopupStatus' ) ;
152
160
const deviceList = document . getElementById ( 'npgDeviceList' ) ;
153
161
const scanBtn = document . getElementById ( 'scanDevicesBtn' ) ;
154
162
163
+ // Show scanning status and disable scan button
155
164
scanBtn . disabled = true ;
156
165
statusDiv . textContent = 'Scanning for devices...' ;
157
166
statusDiv . className = 'scanning-status' ;
@@ -161,15 +170,18 @@ <h3>Select NPG Device</h3>
161
170
const response = await fetch ( '/scan_devices' , { method : 'POST' } ) ;
162
171
const data = await response . json ( ) ;
163
172
173
+ // If devices are found
164
174
if ( data . status === 'success' && data . devices . length > 0 ) {
165
175
deviceList . innerHTML = '' ;
166
176
177
+ // Display each device to UI and make them selectable
167
178
data . devices . forEach ( device => {
168
179
const div = document . createElement ( 'div' ) ;
169
180
div . className = 'npg-device-item' ;
170
181
div . textContent = `${ device . name || 'Unknown' } (${ device . address } )` ;
171
182
div . dataset . address = device . address ;
172
183
184
+ // Add click event to highlight selected device
173
185
div . addEventListener ( 'click' , ( ) => {
174
186
document . querySelectorAll ( '.npg-device-item' ) . forEach ( item => {
175
187
item . classList . remove ( 'selected' ) ;
@@ -189,23 +201,25 @@ <h3>Select NPG Device</h3>
189
201
statusDiv . textContent = data . message || 'No devices found' ;
190
202
statusDiv . className = 'error-status' ;
191
203
}
192
- } catch ( error ) {
204
+ } catch ( error ) { // Handle scan error
193
205
console . error ( 'Scan error:' , error ) ;
194
206
deviceList . innerHTML = '<p>Scan failed</p>' ;
195
207
statusDiv . textContent = 'Scan failed - please try again' ;
196
208
statusDiv . className = 'error-status' ;
197
209
} finally {
198
- scanBtn . disabled = false ;
210
+ scanBtn . disabled = false ; // Re-enable scan button
199
211
}
200
212
}
201
213
214
+ // Function to connect to the selected NPG device
202
215
async function connectToDevice ( ) {
203
216
if ( ! selectedDevice ) return ;
204
217
205
218
const statusDiv = document . getElementById ( 'npgPopupStatus' ) ;
206
219
const connectBtn = document . getElementById ( 'npgConnectBtn' ) ;
207
220
const scanBtn = document . getElementById ( 'scanDevicesBtn' ) ;
208
221
222
+ // Show connecting state
209
223
connectBtn . disabled = true ;
210
224
scanBtn . disabled = true ;
211
225
statusDiv . textContent = 'Connecting to device...' ;
@@ -222,17 +236,20 @@ <h3>Select NPG Device</h3>
222
236
223
237
const data = await response . json ( ) ;
224
238
239
+ // If connection is pending, start checking status
225
240
if ( data . status === 'pending' ) {
226
241
const checkStatus = async ( ) => {
227
242
const statusResponse = await fetch ( '/check_connection' ) ;
228
243
const statusData = await statusResponse . json ( ) ;
229
244
245
+ // Log connection status for debugging
230
246
console . log ( "Connection status:" , statusData ) ;
247
+ // Check if connected or if there was an error
231
248
if ( statusData . connected ) {
232
249
clearInterval ( connectionCheckInterval ) ;
233
250
statusDiv . textContent = statusData . message ;
234
251
statusDiv . className = 'connected-status' ;
235
- setTimeout ( ( ) => {
252
+ setTimeout ( ( ) => { // Hide popup after 1 second
236
253
hideNPGPopup ( ) ;
237
254
window . location . reload ( ) ; // Force refresh to sync state
238
255
} , 1000 ) ;
@@ -265,21 +282,24 @@ <h3>Select NPG Device</h3>
265
282
}
266
283
}
267
284
285
+ // Function to show the CSV confirmation popup when the LSL button is clicked
268
286
function showCSVConfirmation ( ) {
269
287
document . getElementById ( 'csvConfirmationPopup' ) . style . display = 'block' ;
270
288
document . getElementById ( 'npgDevicePopup' ) . style . display = 'none' ;
271
289
}
272
290
291
+ // Function to set the CSV choice and submit the form. This is called when the user clicks YES or NO in the CSV Popup.
273
292
function setCSVChoice ( saveAsCSV ) {
274
293
document . getElementById ( 'csvInput' ) . value = saveAsCSV ? 'true' : 'false' ;
275
294
document . getElementById ( 'csvForm' ) . submit ( ) ;
276
295
document . getElementById ( 'csvConfirmationPopup' ) . style . display = 'none' ;
277
296
}
278
297
298
+ // Function to update the state of app buttons based on running applications. This function is called when the server sends updates about running applications.
279
299
function updateAppButtons ( runningApps ) {
280
300
// Get all app buttons
281
301
const appButtons = document . querySelectorAll ( '.app-buttons button[type="submit"]' ) ;
282
-
302
+ // Loop through each button and check if the corresponding app is running
283
303
appButtons . forEach ( button => {
284
304
const appName = button . value ;
285
305
const isRunning = runningApps . includes ( appName ) ;
@@ -296,6 +316,7 @@ <h3>Select NPG Device</h3>
296
316
} ) ;
297
317
}
298
318
319
+ // Function to set up the EventSource for receiving real-time updates from the server. This function is called when the page loads and whenever the connection is re-established.
299
320
function setupEventSource ( ) {
300
321
if ( eventSource ) eventSource . close ( ) ;
301
322
@@ -364,13 +385,13 @@ <h3>Select NPG Device</h3>
364
385
}
365
386
366
387
document . addEventListener ( 'DOMContentLoaded' , function ( ) {
367
- setupEventSource ( ) ;
388
+ setupEventSource ( ) ; // Initialize the SSE connection to receive real-time updates from the server
368
389
369
- // Initial state setup
390
+ // Fetch the current status of running applications when the page loads
370
391
fetch ( '/check_app_status' )
371
- . then ( response => response . json ( ) )
392
+ . then ( response => response . json ( ) ) // Parse the JSON response from the server
372
393
. then ( data => {
373
- if ( data . running_apps ) {
394
+ if ( data . running_apps ) { // If there are running applications, update the UI to show their current state
374
395
updateAppButtons ( data . running_apps ) ;
375
396
}
376
397
} ) ;
0 commit comments