(This writeup may not be 100% accurate. I'm creating this PR weeks after my initial commit, and discovered numerous errors in my original commit message, so I had to reword those messages. There may be errors in this writeup as well.)
Initialize GBS_PRESET_CUSTOM in setOutModeHdBypass
I found that GBS_PRESET_CUSTOM was left uninitialized (keeps old value) when switching into bypass mode. This means that switching from a fixed resolution to Bypass left it at 0, and switching from a custom preset to Bypass left it at 1. This may or may not affect auto gain behavior; I have not checked, but this inconsistent behavior is worth fixing anyway.
To avoid issues, make setOutModeHdBypass() set GBS_PRESET_CUSTOM to 0. But don't do this if applyPresets() is loading a custom preset, has set GBS_PRESET_CUSTOM to 1, and is calling setOutModeHdBypass(regsInitialized=true) to apply the saved "bypass" preset.
(This really belongs in a separate PR, but I got a merge conflict trying to remove this commit from this PR, and I'm worried about introducing new bugs when disentangling the code.)
Fix output resolution shown after loading and saving custom presets
Change the code to set rto->isCustomPreset = GBS_PRESET_CUSTOM::read(), and not set rto->presetID to 9.
Why was this done? Loading a custom preset writes the "effective preset ID" to the GBS_PRESET_ID register. Previously it would set rto->presetID to 9 rather than GBS_PRESET_ID, so the web UI (updateWebSocketData()) can highlight the "load preset" button to indicate a preset was loaded.
Saving the preset again (in the HTTP "/slot/save" handler) writes rto->presetID (=9) to SlotMeta::presetID. This causes the web UI to show the preset slot's output resolution as "Custom", which is not useful.
Fix
We cannot make "/slot/save" read the GBS_PRESET_ID register rather than rto->presetID, because reading registers over I2C requires calling yield(), and the current (terrible) AsyncWebServer does not allow calling yield() from HTTP callbacks.
Instead we make rto->presetID always reflect GBS_PRESET_ID (and never be set to 9). "/slot/save" reads only rto->presetID when writing the resolution metadata of a saved preset.
One alternative is to create a rto->presetIdReal variable, keep assigning rto->presetId = {9,PresetCustomized} in doPostPresetLoadSteps, and only read rto->presetIdReal in "/slot/save" or when necessary.
This alternative might result in less code side effects, since presumably there might be some code relying on doPostPresetLoadSteps() setting rto->presetID = 9.
Currently there is no code which checks for rto->presetID {==,!=} {PresetCustomized,9,0x09}, but there might be code which depends on rto->presetID not being a regular value (as opposed to "/slot/save" depending on it being a regular value).
On the other hand, there might be code (activeFrameTimeLockInitialSteps?, printVideoTimings, runSyncWatcher?, settingsMenuOLED) which are fixed by not setting rto->presetID = {9,PresetCustomized}.
How do we fix the web UI? We cannot make updateWebSocketData() highlight "load preset" if uopt->presetPreference == OutputCustomized. This is because clicking a custom slot in the web UI (HTTP /slot/set) sets uopt->presetPreference = OutputCustomized, but doesn't call applyPresets() until you click "load preset" (user command '3'). Prior to actually loading the custom preset, if we're on a fixed resolution and GBS_PRESET_CUSTOM is 0, we need to highlight the fixed resolution's button (and ignore uopt->presetPreference == OutputCustomized).
To fix the web UI, we create a new variable rto->isCustomPreset mirroring GBS_PRESET_CUSTOM. Then updateWebSocketData() reads rto->isCustomPreset to decide whether to highlight "load preset" in the web UI.
I'm not sure if this code interacts correctly with the OLED menu, or if the old code did so either. Specifically if (oled_menuItem == 4 && oled_subsetFrame == 1) sets rto->presetID = GBS::GBS_PRESET_ID::read() without actually loading a different preset. This would previously cause the web UI to stop highlighting "load preset" even when a custom preset was loaded, but will no longer do so.
Future work
In the future, we could also change the WebSockets protocol to independently transmit the output resolution (and whether it's customized), and the current preset slot if uopt->presetPreference == OutputCustomized.
If different input resolutions are mapped to different output resolutions (for example mapping 480i input to 480p output, and 480p input to Bypass), the web UI still only shows the output resolution for the most recently saved input resolution, not the current one. But this is a smaller problem than before.
(This writeup may not be 100% accurate. I'm creating this PR weeks after my initial commit, and discovered numerous errors in my original commit message, so I had to reword those messages. There may be errors in this writeup as well.)
Initialize
GBS_PRESET_CUSTOM
in setOutModeHdBypassI found that
GBS_PRESET_CUSTOM
was left uninitialized (keeps old value) when switching into bypass mode. This means that switching from a fixed resolution to Bypass left it at 0, and switching from a custom preset to Bypass left it at 1. This may or may not affect auto gain behavior; I have not checked, but this inconsistent behavior is worth fixing anyway.To avoid issues, make
setOutModeHdBypass()
setGBS_PRESET_CUSTOM
to 0. But don't do this ifapplyPresets()
is loading a custom preset, has setGBS_PRESET_CUSTOM
to 1, and is callingsetOutModeHdBypass(regsInitialized=true)
to apply the saved "bypass" preset.(This really belongs in a separate PR, but I got a merge conflict trying to remove this commit from this PR, and I'm worried about introducing new bugs when disentangling the code.)
Fix output resolution shown after loading and saving custom presets
Change the code to set
rto->isCustomPreset = GBS_PRESET_CUSTOM::read()
, and not setrto->presetID
to 9.Why was this done? Loading a custom preset writes the "effective preset ID" to the GBS_PRESET_ID register. Previously it would set
rto->presetID
to 9 rather thanGBS_PRESET_ID
, so the web UI (updateWebSocketData()
) can highlight the "load preset" button to indicate a preset was loaded.Saving the preset again (in the HTTP "/slot/save" handler) writes
rto->presetID
(=9) toSlotMeta::presetID
. This causes the web UI to show the preset slot's output resolution as "Custom", which is not useful.Fix
We cannot make "/slot/save" read the
GBS_PRESET_ID
register rather thanrto->presetID
, because reading registers over I2C requires callingyield()
, and the current (terrible) AsyncWebServer does not allow callingyield()
from HTTP callbacks.Instead we make
rto->presetID
always reflectGBS_PRESET_ID
(and never be set to 9). "/slot/save" reads onlyrto->presetID
when writing the resolution metadata of a saved preset.rto->presetIdReal
variable, keep assigningrto->presetId = {9,PresetCustomized}
indoPostPresetLoadSteps
, and only readrto->presetIdReal
in "/slot/save" or when necessary.doPostPresetLoadSteps()
settingrto->presetID = 9
.rto->presetID {==,!=} {PresetCustomized,9,0x09}
, but there might be code which depends onrto->presetID
not being a regular value (as opposed to "/slot/save" depending on it being a regular value).activeFrameTimeLockInitialSteps
?,printVideoTimings
,runSyncWatcher
?,settingsMenuOLED
) which are fixed by not settingrto->presetID = {9,PresetCustomized}
.How do we fix the web UI? We cannot make
updateWebSocketData()
highlight "load preset" ifuopt->presetPreference == OutputCustomized
. This is because clicking a custom slot in the web UI (HTTP /slot/set) setsuopt->presetPreference = OutputCustomized
, but doesn't callapplyPresets()
until you click "load preset" (user command '3'). Prior to actually loading the custom preset, if we're on a fixed resolution andGBS_PRESET_CUSTOM
is 0, we need to highlight the fixed resolution's button (and ignoreuopt->presetPreference == OutputCustomized
).To fix the web UI, we create a new variable
rto->isCustomPreset
mirroringGBS_PRESET_CUSTOM
. ThenupdateWebSocketData()
readsrto->isCustomPreset
to decide whether to highlight "load preset" in the web UI.if (oled_menuItem == 4 && oled_subsetFrame == 1)
setsrto->presetID = GBS::GBS_PRESET_ID::read()
without actually loading a different preset. This would previously cause the web UI to stop highlighting "load preset" even when a custom preset was loaded, but will no longer do so.Future work
In the future, we could also change the WebSockets protocol to independently transmit the output resolution (and whether it's customized), and the current preset slot if
uopt->presetPreference == OutputCustomized
.If different input resolutions are mapped to different output resolutions (for example mapping 480i input to 480p output, and 480p input to Bypass), the web UI still only shows the output resolution for the most recently saved input resolution, not the current one. But this is a smaller problem than before.