Skip to content

Commit 280ec45

Browse files
committed
Add recording functionality
1 parent 9ed2f6d commit 280ec45

File tree

1 file changed

+189
-54
lines changed

1 file changed

+189
-54
lines changed

src/app/npg-lite/page.tsx

Lines changed: 189 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ EXGFilters.forEach((filter) => {
399399
});
400400
function processSample(dataView: DataView): void {
401401
if (dataView.byteLength !== SINGLE_SAMPLE_LEN) {
402-
console.log("Unexpected sample length: " + dataView.byteLength);
402+
// console.log("Unexpected sample length: " + dataView.byteLength);
403403
return;
404404
}
405405

@@ -409,7 +409,7 @@ EXGFilters.forEach((filter) => {
409409
const endByte = dataView.getUint8(9);
410410

411411
if (sync1 !== 0xC7 || sync2 !== 0x7C || endByte !== 0x01) {
412-
console.log(`Invalid sample header/footer: ${sync1} ${sync2} ${endByte}`);
412+
// console.log(`Invalid sample header/footer: ${sync1} ${sync2} ${endByte}`);
413413
return;
414414
}
415415

@@ -418,7 +418,7 @@ EXGFilters.forEach((filter) => {
418418
} else {
419419
const expected = (prevSampleCounter + 1) % 256;
420420
if (sampleCounter !== expected) {
421-
console.log(`Missing sample: expected ${expected}, got ${sampleCounter}`);
421+
// console.log(`Missing sample: expected ${expected}, got ${sampleCounter}`);
422422
}
423423
prevSampleCounter = sampleCounter;
424424
}
@@ -433,8 +433,30 @@ EXGFilters.forEach((filter) => {
433433
)
434434
);
435435
}
436-
437436
updatePlots(channelData, zoomRef.current);
437+
if (isRecordingRef.current) {
438+
const channeldatavalues = channelData
439+
.slice(0, canvasElementCountRef.current + 1)
440+
.map((value) => (value !== undefined ? value : null))
441+
.filter((value): value is number => value !== null); // Filter out null values
442+
// Check if recording is enabled
443+
recordingBuffers[activeBufferIndex][fillingindex.current] = channeldatavalues;
444+
445+
if (fillingindex.current >= MAX_BUFFER_SIZE - 1) {
446+
processBuffer(activeBufferIndex, canvasElementCountRef.current, selectedChannels);
447+
activeBufferIndex = (activeBufferIndex + 1) % NUM_BUFFERS;
448+
}
449+
fillingindex.current = (fillingindex.current + 1) % MAX_BUFFER_SIZE;
450+
const elapsedTime = Date.now() - recordingStartTimeRef.current;
451+
setRecordingElapsedTime((prev) => {
452+
if (endTimeRef.current !== null && elapsedTime >= endTimeRef.current) {
453+
stopRecording();
454+
return endTimeRef.current;
455+
}
456+
return elapsedTime;
457+
});
458+
459+
}
438460
channelData=[];
439461
samplesReceived++;
440462
}
@@ -443,7 +465,7 @@ channelData=[];
443465
value?: DataView;
444466
}
445467

446-
function handleNotification(event: Event): void {
468+
function handledata(event: Event): void {
447469
const target = event.target as BluetoothRemoteGATTCharacteristicExtended;
448470
if (!target.value) {
449471
console.log("Received event with no value.");
@@ -460,73 +482,186 @@ channelData=[];
460482
processSample(new DataView(value.buffer));
461483
} else {
462484
console.log("Unexpected packet length: " + value.byteLength);
485+
463486
}
464487
}
465488

466-
async function connectBLE(): Promise<void> {
489+
// async function connectBLE(): Promise<void> {
490+
// try {
491+
// setIsLoading(true);
492+
// const nav = navigator as any;
493+
// if (!nav.bluetooth) {
494+
// console.log("Web Bluetooth API is not available in this browser.");
495+
// return;
496+
// }
497+
// console.log("Requesting Bluetooth device...");
498+
// const device = await nav.bluetooth.requestDevice({
499+
// filters: [{ name: DEVICE_NAME }],
500+
// optionalServices: [SERVICE_UUID],
501+
// });
502+
503+
// console.log("Connecting to GATT Server...");
504+
// const server = await device.gatt?.connect();
505+
// if (!server) {
506+
// console.log("Failed to connect to GATT Server.");
507+
// return;
508+
// }
509+
510+
// console.log("Getting Service...");
511+
// const service = await server.getPrimaryService(SERVICE_UUID);
512+
513+
// console.log("Getting Control Characteristic...");
514+
// const controlChar = await service.getCharacteristic(CONTROL_CHAR_UUID);
515+
// console.log("Getting Data Characteristic...");
516+
// const dataChar = await service.getCharacteristic(DATA_CHAR_UUID);
517+
518+
// console.log("Sending START command...");
519+
// const encoder = new TextEncoder();
520+
// await controlChar.writeValue(encoder.encode("START"));
521+
522+
// console.log("Starting notifications...");
523+
// await dataChar.startNotifications();
524+
// dataChar.addEventListener("characteristicvaluechanged", handledata);
525+
// setIsLoading(false);
526+
// setIsConnected(true);
527+
528+
// console.log("Notifications started. Listening for data...");
529+
530+
// setInterval(() => {
531+
// console.log("Samples per second: " + samplesReceived);
532+
// samplesReceived = 0;
533+
// }, 1000);
534+
// } catch (error) {
535+
// console.log("Error: " + (error instanceof Error ? error.message : error));
536+
// }
537+
// }
538+
539+
540+
541+
// async function disconnect(): Promise<void> {
542+
// try {
543+
// if (!device) {
544+
// console.log("No connected device to disconnect.");
545+
// return;
546+
// }
547+
548+
// console.log("Stopping notifications...");
549+
// const server = device.gatt;
550+
// if (server && server.connected) {
551+
// const service = await server.getPrimaryService(SERVICE_UUID);
552+
// const dataChar = await service.getCharacteristic(DATA_CHAR_UUID);
553+
// await dataChar.stopNotifications();
554+
// dataChar.removeEventListener("characteristicvaluechanged", handledata);
555+
556+
// console.log("Disconnecting from GATT Server...");
557+
// server.disconnect();
558+
// }
559+
560+
// console.log("Bluetooth device disconnected.");
561+
// setIsConnected(false);
562+
// } catch (error) {
563+
// console.log("Error during disconnection: " + (error instanceof Error ? error.message : error));
564+
// }
565+
// }
566+
567+
568+
const connectedDeviceRef = useRef<any | null>(null); // UseRef for device tracking
569+
570+
async function connectBLE(): Promise<void> {
571+
try {
572+
setIsLoading(true);
573+
const nav = navigator as any;
574+
if (!nav.bluetooth) {
575+
console.log("Web Bluetooth API is not available in this browser.");
576+
return;
577+
}
578+
579+
console.log("Requesting Bluetooth device...");
580+
const device = await nav.bluetooth.requestDevice({
581+
filters: [{ name: DEVICE_NAME }],
582+
optionalServices: [SERVICE_UUID],
583+
});
584+
585+
console.log("Connecting to GATT Server...");
586+
const server = await device.gatt?.connect();
587+
if (!server) {
588+
console.log("Failed to connect to GATT Server.");
589+
return;
590+
}
591+
592+
console.log("Getting Service...");
593+
const service = await server.getPrimaryService(SERVICE_UUID);
594+
595+
console.log("Getting Control Characteristic...");
596+
const controlChar = await service.getCharacteristic(CONTROL_CHAR_UUID);
597+
console.log("Getting Data Characteristic...");
598+
const dataChar = await service.getCharacteristic(DATA_CHAR_UUID);
599+
600+
console.log("Sending START command...");
601+
const encoder = new TextEncoder();
602+
await controlChar.writeValue(encoder.encode("START"));
603+
604+
console.log("Starting notifications...");
605+
await dataChar.startNotifications();
606+
dataChar.addEventListener("characteristicvaluechanged", handledata);
607+
608+
// Store the device globally for later disconnection
609+
connectedDeviceRef.current = device;
610+
611+
setIsLoading(false);
612+
setIsConnected(true);
613+
614+
console.log("Notifications started. Listening for data...");
615+
616+
setInterval(() => {
617+
console.log("Samples per second: " + samplesReceived);
618+
samplesReceived = 0;
619+
}, 1000);
620+
} catch (error) {
621+
console.log("Error: " + (error instanceof Error ? error.message : error));
622+
}
623+
}
624+
async function disconnect(): Promise<void> {
467625
try {
468-
setIsLoading(true);
469-
const nav = navigator as any;
470-
if (!nav.bluetooth) {
471-
console.log("Web Bluetooth API is not available in this browser.");
626+
if (!connectedDeviceRef) {
627+
console.log("No connected device to disconnect.");
472628
return;
473629
}
474-
console.log("Requesting Bluetooth device...");
475-
const device = await nav.bluetooth.requestDevice({
476-
filters: [{ name: DEVICE_NAME }],
477-
optionalServices: [SERVICE_UUID],
478-
});
479630

480-
console.log("Connecting to GATT Server...");
481-
const server = await device.gatt?.connect();
631+
const server = connectedDeviceRef.current.gatt;
482632
if (!server) {
483-
console.log("Failed to connect to GATT Server.");
633+
console.log("No GATT server found.");
484634
return;
485635
}
486636

487-
console.log("Getting Service...");
488-
const service = await server.getPrimaryService(SERVICE_UUID);
637+
console.log("Checking connection status...");
638+
console.log("GATT Connected:", server.connected);
489639

490-
console.log("Getting Control Characteristic...");
491-
const controlChar = await service.getCharacteristic(CONTROL_CHAR_UUID);
492-
console.log("Getting Data Characteristic...");
493-
const dataChar = await service.getCharacteristic(DATA_CHAR_UUID);
640+
if (!server.connected) {
641+
console.log("Device is already disconnected.");
642+
connectedDeviceRef.current = null;
643+
setIsConnected(false);
644+
return;
645+
}
494646

495-
console.log("Sending START command...");
496-
const encoder = new TextEncoder();
497-
await controlChar.writeValue(encoder.encode("START"));
647+
console.log("Stopping notifications...");
648+
const service = await server.getPrimaryService(SERVICE_UUID);
649+
const dataChar = await service.getCharacteristic(DATA_CHAR_UUID);
650+
await dataChar.stopNotifications();
651+
dataChar.removeEventListener("characteristicvaluechanged", handledata);
498652

499-
console.log("Starting notifications...");
500-
await dataChar.startNotifications();
501-
dataChar.addEventListener("characteristicvaluechanged", handleNotification);
502-
setIsLoading(false);
503-
setIsConnected(true);
504-
505-
console.log("Notifications started. Listening for data...");
653+
console.log("Disconnecting from GATT Server...");
654+
server.disconnect(); // Disconnect the device
506655

507-
setInterval(() => {
508-
console.log("Samples per second: " + samplesReceived);
509-
samplesReceived = 0;
510-
}, 1000);
656+
console.log("Bluetooth device disconnected.");
657+
connectedDeviceRef.current = null; // Clear the global reference
658+
setIsConnected(false);
511659
} catch (error) {
512-
console.log("Error: " + (error instanceof Error ? error.message : error));
660+
console.log("Error during disconnection: " + (error instanceof Error ? error.message : error));
513661
}
514662
}
515663

516-
517-
const disconnect = () => {
518-
setManualDisconnect(true);
519-
setIsConnected(false);
520-
if (wsRef.current) {
521-
522-
wsRef.current.onclose = () => console.log("WebSocket closed by disconnect()");
523-
wsRef.current.close();
524-
wsRef.current = null;
525-
}
526-
};
527-
528-
529-
664+
530665
const workerRef = useRef<Worker | null>(null);
531666

532667
const initializeWorker = () => {
@@ -845,7 +980,7 @@ channelData=[];
845980
console.warn(`WebglPlot instance at index ${index} is undefined.`);
846981
}
847982
});
848-
console.log(data);
983+
// console.log(data);
849984
linesRef.current.forEach((line, i) => {
850985
if (!line) {
851986
console.warn(`Line at index ${i} is undefined.`);

0 commit comments

Comments
 (0)