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
Diff: main.cpp
- Revision:
- 17:fc68d40b8b1f
- Parent:
- 16:52484666b323
- Child:
- 18:ebe5da639a6a
diff -r 52484666b323 -r fc68d40b8b1f main.cpp --- a/main.cpp Sat Oct 06 12:40:24 2012 +0000 +++ b/main.cpp Sun Oct 07 12:48:44 2012 +0000 @@ -55,6 +55,7 @@ #include "mbedOSC.h" #include "DmxArtNet.h" #include "DMX.h" +#include "filter.h" #include <sstream> @@ -113,8 +114,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 @@ -127,6 +128,8 @@ AnalogIn fadeUpAIN(kMBED_AIN_FADEUP); DigitalIn tapLeftDIN(kMBED_DIN_TAP_L); DigitalIn tapRightDIN(kMBED_DIN_TAP_R); +medianFilter xFadeFilter(9); +medianFilter fadeUpFilter(9); SPKRotaryEncoder menuEnc(kMBED_ENC_A, kMBED_ENC_B, kMBED_ENC_SW); @@ -160,7 +163,7 @@ SPKMenuPayload commsMenu; enum { commsNone, commsOSC, commsArtNet, commsDMXIn, commsDMXOut}; int commsMode = commsNone; -enum { advancedHDCPOn, advancedHDCPOff, advancedLoadDefaults, advancedSelfTest }; +enum { advancedHDCPOn, advancedHDCPOff, advancedConformProcessor, advancedLoadDefaults, advancedSelfTest }; // RJ45 Comms enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit @@ -178,6 +181,8 @@ // A&B Fade as resolved percent int fadeAPercent = 0; int fadeBPercent = 0; +int oldFadeAPercent = 0; +int oldFadeBPercent = 0; // Tap button states bool tapLeftWasFirstPressed = false; @@ -301,6 +306,152 @@ return ok; } +bool conformProcessor() +{ + bool ok = true; + + int32_t on = 1; + int32_t off = 0; + + // Make sure our windows exist + ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsEnable, on); + ok = ok && tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsEnable, on); + ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsLayerPriority, 1); // TODO: Setting this to 4 caused controller freeze? + ok = ok && tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsLayerPriority, 2); + + // Assign inputs to windows, so that left on the crossfader is left on the processor viewed from front + ok = ok && tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsWindowSource, kTV1SourceRGB2); + ok = ok && tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsWindowSource, kTV1SourceRGB1); + + // Set scaling to fit source within output, maintaining aspect ratio + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustWindowsZoomLevel, 100); + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDB, kTV1FunctionAdjustWindowsZoomLevel, 100); + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustWindowsShrinkEnable, off); + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDB, kTV1FunctionAdjustWindowsShrinkEnable, off); + int32_t fit = 1; + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, fit); + ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceAspectCorrect, fit); + + // On source loss, hold on the last frame received. + int32_t freeze = 1; + ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceOnSourceLoss, freeze); + ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceOnSourceLoss, freeze); + + // Finally, autoset to sources? + //int32_t start = 1; + //ok = ok && tvOne.command(kTV1SourceRGB1, kTV1WindowIDA, kTV1FunctionAdjustSourceAutoSet, start); + //ok = ok && tvOne.command(kTV1SourceRGB2, kTV1WindowIDA, kTV1FunctionAdjustSourceAutoSet, start); + + return ok; +} + +void selfTest() +{ + /* SELF TEST - Pixels + * Clicking �self-test� menu will display a solid lit screen. Check all pixels lit. + * Verified: Display + */ + + screen.imageToBuffer(spkDisplayAllPixelsOn); + screen.sendBuffer(); + + while(!menuEnc.hasPressed()) + { + // do nothing, wait for press + } + + /* SELF TEST - Mixing Controls + * Clicking again will prompt to check crossfader, fade to black and tap buttons. Check movement of physical controls against 0.0-1.0 values on- screen. + * Verified: Mixing controls. + */ + + screen.clearBuffer(); + screen.textToBuffer("Self test - Mixing Controls", 0); + + while(!menuEnc.hasPressed()) + { + stringstream xFadeReadOut; + stringstream fadeToBlackReadOut; + stringstream tapsReadOut; + + xFadeReadOut.precision(2); + fadeToBlackReadOut.precision(2); + tapsReadOut.precision(1); + + xFadeReadOut << "Crossfade: " << xFadeAIN.read(); + fadeToBlackReadOut << "Fade to black: " << fadeUpAIN.read(); + tapsReadOut << "Tap left: " << tapLeftDIN.read() << " right: " << tapRightDIN.read(); + + screen.clearBufferRow(1); + screen.clearBufferRow(2); + screen.clearBufferRow(3); + + screen.textToBuffer(xFadeReadOut.str(), 1); + screen.textToBuffer(fadeToBlackReadOut.str(), 2); + screen.textToBuffer(tapsReadOut.str(), 3); + screen.sendBuffer(); + } + + /* SELF TEST - RS232 + * Click the controller menu control. Should see �RS232 test� prompt and test message. Ensure PC is displaying the test message. + * Verified: RS232 connection. + */ + + screen.clearBuffer(); + screen.textToBuffer("Self test - RS232", 0); + screen.sendBuffer(); + + while(!menuEnc.hasPressed()) + { + screen.textToBuffer("TODO!", 1); + screen.sendBuffer(); + } + + /* SELF TEST - DMX + * Click the controller menu control. Should see �DMX test� prompt and test message. Ensure PC is displaying the test message. + * Verified: RS485 connection and DMX library. + */ + + screen.clearBuffer(); + screen.textToBuffer("Self test - DMX", 0); + screen.sendBuffer(); + + while(!menuEnc.hasPressed()) + { + screen.textToBuffer("TODO!", 1); + screen.sendBuffer(); + } + + /* SELF TEST - OSC + * Click the controller menu control. Should see �OSC test� prompt and test message. Ensure PC is displaying the test message. + * Verified: Ethernet connection and OSC library. + */ + + screen.clearBuffer(); + screen.textToBuffer("Self test - DMX", 0); + screen.sendBuffer(); + + while(!menuEnc.hasPressed()) + { + screen.textToBuffer("TODO!", 1); + screen.sendBuffer(); + } + + /* SELF TEST - Exit! + * To do this, we could just do nothing but we'd need to recreate screen and comms as they were. + * Instead, lets just restart the mbed + */ + + screen.clearBuffer(); + screen.textToBuffer("Self test complete", 0); + screen.textToBuffer("Press to restart controller", 1); + screen.sendBuffer(); + + while(!menuEnc.hasPressed()) {} + + mbed_reset(); +} + int main() { if (debug) @@ -354,6 +505,7 @@ advancedMenu.title = "Troubleshooting"; advancedMenu.addMenuItem("HDCP Off", advancedHDCPOff, 0); advancedMenu.addMenuItem("HDCP On", advancedHDCPOn, 0); + advancedMenu.addMenuItem("Conform Processor", advancedConformProcessor, 0); if (settingsAreCustom) advancedMenu.addMenuItem("Revert to defaults", advancedLoadDefaults, 0); advancedMenu.addMenuItem("Start Self-Test", advancedSelfTest, 0); @@ -658,6 +810,15 @@ screen.clearBufferRow(kTVOneStatusLine); screen.textToBuffer(sendOK, kTVOneStatusLine); } + else if (advancedMenu.selectedPayload1() == advancedConformProcessor) + { + bool ok = conformProcessor(); + + std::string sendOK = ok ? "Conform success" : "Send Error: Conform"; + + screen.clearBufferRow(kTVOneStatusLine); + screen.textToBuffer(sendOK, kTVOneStatusLine); + } else if (advancedMenu.selectedPayload1() == advancedLoadDefaults) { settings.loadDefaults(); @@ -667,109 +828,7 @@ } else if (advancedMenu.selectedPayload1() == advancedSelfTest) { - /* SELF TEST - Pixels - * Clicking �self-test� menu will display a solid lit screen. Check all pixels lit. - * Verified: Display - */ - - screen.imageToBuffer(spkDisplayAllPixelsOn); - screen.sendBuffer(); - - while(!menuEnc.hasPressed()) - { - // do nothing, wait for press - } - - /* SELF TEST - Mixing Controls - * Clicking again will prompt to check crossfader, fade to black and tap buttons. Check movement of physical controls against 0.0-1.0 values on- screen. - * Verified: Mixing controls. - */ - - screen.clearBuffer(); - screen.textToBuffer("Self test - Mixing Controls", 0); - - while(!menuEnc.hasPressed()) - { - stringstream xFadeReadOut; - stringstream fadeToBlackReadOut; - stringstream tapsReadOut; - - xFadeReadOut.precision(2); - fadeToBlackReadOut.precision(2); - tapsReadOut.precision(1); - - xFadeReadOut << "Crossfade: " << xFadeAIN.read(); - fadeToBlackReadOut << "Fade to black: " << fadeUpAIN.read(); - tapsReadOut << "Tap left: " << tapLeftDIN.read() << " right: " << tapRightDIN.read(); - - screen.clearBufferRow(1); - screen.clearBufferRow(2); - screen.clearBufferRow(3); - - screen.textToBuffer(xFadeReadOut.str(), 1); - screen.textToBuffer(fadeToBlackReadOut.str(), 2); - screen.textToBuffer(tapsReadOut.str(), 3); - screen.sendBuffer(); - } - - /* SELF TEST - RS232 - * Click the controller menu control. Should see �RS232 test� prompt and test message. Ensure PC is displaying the test message. - * Verified: RS232 connection. - */ - - screen.clearBuffer(); - screen.textToBuffer("Self test - RS232", 0); - screen.sendBuffer(); - - while(!menuEnc.hasPressed()) - { - screen.textToBuffer("TODO!", 1); - screen.sendBuffer(); - } - - /* SELF TEST - DMX - * Click the controller menu control. Should see �DMX test� prompt and test message. Ensure PC is displaying the test message. - * Verified: RS485 connection and DMX library. - */ - - screen.clearBuffer(); - screen.textToBuffer("Self test - DMX", 0); - screen.sendBuffer(); - - while(!menuEnc.hasPressed()) - { - screen.textToBuffer("TODO!", 1); - screen.sendBuffer(); - } - - /* SELF TEST - OSC - * Click the controller menu control. Should see �OSC test� prompt and test message. Ensure PC is displaying the test message. - * Verified: Ethernet connection and OSC library. - */ - - screen.clearBuffer(); - screen.textToBuffer("Self test - DMX", 0); - screen.sendBuffer(); - - while(!menuEnc.hasPressed()) - { - screen.textToBuffer("TODO!", 1); - screen.sendBuffer(); - } - - /* SELF TEST - Exit! - * To do this, we could just do nothing but we'd need to recreate screen and comms as they were. - * Instead, lets just restart the mbed - */ - - screen.clearBuffer(); - screen.textToBuffer("Self test complete", 0); - screen.textToBuffer("Press to restart controller", 1); - screen.sendBuffer(); - - while(!menuEnc.hasPressed()) {} - - mbed_reset(); + selfTest(); } } else @@ -794,9 +853,18 @@ const bool tapLeft = !tapLeftDIN; const bool tapRight = !tapRightDIN; - // We're going to cache the analog in reads, as have seen wierdness otherwise - const float xFadeAINCached = 1-xFadeAIN.read(); - const float fadeUpAINCached = fadeUpAIN.read(); + // We're taking a further median of the AINs on top of mbed libs v29. + // This takes some values from last passes and most from now. With debug off, seem to need median size > 5 + xFadeFilter.process(xFadeAIN.read()); + fadeUpFilter.process(fadeUpAIN.read()); + xFadeFilter.process(xFadeAIN.read()); + fadeUpFilter.process(fadeUpAIN.read()); + xFadeFilter.process(xFadeAIN.read()); + fadeUpFilter.process(fadeUpAIN.read()); + xFadeFilter.process(xFadeAIN.read()); + fadeUpFilter.process(fadeUpAIN.read()); + const float xFadeAINCached = xFadeFilter.process(xFadeAIN.read()); + const float fadeUpAINCached = fadeUpFilter.process(fadeUpAIN.read()); // When a tap is depressed, we can ignore any move of the crossfader but not fade to black if (tapLeft || tapRight) @@ -878,35 +946,48 @@ newFadeBPercent = fadeUp * 100.0; } - // Send to TVOne if percents have changed + //// TASK: Send to TVOne if percents have changed + + // No amount of median filtering is stopping flipflopping between two adjacent percents, so... + bool fadeAPercentHasChanged; + bool fadeBPercentHasChanged; + if (oldFadeAPercent == newFadeAPercent && (newFadeAPercent == fadeAPercent - 1 || newFadeAPercent == fadeAPercent + 1)) + fadeAPercentHasChanged = false; + else + fadeAPercentHasChanged = newFadeAPercent != fadeAPercent; + if (oldFadeBPercent == newFadeBPercent && (newFadeBPercent == fadeBPercent - 1 || newFadeBPercent == fadeBPercent + 1)) + fadeBPercentHasChanged = false; + else + fadeBPercentHasChanged = newFadeBPercent != fadeBPercent; + // We want to send the higher first, otherwise black flashes can happen on taps - if (newFadeAPercent != fadeAPercent && newFadeAPercent >= newFadeBPercent) + if (fadeAPercentHasChanged && newFadeAPercent >= newFadeBPercent) { + oldFadeAPercent = fadeAPercent; fadeAPercent = newFadeAPercent; updateFade = true; fadeAPO = fadeAPercent / 100.0; tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeAPercent); } - - if (newFadeBPercent != fadeBPercent) + if (fadeBPercentHasChanged) { + oldFadeBPercent = fadeBPercent; fadeBPercent = newFadeBPercent; updateFade = true; fadeBPO = fadeBPercent / 100.0; tvOne.command(0, kTV1WindowIDB, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeBPercent); } - - if (newFadeAPercent != fadeAPercent && newFadeAPercent < newFadeBPercent) + if (fadeAPercentHasChanged && newFadeAPercent < newFadeBPercent) { + oldFadeAPercent = fadeAPercent; fadeAPercent = newFadeAPercent; updateFade = true; fadeAPO = fadeAPercent / 100.0; tvOne.command(0, kTV1WindowIDA, kTV1FunctionAdjustWindowsMaxFadeLevel, fadeAPercent); } - if (updateFade && debug) { debug->printf("\r\n"); @@ -914,6 +995,5 @@ debug->printf("xFade = %3f fadeUp = %3f \r\n", xFadeAINCached, fadeUpAINCached); debug->printf("xFade = %3f fadeUp = %3f fadeA% = %i fadeB% = %i \r\n", xFade, fadeUp, fadeAPercent, fadeBPercent); } - } }