The codebase to run the *spark d-fuser controller www.sparkav.co.uk/dvimixer

Dependencies:   SPK-TVOne DMX DmxArtNet NetServicesMin OSC PinDetect mRotaryEncoder iniparser mbed spk_oled_ssd1305 filter

Revision:
31:01845a2347ff
Parent:
30:873979018850
Child:
32:9f9eb3583bfa
--- a/main.cpp	Mon Oct 29 13:18:52 2012 +0000
+++ b/main.cpp	Sat Nov 03 20:12:22 2012 +0000
@@ -116,8 +116,8 @@
 //// DEBUG
 
 // Comment out one or the other...
-//Serial *debug = new Serial(USBTX, USBRX); // For debugging via USB serial
-Serial *debug = NULL; // For release (no debugging)
+Serial *debug = new Serial(USBTX, USBRX); // For debugging via USB serial
+//Serial *debug = NULL; // For release (no debugging)
 
 //// SOFT RESET
 
@@ -199,6 +199,11 @@
 bool tvOneRGB1Stable = true; // init true as this is conformed state of mixer, ie. RGB1 not SIS1
 bool tvOneRGB2Stable = true;
 
+// TVOne behaviour flags
+bool tvOneHDCPOn = false;
+bool tvOneEDIDPassthrough = true;
+const int32_t EDIDPassthroughSlot = 7;
+
 void processOSC(float &xFade, float &fadeUp) {
     string statusMessage;
     
@@ -299,7 +304,7 @@
     return pos;
 }
 
-bool handleTVOneSources()
+bool handleTVOneSources(bool updateScreenOverride = false)
 {
     bool ok = true;
 
@@ -331,8 +336,8 @@
     if (RGB2 && !tvOneRGB2Stable) tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsWindowSource, kTV1SourceRGB2);
     if (!RGB1 && tvOneRGB1Stable) tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsWindowSource, kTV1SourceSIS1);
     if (!RGB2 && tvOneRGB2Stable) tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsWindowSource, kTV1SourceSIS2);
-    
-    if (RGB1 != tvOneRGB1Stable || RGB2 != tvOneRGB2Stable)
+     
+    if (updateScreenOverride || (RGB1 != tvOneRGB1Stable || RGB2 != tvOneRGB2Stable))
     {
         screen.clearBufferRow(kTVOneStatusLine);
         screen.textToBuffer(tvOneDetectString, kTVOneStatusLine); 
@@ -354,12 +359,12 @@
     
     if (index != keyerParamsSet)
     {
-        ok =       tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinY, settings.keyerParamSet(index)[0]); 
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxY, settings.keyerParamSet(index)[1]); 
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinU, settings.keyerParamSet(index)[2]); 
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxU, settings.keyerParamSet(index)[3]); 
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinV, settings.keyerParamSet(index)[4]); 
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxV, settings.keyerParamSet(index)[5]);
+        ok =       tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinY, settings.keyerParamSet(index)[SPKSettings::minY]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxY, settings.keyerParamSet(index)[SPKSettings::maxY]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinU, settings.keyerParamSet(index)[SPKSettings::minU]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxU, settings.keyerParamSet(index)[SPKSettings::maxU]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMinV, settings.keyerParamSet(index)[SPKSettings::minV]); 
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerMaxV, settings.keyerParamSet(index)[SPKSettings::maxV]);
         
         keyerParamsSet = index;
     }
