Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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);
}
-
}
}