Public Access
Fix shifted pictures: non-blocking Nano drawing, frame check, refresh settings
The Nano's periodic full redraw blocked for ~0.8 s. A frame that arrived meanwhile overflowed its 64-byte serial buffer; lost bytes in a bitmap shift the rest of the image (picture moved up), and diff frames never repaired it. - Nano: all drawing (frames, effects, the dot refresh) runs from update() in ~1 ms slices; the refresh pauses while a frame is received or shown - New commands: C (reply with the image checksum) and I (refresh minutes, EEPROM) - ESP32: NanoMonitor asks for the checksum after frames and sends the whole image again on a mismatch, missing answer or Nano restart; counts ERR replies. Periodic whole-image resync. - Settings: "Dot refresh" and "Image resync" intervals (settings v5, v4 records are migrated) - System tab: loop timing, free memory, frame check counts - test_driver: the real driver against a simulated panel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
58a7cb03c2
commit
090c2bf8ae
45 files changed
+1265
-157
No files matched your search
@@ -145,8 +145,10 @@ details{margin-top:10px}summary{cursor:pointer;color:var(--dim);font-size:13px;m
|
||||
<option value="8">Push (slides in from the right)</option><option value="9">Random</option></select>
|
||||
<label>Effect for</label><label><input type="checkbox" id="h_small"> small changes only (the clock's minutes); a new page appears at once</label>
|
||||
<label>Effect time</label><label><input type="number" id="h_efft" min="100" max="10000" style="width:6em"> ms (100-10000, not for Instant; Push needs more when many dots change)</label>
|
||||
<label>Dot refresh</label><label>every <input type="number" id="h_rdots" min="0" max="1440" style="width:5em"> min (0 = off): every dot flipped again</label>
|
||||
<label>Image resync</label><label>every <input type="number" id="h_rimg" min="0" max="1440" style="width:5em"> min (0 = off): the whole image sent again</label>
|
||||
<label>Status LED</label><label><input type="checkbox" id="h_led"> blink while the display is on</label>
|
||||
</div><p class="hint">Dots that don't flip: a longer gap gives the power supply time to recover between pulses, a second pulse catches dots that missed the first one. Full redraws (after power on, every 2 minutes) use one pulse per dot.</p></div>
|
||||
</div><p class="hint">Dots that don't flip: a longer gap gives the power supply time to recover between pulses, a second pulse catches dots that missed the first one. The dot refresh (and the first frame after power on) uses one pulse per dot; it runs between frames. The image resync repairs a picture the Nano got wrong (e.g. shifted); only dots that differ flip, so normally nothing changes. A wrong picture is also found and repaired by the frame check (see System).</p></div>
|
||||
<div class="card"><h2>Test patterns</h2>
|
||||
<div class="row"><button class="s" onclick="pattern('yellow')">All yellow</button><button class="s" onclick="pattern('black')">All black</button>
|
||||
<button class="s" onclick="pattern('checker')">Checkerboard</button><button class="s" onclick="pattern('checker2')">Checkerboard inverted</button>
|
||||
@@ -212,6 +214,9 @@ async function pollStatus(){try{status=await api('/api/status');
|
||||
function sysinfo(){if(!status)return;const r=[['Firmware',status.firmware],['Last restart',status.reset_reason],['Uptime',Math.floor(status.uptime/3600)+' h '+Math.floor(status.uptime%3600/60)+' min'],
|
||||
['WiFi',status.wifi.ssid+' ('+status.wifi.ip+', '+status.wifi.rssi+' dBm)'],['Home Assistant',status.ha.enabled?(status.ha.connected?'connected':'not connected'):'disabled'],
|
||||
['HA power switch',status.power_enabled?'on':'off'],
|
||||
['Loop',status.load?(status.load.loops_per_s?status.load.loops_per_s+'/s, avg '+(status.load.avg_us/1000).toFixed(1)+' ms, max '+status.load.max_ms+' ms (since boot '+status.load.max_ever_ms+' ms)':'measuring...'):''],
|
||||
['Frame check',status.nano_link?(()=>{const n=status.nano_link;return n.checks+' ok, '+n.mismatches+' wrong, '+n.no_reply+' no answer, '+n.repairs+' repaired'+(n.restarts?', Nano restarted '+n.restarts+'x':'')+(n.errors?', '+n.errors+' errors (last: '+n.last_error+')':'')})():''],
|
||||
['Memory',status.load?Math.round(status.load.heap_free/1024)+' KB free (lowest '+Math.round(status.load.heap_min/1024)+' KB)':''],
|
||||
['Storage',status.storage.available?Math.round(status.storage.used/1024)+' of '+Math.round(status.storage.total/1024)+' KB used':'not available']];
|
||||
$('sysinfo').innerHTML='';r.forEach(([k,v])=>{const a=document.createElement('label');a.textContent=k;const b=document.createElement('span');b.textContent=v;$('sysinfo').append(a,b)})}
|
||||
// pages, bitmaps and fonts
|
||||
@@ -536,7 +541,7 @@ async function stopTest(){clearInterval(testTimer);testTimer=null;await stopLive
|
||||
function fill(){const s=settings;$('s_en').checked=s.schedule.enabled;$('s_day').value=s.schedule.day_start;$('s_late').value=s.schedule.late_start;
|
||||
$('s_q').checked=s.schedule.quarter_hours;$('s_night').value=s.schedule.night_start;
|
||||
$('c_nw').checked=s.clock.no_wifi_screen;$('h_flip').value=s.flip_time;$('h_led').checked=s.status_led;
|
||||
$('h_gap').value=s.drive.flip_gap;$('h_pulses').value=s.drive.pulses;$('h_effect').value=s.drive.effect;$('h_efft').value=s.drive.effect_time;$('h_small').checked=s.drive.effect_small_only;
|
||||
$('h_gap').value=s.drive.flip_gap;$('h_pulses').value=s.drive.pulses;$('h_effect').value=s.drive.effect;$('h_efft').value=s.drive.effect_time;$('h_small').checked=s.drive.effect_small_only;$('h_rdots').value=s.refresh.dots;$('h_rimg').value=s.refresh.image;
|
||||
$('ha_en').checked=s.home_assistant.enabled;$('ha_host').value=s.home_assistant.host;$('ha_port').value=s.home_assistant.port;$('ha_user').value=s.home_assistant.user;
|
||||
$('ha_pass').placeholder=s.home_assistant.password_set?'unchanged':'none';$('ha_url').value=s.home_assistant.api_url;
|
||||
$('ha_token').value='';$('ha_token').placeholder=s.home_assistant.token_set?'unchanged':'none'}
|
||||
@@ -544,7 +549,7 @@ function collect(){const s=JSON.parse(JSON.stringify(settings));
|
||||
Object.assign(s.schedule,{enabled:$('s_en').checked,day_start:$('s_day').value,late_start:$('s_late').value,quarter_hours:$('s_q').checked,night_start:$('s_night').value.trim()});
|
||||
s.clock={no_wifi_screen:$('c_nw').checked};
|
||||
s.flip_time=+$('h_flip').value;s.status_led=$('h_led').checked;
|
||||
s.drive={flip_gap:+$('h_gap').value,pulses:+$('h_pulses').value,effect:+$('h_effect').value,effect_time:+$('h_efft').value,effect_small_only:$('h_small').checked};
|
||||
s.drive={flip_gap:+$('h_gap').value,pulses:+$('h_pulses').value,effect:+$('h_effect').value,effect_time:+$('h_efft').value,effect_small_only:$('h_small').checked};s.refresh={dots:+$('h_rdots').value,image:+$('h_rimg').value};
|
||||
Object.assign(s.home_assistant,{enabled:$('ha_en').checked,host:$('ha_host').value.trim(),port:+$('ha_port').value,user:$('ha_user').value.trim(),api_url:$('ha_url').value.trim()});
|
||||
if($('ha_pass').value)s.home_assistant.password=$('ha_pass').value;if($('ha_token').value)s.home_assistant.token=$('ha_token').value.trim();return s}
|
||||
async function saveSettings(){const r=await post('/api/settings',collect());settings=r.settings;fill();msg(r.restart?'Saved, restarting...':'Settings saved')}
|
||||
|
||||
Reference in new issue
Block a user