@@ -373,6 +378,8 @@
 
 void actionMixMode()
 {
+    if (debug) debug->printf("Changing mix mode \r\n");
+
     bool ok = true;
     string sentOK;
     char sentMSGBuffer[kStringBufferLength];
@@ -380,17 +387,23 @@
     // Set Keyer
     if (mixMode < mixKey)
     {
-        if (mixMode == mixBlend)
-        {
-            // Waiting on TV One...
-        }
-        else if (mixMode == mixAdditive)
+        // Set Keyer Off. Quicker to set and fail than to test for on and then turn off
+        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerEnable, false);
+        
+        if (mixMode == mixBlend)    
         {
-            // Waiting on TV One...
+            // Turn off Additive Mixing on output
+            ok = tvOne.command(0, kTV1WindowIDA, 0x298, 0);
+            snprintf(sentMSGBuffer, kStringBufferLength, "Blend");
         }
-        
-        ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustKeyerEnable, false);
-        snprintf(sentMSGBuffer, kStringBufferLength, "Keyer Off");                
+        if (mixMode == mixAdditive) 
+        {   
+            // First set B to what you'd expect for additive; it may be left at 100 if optimised blend mixing was previous mixmode.
+            ok =       tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeBPercent);
+            // Then turn on Additive Mixing
+            ok = ok && tvOne.command(0, kTV1WindowIDA, 0x298, 1);
+            snprintf(sentMSGBuffer, kStringBufferLength, "Additive");
+        }                
     }
     else
     {
@@ -407,8 +420,6 @@
     
     screen.clearBufferRow(kTVOneStatusLine);
     screen.textToBuffer(sentOK + sentMSGBuffer, kTVOneStatusLine);
-    
-    if (debug) { debug->printf("Changing mix mode"); }
 }
 
 
@@ -449,9 +460,10 @@
     ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceOnSourceLoss, freeze);
     
     // Set resolution and fade levels for maximum chance of being seen
+    int32_t slot = tvOneEDIDPassthrough ? EDIDPassthroughSlot : 5;
     ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsOutputResolution, kTV1ResolutionVGA);
-    ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, 7);
-    ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, 7);
+    ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+    ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
     ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsMaxFadeLevel, 100);
     ok = ok && tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsMaxFadeLevel, 100);
     
@@ -654,10 +666,10 @@
     advancedMenu.title = "Troubleshooting"; 
     advancedMenu.addMenuItem(SPKMenuItem("HDCP Off", advancedHDCPOff));
     advancedMenu.addMenuItem(SPKMenuItem("HDCP On", advancedHDCPOn));
+    advancedMenu.addMenuItem(SPKMenuItem("EDID Passthrough", advancedEDIDPassthrough)); // have global setting of passthrough that overrides resolution sets and is saved with conform processor
+    advancedMenu.addMenuItem(SPKMenuItem("EDID Internal", advancedEDIDInternal));
     advancedMenu.addMenuItem(SPKMenuItem("Test Processor Sources", advancedTestSources));
     advancedMenu.addMenuItem(SPKMenuItem("Conform Processor", advancedConformProcessor));
-    //advancedMenu.addMenuItem(SPKMenuItem("EDID Passthrough", advancedEDIDPassthrough)); // have global setting of passthrough that overrides resolution sets and is saved with conform processor
-    //advancedMenu.addMenuItem(SPKMenuItem("EDID Internal", advancedEDIDInternal));
     if (settingsAreCustom) advancedMenu.addMenuItem(SPKMenuItem("Revert Controller", advancedLoadDefaults));
     advancedMenu.addMenuItem(SPKMenuItem("Start Self-Test", advancedSelfTest));
     advancedMenu.addMenuItem(SPKMenuItem("Back to Main Menu", &mainMenu));
@@ -696,10 +708,8 @@
     
     // If we do not have two solid sources, act on this as we rely on the window having a source for crossfade behaviour
     // Once we've had two solid inputs, don't check any more as we're ok as the unit is set to hold on last frame.
-    // This will update kTVOneStatusLine if necessary
-    bool ok = handleTVOneSources();
-
-    screen.sendBuffer();
+    // This is set to update kTVOneStatusLine and sendBuffer regardless
+    bool ok = handleTVOneSources(true);
 
     //// CONTROLS TEST
 
@@ -757,13 +767,19 @@
                     if (fadeCurve > 1.0f) fadeCurve = 1.0f;
                     if (fadeCurve < 0.0f) fadeCurve = 0.0f;
                     
-                    mixMode = (fadeCurve > 0.0f) ? mixAdditive: mixBlend;
+                    int newMixMode = (fadeCurve > 0.0f) ? mixAdditive: mixBlend;
+
+                    if (newMixMode != mixMode)
+                    {
+                        mixMode = newMixMode;
+                        actionMixMode();
+                    }
 
                     screen.clearBufferRow(kMenuLine2);
                     screen.textToBuffer("Blend [ ----- ] Add", kMenuLine2);
                     screen.characterToBuffer('X', 38 + fadeCurve*20.0f, kMenuLine2);
                     
