Bladeren bron

fix: guard c.types in backup import and include lizard map in export

copilot-swe-agent[bot] 3 maanden geleden
bovenliggende
commit
6901c7b135
1 gewijzigde bestanden met toevoegingen van 34 en 8 verwijderingen
  1. 34 8
      docs/index.html

+ 34 - 8
docs/index.html

@@ -980,9 +980,15 @@ function buildBackup(p, bp){
   const types=[];
   for(let et=0; et<TYPE_DEFS.length; et++){ const q=73+et*8;
     types.push({back:[p[q],p[q+1],p[q+2],p[q+3]], qam:p[q+4], abSwap:p[q+5], pad:p[q+6], led:p[q+7]}); }
-  return { magic:"openpuck-backup", version:1, bonds,
-    config:{ mode:p[1], mDiv:p[2], mFric:p[3], persistMode:p[22], chord:[p[23],p[24],p[25]],
-             rumble:p[51], swProRate:p[52], swGyro10:p[53], types } };
+  const cfg={ mode:p[1], mDiv:p[2], mFric:p[3], persistMode:p[22], chord:[p[23],p[24],p[25]],
+              rumble:p[51], swProRate:p[52], swGyro10:p[53], types };
+  // version 2: include the lizard map so it survives a backup/restore cycle.
+  // Guard on !lizardBusy to avoid a race with the one-shot lazy load (lizardExchange sets
+  // lizardBusy while the initial 0x11 fetch is in flight); if the load is still pending the
+  // map snapshot would be empty, which would incorrectly clear bindings on restore.
+  if(lizardLoaded && lizardCapable() && !lizardBusy)
+    cfg.lizardMap=lizardBindings.map(b=>({outType:b.outType,od:b.od.slice(),trig:b.trig>>>0,hold:b.hold>>>0}));
+  return { magic:"openpuck-backup", version:(cfg.lizardMap?2:1), bonds, config:cfg };
 }
 function downloadBackup(obj){
   const ts=new Date().toISOString().slice(0,19).replace(/[:T]/g,"-");
@@ -1038,11 +1044,31 @@ async function importBackup(file){
     await sf(1,c.mDiv); await sf(2,c.mFric); await sf(22,c.rumble); await sf(16,c.persistMode?1:0);
     await sf(17,c.chord[0]); await sf(18,c.chord[1]); await sf(19,c.chord[2]);
     await sf(23,c.swProRate); await sf(24,c.swGyro10);
-    for(let et=0; et<c.types.length && et<4; et++){ const t=c.types[et];
-      for(let k=0;k<4;k++) await sf(40+et*8+k, t.back[k]);
-      await sf(40+et*8+4, t.qam); await sf(40+et*8+5, t.abSwap?1:0);
-      await sf(40+et*8+6, t.pad?1:0); await sf(40+et*8+7, t.led); }
-    log("settings replayed ("+(9+c.types.length*8)+" fields)");
+    // c.types is absent in pre-lizard-map backups (version 1 before per-type config was
+    // added); guard so a missing or malformed field never crashes the import mid-flight.
+    if(Array.isArray(c.types)){
+      for(let et=0; et<c.types.length && et<4; et++){ const t=c.types[et];
+        for(let k=0;k<4;k++) await sf(40+et*8+k, t.back[k]);
+        await sf(40+et*8+4, t.qam); await sf(40+et*8+5, t.abSwap?1:0);
+        await sf(40+et*8+6, t.pad?1:0); await sf(40+et*8+7, t.led); }
+      log("settings replayed ("+(9+c.types.length*8)+" fields)");
+    } else { log("settings replayed (9 fields — no per-type config in this backup)"); }
+    // restore the lizard map if the backup includes it (version 2+) and the puck speaks v16+.
+    // pre-lizard-map backups simply lack c.lizardMap; skip silently so they still import cleanly.
+    if(Array.isArray(c.lizardMap) && lizardCapable()){
+      const map=c.lizardMap.slice(0,LZ_MAX);
+      await send([0x13, map.length&0xff]); // begin edit (set count)
+      for(let i=0;i<map.length;i++){
+        const b=map[i], od=(b.od||[]).slice(0,7); while(od.length<7) od.push(0);
+        const t=(b.trig||0)>>>0, h=(b.hold||0)>>>0;
+        await send([0x12, i, (b.outType||0)&0xff, ...od.map(x=>(x||0)&0xff),
+          t&0xff,(t>>>8)&0xff,(t>>>16)&0xff,(t>>>24)&0xff,
+          h&0xff,(h>>>8)&0xff,(h>>>16)&0xff,(h>>>24)&0xff]);
+      }
+      await send([0x14]); // commit + persist to flash
+      await readLizard(); // drain the 0xAA echo so the pipe is clean for bond writes
+      log("lizard map restored — "+map.length+" bindings");
+    }
     // write each bond slot with its own small command [0x0D][slot][used][24-byte rec]
     let n=0;
     for(let s=0;s<4;s++){