Debounce GATT events

This commit is contained in:
2026-03-01 21:01:55 +01:00
parent 91d802a52e
commit 8f72825318

View File

@@ -15,7 +15,31 @@ const config = { sensitivity:600, deadZone:0.06, accelStrength:0.08, curve:0, ax
let device=null, server=null, chars={}, userDisconnected=false;
let currentChargeStatus=0, currentBattPct=null;
// ── GATT write queue (prevents "operation already in progress") ───────────────
let _gattQueue = Promise.resolve();
function gattWrite(char, value) {
const p = _gattQueue.then(() => char.writeValueWithResponse(value));
_gattQueue = p.catch(() => {});
return p;
}
function gattCmd(char, value) {
const p = _gattQueue.then(() => char.writeValueWithoutResponse(value));
_gattQueue = p.catch(() => {});
return p;
}
// ── Logging ──────────────────────────────────────────────────────────────────
(function() {
const _methods = { log: '', warn: 'warn', error: 'err' };
for (const [method, type] of Object.entries(_methods)) {
const orig = console[method].bind(console);
console[method] = (...args) => {
orig(...args);
log(args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' '), type);
};
}
})();
function log(msg, type='') {
const el=document.getElementById('console');
const now=new Date();
@@ -153,7 +177,12 @@ function applyConfigToUI() {
document.getElementById('tapModGui').checked = !!(config.tapMod & 0x08);
}
async function writeConfigBlob() {
let _writeConfigTimer = null;
function writeConfigBlob() {
clearTimeout(_writeConfigTimer);
_writeConfigTimer = setTimeout(_doWriteConfigBlob, 150);
}
async function _doWriteConfigBlob() {
if (!chars.configBlob) return;
// Gather current UI values into the config shadow
@@ -184,7 +213,7 @@ async function writeConfigBlob() {
view.setUint8(19, 0);
try {
await chars.configBlob.writeValueWithResponse(buf);
await gattWrite(chars.configBlob, buf);
log(`Config written — sens=${config.sensitivity.toFixed(0)} tapThr=${config.tapThreshold} tapAction=${config.tapAction}`,'ok');
} catch(e) { log(`Config write failed: ${e.message}`,'err'); }
}
@@ -192,10 +221,10 @@ async function writeConfigBlob() {
// ── Individual control handlers ───────────────────────────────────────────────
// These update the local config shadow then write the full blob
async function setCurve(val) {
function setCurve(val) {
config.curve = val;
setCurveUI(val);
await writeConfigBlob();
writeConfigBlob();
log(`Curve → ${['LINEAR','SQUARE','SQRT'][val]}`,'ok');
}
function setCurveUI(val) {
@@ -203,10 +232,10 @@ function setCurveUI(val) {
document.getElementById(id).classList.toggle('active', i===val));
}
async function setChargeMode(val) {
function setChargeMode(val) {
config.chargeMode = val;
setChargeModeUI(val);
await writeConfigBlob();
writeConfigBlob();
log(`Charge → ${['OFF','SLOW 50mA','FAST 100mA'][val]}`,'warn');
}
function setChargeModeUI(val) {
@@ -218,10 +247,10 @@ function setChargeModeUI(val) {
document.getElementById('ciMode').textContent = ['Off (0mA)','50 mA','100 mA'][val] ?? '--';
}
async function setTapAction(val) {
function setTapAction(val) {
config.tapAction = val;
setTapActionUI(val);
await writeConfigBlob();
writeConfigBlob();
}
function setTapActionUI(val) {
['tapActLeft','tapActRight','tapActMiddle','tapActKey'].forEach((id,i) =>
@@ -237,7 +266,7 @@ function onTapKeyInput() {
async function sendCalibrate() {
if (!chars.command) return;
try { await chars.command.writeValueWithoutResponse(new Uint8Array([0x01])); log('Calibration sent — hold still!','warn'); }
try { await gattCmd(chars.command, new Uint8Array([0x01])); log('Calibration sent — hold still!','warn'); }
catch(e) { log(`Calibrate failed: ${e.message}`,'err'); }
}
function confirmReset() { document.getElementById('overlay').classList.add('show'); }
@@ -245,7 +274,7 @@ function closeModal() { document.getElementById('overlay').classList.remove('s
async function doReset() {
closeModal(); if (!chars.command) return;
try {
await chars.command.writeValueWithoutResponse(new Uint8Array([0xFF]));
await gattCmd(chars.command, new Uint8Array([0xFF]));
log('Factory reset sent…','warn');
setTimeout(async () => { await readConfigBlob(); log('Config reloaded','ok'); }, 1500);
} catch(e) { log(`Reset failed: ${e.message}`,'err'); }