From 42e6a93f6b8659eff56a42fe3b909b8047024dd5 Mon Sep 17 00:00:00 2001 From: Jake Date: Mon, 29 Sep 2025 23:04:45 +0800 Subject: [PATCH] sync option implemented, motors move with dials and timeline shifts --- index.html | 91 ++++++++++++++++++++++++++-------------------------- script.js | 93 ++++++++++++++++++++++++++++++++++++++++++++++++------ serial.js | 10 ++++++ todo.md | 3 ++ 4 files changed, 142 insertions(+), 55 deletions(-) create mode 100644 todo.md diff --git a/index.html b/index.html index cb65e91..c9d463f 100644 --- a/index.html +++ b/index.html @@ -13,61 +13,62 @@ -
Status: Disconnected + + - - -
-
-
512 -
-
-
512 -
-
-
512 -
-
-
512 -
-
-
512 -
-
- - - - -
-
- -
- - - - - -
-
- Animations -
- - +
+
+
512 +
+
+
512 +
+
+
512 +
+
+
512 +
+
+
512
-
    -
    + + + + +
    +
    + +
    + + + + + +
    +
    + Animations +
    + + +
    +
    +
      +
      -
      - - +
      + + - + diff --git a/script.js b/script.js index 4e10253..a3f374d 100644 --- a/script.js +++ b/script.js @@ -6,6 +6,11 @@ window.onload = () => { const statusText = document.getElementById('statusText'); const disconnectBtn = document.getElementById('disconnect'); const connectBtn = document.getElementById('connect'); + const syncCheckbox = document.getElementById("syncCheckbox"); + + // Limits rate of move commands sent while sliding timeslider + let lastSyncTime = 0; // global or outer-scope variable + const syncIntervalMs = 20; // e.g. 100ms = max 10 times per second let isInterpolating = false; let currentFrame = 0; @@ -81,9 +86,8 @@ window.onload = () => { deleteButton.addEventListener('click', () => { if (selectedFile) { console.log(`Deleting file: ${selectedFile}`); - // Add logic to send delete command to ESP32 + sendDeleteToESP32(); - // Remove from UI const selectedLi = fileListElement.querySelector('.selected'); if (selectedLi) selectedLi.remove(); selectedFile = null; @@ -98,6 +102,7 @@ window.onload = () => { + // Timeline frameSlider.oninput = () => { @@ -142,6 +147,11 @@ window.onload = () => { drawTimelineMarkers(); isInterpolating = false; + + + syncMotorsWithTimeline(); + + }; for (let i = 0; i < 5; i++) { @@ -160,8 +170,42 @@ window.onload = () => { document.getElementById(`value${i}`).textContent = val; dialKeyframes[i][currentFrame] = val; drawTimelineMarkers(); + + + syncMotorsWithTimeline(); + }); + + } + + function syncMotorsWithTimeline() { + const now = Date.now(); + if (syncCheckbox.checked && now - lastSyncTime >= syncIntervalMs) { + lastSyncTime = now; + + const motorPayloads = []; + + for (let ch = 0; ch < dials.length; ch++) { + const value = dials[ch].value; + motorPayloads.push({ motorId: ch, position: value }); + } + + const buffer = new ArrayBuffer(motorPayloads.length * 3); + const view = new DataView(buffer); + + motorPayloads.forEach(({ motorId, position }, i) => { + const offset = i * 3; + view.setUint8(offset, motorId); + view.setUint16(offset + 1, position, true); // little-endian + }); + + const payload = new Uint8Array(buffer); + serial.sendSetPositions(payload); + } + } + + document.querySelectorAll('.dial').forEach(el => { el.onclick = () => { selectedDial = parseInt(el.dataset.index); @@ -208,6 +252,14 @@ window.onload = () => { // 🔹 Do something with the file handleLoadedFile(fileData); break; + + case 0x04: // CMD_DELETE_FILE + console.log(`File deleted`); + console.log(new Uint8Array(payload)); + document.getElementById('log').value += `File deleted\n`; + // 🔹 Do something with the file + //handleLoadedFile(fileData); + break; case 0x05: // CMD_SAVE_FILE console.log(`Saved file Response Recieved`); @@ -228,6 +280,14 @@ window.onload = () => { // 🔹 Do something with the file //handleLoadedFile(fileData); break; + + case 0x07: // CMD_SET_POSITION + console.log(`Positions set`); + console.log(new Uint8Array(payload)); + document.getElementById('log').value += `Positions set\n`; + // 🔹 Do something with the file + //handleLoadedFile(fileData); + break; // Add more cases as needed default: document.getElementById('log').value += `Unknown command ${command}\n`; @@ -419,6 +479,27 @@ window.onload = () => { serial.saveFile(payload); // CMD_SAVE_ANIMATION } + async function sendDeleteToESP32() { + if (!selectedFile) return; + + const filename = selectedFile; + console.log("Sanitized filename for delete:", filename); + + const filenameBytes = new TextEncoder().encode(filename); + const filenameLength = filenameBytes.length; + + // Total size: 2 bytes for length + filename bytes + const buffer = new ArrayBuffer(2 + filenameLength); + const view = new DataView(buffer); + let offset = 0; + + // 🔹 Filename block + view.setUint16(offset, filenameLength, true); offset += 2; + filenameBytes.forEach(byte => view.setUint8(offset++, byte)); + + const payload = new Uint8Array(buffer); + serial.deleteFile(payload); // CMD_DELETE_FILE + } // Disconnect button @@ -439,14 +520,6 @@ window.onload = () => { document.getElementById('input').value = ''; }; - document.getElementById('sendFrame').onclick = async () => { - // const positions = dials.map(d => Math.round(d.value)); - // const message = `FRAME ${positions.join(',')}\n`; - // const encoder = new TextEncoder(); - // await writer.write(encoder.encode(message)); - console.log(dialKeyframes); - }; - function drawTimelineMarkers() { ctx.clearRect(0, 0, canvas.width, canvas.height); const width = canvas.width; diff --git a/serial.js b/serial.js index 0f080e3..f9974ca 100644 --- a/serial.js +++ b/serial.js @@ -9,6 +9,7 @@ const CMD_FILE_LIST = 0x02; const CMD_LOAD_FILE = 0x03; const CMD_SAVE_FILE = 0x05; const CMD_DELETE_FILE = 0x04; +const CMD_SET_POSITION = 0x07; export class SerialManager { constructor() { @@ -62,6 +63,15 @@ export class SerialManager { await this.send(CMD_SAVE_FILE, payload); } + async deleteFile(payload) { + console.log("Deleting File: " + "filename"); + await this.send(CMD_DELETE_FILE, payload); + } + + async sendSetPositions(payload){ + console.log("Setting positions"); + await this.send(CMD_SET_POSITION, payload); + } startReading(onPacket) { const decoder = new TextDecoder(); diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..5cdd049 --- /dev/null +++ b/todo.md @@ -0,0 +1,3 @@ +Add play animation command +play combined animations +play combined animations with masks \ No newline at end of file