Attempt to add jerk correction
This commit is contained in:
+109
-3
@@ -11,7 +11,7 @@ const CHR = {
|
||||
|
||||
// Local shadow of the current config (kept in sync with device)
|
||||
const config = { sensitivity:600, deadZone:0.06, accelStrength:0.08, curve:0, axisFlip:0, chargeMode:1,
|
||||
tapThreshold:12, tapAction:0, tapKey:0, tapMod:0 };
|
||||
tapThreshold:12, tapAction:0, tapKey:0, tapMod:0, jerkThreshold:2000 };
|
||||
|
||||
let device=null, server=null, chars={}, userDisconnected=false;
|
||||
let currentChargeStatus=0, currentBattPct=null, currentBattVoltage=null;
|
||||
@@ -222,6 +222,9 @@ async function readConfigBlob() {
|
||||
config.tapKey = view.getUint8(17);
|
||||
config.tapMod = view.getUint8(18);
|
||||
}
|
||||
if (view.byteLength >= 24) {
|
||||
config.jerkThreshold = view.getFloat32(20, true);
|
||||
}
|
||||
applyConfigToUI();
|
||||
log(`Config loaded — sens=${config.sensitivity.toFixed(0)} dz=${config.deadZone.toFixed(3)} tapThr=${config.tapThreshold}`,'ok');
|
||||
} catch(e) { log(`Config read error: ${e.message}`,'err'); }
|
||||
@@ -238,6 +241,8 @@ function applyConfigToUI() {
|
||||
document.getElementById('flipX').checked = !!(config.axisFlip & 1);
|
||||
document.getElementById('flipY').checked = !!(config.axisFlip & 2);
|
||||
setChargeModeUI(config.chargeMode);
|
||||
document.getElementById('slJerkThreshold').value = config.jerkThreshold;
|
||||
updateDisplay('jerkThreshold', config.jerkThreshold);
|
||||
document.getElementById('slTapThreshold').value = config.tapThreshold;
|
||||
updateDisplay('tapThreshold', config.tapThreshold);
|
||||
setTapActionUI(config.tapAction);
|
||||
@@ -267,9 +272,10 @@ async function _doWriteConfigBlob() {
|
||||
| (document.getElementById('tapModShift').checked ? 0x02 : 0)
|
||||
| (document.getElementById('tapModAlt').checked ? 0x04 : 0)
|
||||
| (document.getElementById('tapModGui').checked ? 0x08 : 0);
|
||||
config.jerkThreshold = +document.getElementById('slJerkThreshold').value;
|
||||
// config.curve, config.chargeMode, config.tapAction, config.tapKey updated directly
|
||||
|
||||
const buf = new ArrayBuffer(20);
|
||||
const buf = new ArrayBuffer(24);
|
||||
const view = new DataView(buf);
|
||||
view.setFloat32(0, config.sensitivity, true);
|
||||
view.setFloat32(4, config.deadZone, true);
|
||||
@@ -282,6 +288,7 @@ async function _doWriteConfigBlob() {
|
||||
view.setUint8(17, config.tapKey);
|
||||
view.setUint8(18, config.tapMod);
|
||||
view.setUint8(19, 0);
|
||||
view.setFloat32(20, config.jerkThreshold, true);
|
||||
|
||||
try {
|
||||
await gattWrite(chars.configBlob, buf);
|
||||
@@ -440,16 +447,111 @@ function toggleAdvanced(on) {
|
||||
advancedMode = on;
|
||||
localStorage.setItem('advanced', on);
|
||||
document.getElementById('ciVoltItem').style.display = on ? '' : 'none';
|
||||
document.getElementById('debugBtn').style.display = on ? '' : 'none';
|
||||
// Switch charge-info grid between 3 and 4 columns
|
||||
document.getElementById('chargeInfo').style.gridTemplateColumns = on ? '1fr 1fr 1fr 1fr' : '1fr 1fr 1fr';
|
||||
}
|
||||
|
||||
// ── IMU Debug Recorder ────────────────────────────────────────────────────────
|
||||
let debugModalOpen = false;
|
||||
let debugRecording = false;
|
||||
let debugBuffer = [];
|
||||
const DEBUG_LIVE_ROWS = 40;
|
||||
let debugLiveRing = [];
|
||||
let debugT0 = 0;
|
||||
|
||||
function openDebugModal() {
|
||||
debugModalOpen = true;
|
||||
debugT0 = Date.now();
|
||||
debugLiveRing = [];
|
||||
document.getElementById('debugOverlay').classList.add('show');
|
||||
// Auto-start IMU stream if not already running
|
||||
if (!imuSubscribed && chars.imuStream) vizSetPaused(false);
|
||||
}
|
||||
function closeDebugModal() {
|
||||
debugModalOpen = false;
|
||||
document.getElementById('debugOverlay').classList.remove('show');
|
||||
}
|
||||
|
||||
function feedDebugRow(gyroX, gyroZ, accelX, accelY, accelZ, moveX, moveY, flags) {
|
||||
if (!debugModalOpen) return;
|
||||
const ms = Date.now() - debugT0;
|
||||
const row = { ms, gyroX, gyroZ, accelX, accelY, accelZ, moveX, moveY, flags };
|
||||
|
||||
// Live ring buffer
|
||||
debugLiveRing.push(row);
|
||||
if (debugLiveRing.length > DEBUG_LIVE_ROWS) debugLiveRing.shift();
|
||||
|
||||
// Recording buffer
|
||||
if (debugRecording) {
|
||||
debugBuffer.push(row);
|
||||
document.getElementById('debugRecCount').textContent = debugBuffer.length + ' samples';
|
||||
}
|
||||
|
||||
// Shock indicator
|
||||
const shocked = !!(flags & 0x08);
|
||||
const badge = document.getElementById('debugShockBadge');
|
||||
badge.classList.toggle('active', shocked);
|
||||
|
||||
// Render live table
|
||||
const tbody = document.getElementById('debugRows');
|
||||
tbody.innerHTML = '';
|
||||
for (const r of debugLiveRing) {
|
||||
const f = [];
|
||||
if (r.flags & 0x01) f.push('idle');
|
||||
if (r.flags & 0x02) f.push('tap1');
|
||||
if (r.flags & 0x04) f.push('tap2');
|
||||
if (r.flags & 0x08) f.push('shock');
|
||||
const tr = document.createElement('tr');
|
||||
if (r.flags & 0x08) tr.className = 'shock-row';
|
||||
tr.innerHTML =
|
||||
`<td>${r.ms}</td><td>${r.gyroX}</td><td>${r.gyroZ}</td>` +
|
||||
`<td>${r.accelX}</td><td>${r.accelY}</td><td>${r.accelZ}</td>` +
|
||||
`<td>${r.moveX}</td><td>${r.moveY}</td><td>${f.join(' ')}</td>`;
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
tbody.parentElement.parentElement.scrollTop = tbody.parentElement.parentElement.scrollHeight;
|
||||
}
|
||||
|
||||
function toggleDebugRec() {
|
||||
debugRecording = !debugRecording;
|
||||
const btn = document.getElementById('debugRecBtn');
|
||||
btn.classList.toggle('recording', debugRecording);
|
||||
btn.textContent = debugRecording ? '■ STOP' : '● REC';
|
||||
if (debugRecording) { debugBuffer = []; debugT0 = Date.now(); }
|
||||
document.getElementById('debugRecCount').textContent = debugBuffer.length + ' samples';
|
||||
}
|
||||
|
||||
function saveDebugCSV() {
|
||||
if (!debugBuffer.length) { log('No recorded data to save','warn'); return; }
|
||||
const header = 'ms,gyroX_mDPS,gyroZ_mDPS,accelX_mg,accelY_mg,accelZ_mg,moveX,moveY,flags\n';
|
||||
const rows = debugBuffer.map(r =>
|
||||
`${r.ms},${r.gyroX},${r.gyroZ},${r.accelX},${r.accelY},${r.accelZ},${r.moveX},${r.moveY},${r.flags}`
|
||||
).join('\n');
|
||||
const blob = new Blob([header + rows], { type: 'text/csv' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url; a.download = `imu_debug_${new Date().toISOString().slice(0,19).replace(/:/g,'-')}.csv`;
|
||||
a.click(); URL.revokeObjectURL(url);
|
||||
log(`Saved ${debugBuffer.length} samples as CSV`,'ok');
|
||||
}
|
||||
|
||||
function clearDebugRec() {
|
||||
debugBuffer = [];
|
||||
debugRecording = false;
|
||||
const btn = document.getElementById('debugRecBtn');
|
||||
btn.classList.remove('recording');
|
||||
btn.textContent = '● REC';
|
||||
document.getElementById('debugRecCount').textContent = '0 samples';
|
||||
}
|
||||
|
||||
// ── Param display ─────────────────────────────────────────────────────────────
|
||||
function updateDisplay(key, val) {
|
||||
const map = {
|
||||
sensitivity: ['valSensitivity', v=>parseFloat(v).toFixed(0)],
|
||||
deadZone: ['valDeadZone', v=>parseFloat(v).toFixed(3)],
|
||||
accel: ['valAccel', v=>parseFloat(v).toFixed(2)],
|
||||
jerkThreshold:['valJerkThreshold',v=>parseFloat(v).toFixed(0)],
|
||||
tapThreshold: ['valTapThreshold', v=>(parseFloat(v)*62.5).toFixed(0)+' mg'],
|
||||
};
|
||||
const [id,fmt] = map[key];
|
||||
@@ -601,7 +703,6 @@ async function vizSetPaused(paused) {
|
||||
}
|
||||
|
||||
function parseImuStream(dv) {
|
||||
if (vizPaused) return;
|
||||
let view;
|
||||
try {
|
||||
view = dv instanceof DataView ? new DataView(dv.buffer, dv.byteOffset, dv.byteLength) : new DataView(dv);
|
||||
@@ -625,6 +726,11 @@ function parseImuStream(dv) {
|
||||
moveY = view.getInt8(11);
|
||||
flags = view.getUint8(12);
|
||||
} catch(e) { log(`parseImuStream: parse error — ${e.message}`,'err'); return; }
|
||||
|
||||
// Feed debug recorder (even when viz is paused)
|
||||
feedDebugRow(gyroX, gyroZ, accelX, accelY, accelZ, moveX, moveY, flags);
|
||||
|
||||
if (vizPaused) return;
|
||||
const idle = !!(flags & 0x01);
|
||||
const single = !!(flags & 0x02);
|
||||
const dbl = !!(flags & 0x04);
|
||||
|
||||
Reference in New Issue
Block a user