-                    if (debug) debug->printf("Fade curve changed by %i to %f", menuChange, fadeCurve);
+                    if (debug) debug->printf("Fade curve changed by %i to %f \r\n", menuChange, fadeCurve);
                 }
             }
             else
@@ -788,9 +804,15 @@
             // Are we changing menus?
             if (selectedMenu->selectedItem().type == SPKMenuItem::changesToMenu) 
             {
-                // point selected menu to the new menu
+                // If we're exiting the menu, we should set its selected index back to the menu's beginning...
+                SPKMenu* menuToReset = selectedMenu->selectedItem().payload.menu == &mainMenu? selectedMenu : NULL;
+             
+                // point selected menu pointer to the new menu pointer
                 selectedMenu = selectedMenu->selectedItem().payload.menu;
                 
+                // ...doing this, of course, after we've used the value
+                if (menuToReset) *menuToReset = 0;
+                
                 // update OLED lines 1&2
                 screen.clearBufferRow(kMenuLine1);
                 screen.clearBufferRow(kMenuLine2);
@@ -826,8 +848,11 @@
                 bool ok = true;
                 
                 ok =       tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustOutputsOutputResolution, resolutionMenu.selectedItem().payload.command[0]);
-                ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, resolutionMenu.selectedItem().payload.command[1]);
-                ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, resolutionMenu.selectedItem().payload.command[1]);
+                
+                int32_t slot = tvOneEDIDPassthrough ? EDIDPassthroughSlot : resolutionMenu.selectedItem().payload.command[1];
+                
+                ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+                ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
                 
                 string sentOK;
                 if (ok) sentOK = "Sent: ";
@@ -939,7 +964,7 @@
             {
                 if (advancedMenu.selectedItem().payload.command[0] == advancedHDCPOff)
                 {
-                    bool ok = false;
+                    bool ok;
                     
                     ok = tvOne.setHDCPOn(false);
                     
@@ -950,7 +975,7 @@
                 }
                 else if (advancedMenu.selectedItem().payload.command[0] == advancedHDCPOn)
                 {
-                    bool ok = false;
+                    bool ok;
                     
                     ok = tvOne.setHDCPOn(true);
                     
@@ -959,9 +984,41 @@
                     screen.clearBufferRow(kTVOneStatusLine);
                     screen.textToBuffer(sendOK, kTVOneStatusLine);
                 }
+                else if (advancedMenu.selectedItem().payload.command[0] == advancedEDIDPassthrough)
+                {
+                    tvOneEDIDPassthrough = true;
+                    
+                    bool ok = true;
+                    
+                    int32_t slot = tvOneEDIDPassthrough ? EDIDPassthroughSlot : resolutionMenu.selectedItem().payload.command[1];
+                
+                    ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+                    ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+                    
+                    std::string sendOK = ok ? "Sent: EDID. Next:conform?" : "Send Error: EDID";
+                    
+                    screen.clearBufferRow(kTVOneStatusLine);
+                    screen.textToBuffer(sendOK, kTVOneStatusLine);
+                }
+                else if (advancedMenu.selectedItem().payload.command[0] == advancedEDIDInternal)
+                {
+                    tvOneEDIDPassthrough = false;
+                    
+                    bool ok = true;
+                    
+                    int32_t slot = tvOneEDIDPassthrough ? EDIDPassthroughSlot : resolutionMenu.selectedItem().payload.command[1];
+                
+                    ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+                    ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceEDID, slot);
+                    
+                    std::string sendOK = ok ? "Sent: EDID. Next:conform?" : "Send Error: EDID";
+                    
+                    screen.clearBufferRow(kTVOneStatusLine);
+                    screen.textToBuffer(sendOK, kTVOneStatusLine);
+                }
                 else if (advancedMenu.selectedItem().payload.command[0] == advancedTestSources)
                 {
-                    handleTVOneSources();
+                    handleTVOneSources(true);
                 }
                 else if (advancedMenu.selectedItem().payload.command[0] == advancedConformProcessor)
                 {