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:
5:f8b285ca41ba
Parent:
4:d5ff91b66357
Child:
7:e6717468c18d
--- a/main.cpp	Mon Apr 23 09:30:50 2012 +0000
+++ b/main.cpp	Thu Jul 19 10:46:53 2012 +0000
@@ -12,7 +12,9 @@
 // v13 - Menu system for Resolution + Keying implemented, it writing to debug, it sending TVOne commands - Apr'11
 // v14 - Fixes for new PCB - Oct'11
 // v15 - TBZ PCB, OLED - Mar'12
-// v16 - Comms menu, OSC. There in theory: lots of trouble from EthernetNetIf. NetServices better. But still silently crashes on creation of EthernetNetIf, despite (now) ample memory and code tested elsewhere (inc OSC + spkOLED). 
+// v16 - Comms menu, OSC, ArtNet - April'12
+// v17 - RJ45 - May'12
+// v18 - DMX - July'12
 // vxx - TODO: EDID upload from USB mass storage
 // vxx - TODO: EDID creation from resolution
 
@@ -26,14 +28,43 @@
 #include "EthernetNetIf.h"
 #include "mbedOSC.h"
 #include "DmxArtNet.h"
+#include "DMX.h"
 
 #include <sstream>
 
+// MBED PINS
+
+#define kMBED_AIN_XFADE     p20
+#define kMBED_AIN_FADEUP    p19
+#define kMBED_DIN_TAP_L     p24
+#define kMBED_DIN_TAP_R     p23
+#define kMBED_ENC_SW        p15
+#define kMBED_ENC_A         p16
+#define kMBED_ENC_B         p17
+
+#define kMBED_RS232_TTLTX   p13
+#define kMBED_RS232_TTLRX   p14
+
+#define kMBED_OLED_MOSI     p5
+#define kMBED_OLED_SCK      p7
+#define kMBED_OLED_CS       p8
+#define kMBED_OLED_RES      p9
+#define kMBED_OLED_DC       p10
+
+#define kMBED_DIN_ETHLO_DMXHI       p30
+#define kMBED_DOUT_RS485_TXHI_RXLO  p29
+#define kMBED_RS485_TTLTX           p28
+#define kMBED_RS485_TTLRX           p27
+
+// DISPLAY
+
 #define kMenuLine1 3
 #define kMenuLine2 4
 #define kCommsStatusLine 6
 #define kTVOneStatusLine 7
 
+// NETWORKING
+
 #define kOSCMbedPort 10000
 #define kOSCMbedIPAddress 10,0,0,2
 #define kOSCMbedSubnetMask 255,255,255,0
@@ -43,46 +74,61 @@
 #define kArtNetBindIPAddress 2,0,0,100
 #define kArtNetBroadcastAddress 2,255,255,255
 
+#define kDMXInChannelXFade 0
+#define kDMXInChannelFadeUp 1
+#define kDMXOutChannelXFade 0
+#define kDMXOutChannelFadeUp 1
+
 //// 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)
 
 //// mBED PIN ASSIGNMENTS
 
 // Inputs
-AnalogIn xFadeAIN(p20);    
-AnalogIn fadeUpAIN(p19);
-DigitalIn tapLeftDIN(p24);
-DigitalIn tapRightDIN(p23);
+AnalogIn xFadeAIN(kMBED_AIN_XFADE);    
+AnalogIn fadeUpAIN(kMBED_AIN_FADEUP);
+DigitalIn tapLeftDIN(kMBED_DIN_TAP_L);
+DigitalIn tapRightDIN(kMBED_DIN_TAP_R);
 
-SPKRotaryEncoder menuEnc(p17, p16, p15);
+SPKRotaryEncoder menuEnc(kMBED_ENC_A, kMBED_ENC_B, kMBED_ENC_SW);
+
+DigitalIn rj45ModeDIN(kMBED_DIN_ETHLO_DMXHI);
 
 // Outputs
 PwmOut fadeAPO(LED1);
 PwmOut fadeBPO(LED2);
 
+DigitalOut dmxDirectionDOUT(kMBED_DOUT_RS485_TXHI_RXLO);
+
 // SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin, PinName signErrorPin, Serial *debugSerial)
-SPKTVOne tvOne(p13, p14, LED3, LED4, debug);
+SPKTVOne tvOne(kMBED_RS232_TTLTX, kMBED_RS232_TTLRX, LED3, LED4, debug);
 
 // SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
-SPKDisplay screen(p5, p7, p8, p10, p9, debug);
+SPKDisplay screen(kMBED_OLED_MOSI, kMBED_OLED_SCK, kMBED_OLED_CS, kMBED_OLED_DC, kMBED_OLED_RES, debug);
 
 // Menu 
-
 SPKMenu *selectedMenu;
 SPKMenu *lastSelectedMenu;
 SPKMenuOfMenus mainMenu;
 SPKMenuPayload resolutionMenu;
 SPKMenuPayload mixModeMenu;
+enum { blend, additive, lumaKey, chromaKey1, chromaKey2, chromaKey3 }; // additive will require custom TVOne firmware.
+int mixMode = blend;
 SPKMenuPayload commsMenu;
+enum { commsNone, commsOSC, commsArtNet, commsDMXIn, commsDMXOut};
+int commsMode = commsNone;
 
-// Comms Objects
+// RJ45 Comms
+enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit
+int rj45Mode = -1;
 EthernetNetIf *ethernet = NULL;
 OSCClass *osc = NULL;
 OSCMessage recMessage;
 DmxArtNet *artNet = NULL;
+DMX *dmx = NULL;
 
 // Fade logic constants
 const float xFadeTolerance = 0.05;
@@ -93,8 +139,7 @@
 int fadeBPercent = 0;
 
 // Tap button states
-bool tapLeftPrevious = false;
-bool tapRightPrevious = false;
+bool tapLeftWasFirstPressed = false;
 
 // Key mode parameters
 int keyerParamsSet = -1; // last keyParams index uploaded to unit 
@@ -147,13 +192,45 @@
 
 void processArtNet(float &xFade, float &fadeUp) {
 
-
     screen.clearBufferRow(kCommsStatusLine);
     screen.textToBuffer("ArtNet activity", kCommsStatusLine);
     screen.sendBuffer();
     if (debug) debug->printf("ArtNet activity");
 }
 
+void processDMXIn(float &xFade, float &fadeUp) {
+
+    std::stringstream statusMessage;
+
+    int xFadeDMX = dmx->get(kDMXInChannelXFade);
+    int fadeUpDMX = dmx->get(kDMXInChannelXFade);
+
+    xFade = (float)xFadeDMX/255;
+    fadeUp = (float)fadeUpDMX/255;
+
+    screen.clearBufferRow(kCommsStatusLine);
+    statusMessage << "DMX In: xF " << xFadeDMX << " fUp " << fadeUpDMX;
+    screen.textToBuffer(statusMessage.str(), kCommsStatusLine);
+    screen.sendBuffer();
+    if (debug) debug->printf(statusMessage.str().c_str());
+}
+
+void processDMXOut(float &xFade, float &fadeUp) {
+
+    std::stringstream statusMessage;
+
+    int xFadeDMX = xFade*255;
+    int fadeUpDMX = fadeUp*255;
+    
+    dmx->put(kDMXOutChannelXFade, xFadeDMX);
+    dmx->put(kDMXOutChannelFadeUp, fadeUpDMX);
+    
+    screen.clearBufferRow(kCommsStatusLine);
+    statusMessage << "DMX Out: xF " << xFadeDMX << " fUp " << fadeUpDMX;
+    screen.textToBuffer(statusMessage.str(), kCommsStatusLine);
+    screen.sendBuffer();
+    if (debug) debug->printf(statusMessage.str().c_str());
+}
 
 inline float fadeCalc (const float AIN, const float tolerance) {
     float pos ;
@@ -202,11 +279,11 @@
     // Splash screen
     screen.imageToBuffer(spkDisplayLogo);
     screen.textToBuffer("SPK:D-Fuser",0);
-    screen.textToBuffer("SW beta.15",1);
+    screen.textToBuffer("SW beta.18",1);
+    screen.sendBuffer();
     
     // Set menu structure
     mixModeMenu.title = "Mix Mode";
-    enum { blend, additive, lumaKey, chromaKey1, chromaKey2, chromaKey3 }; // additive will require custom TVOne firmware.
     mixModeMenu.addMenuItem("Blend", blend, 0);
     mixModeMenu.addMenuItem("LumaKey", lumaKey, 0);
     mixModeMenu.addMenuItem("ChromaKey - Blue", chromaKey1, 0);
@@ -223,12 +300,12 @@
     resolutionMenu.addMenuItem(kTV1ResolutionDescriptionDualHeadXGAp60, kTV1ResolutionDualHeadXGAp60, 0);
     resolutionMenu.addMenuItem(kTV1ResolutionDescriptionTripleHeadVGAp60, kTV1ResolutionTripleHeadVGAp60, 0);
 
-    commsMenu.title = "Network Mode";
-    enum { commsNone, commsOSC, commsArtNet, commsDMX}; 
+    commsMenu.title = "Network Mode"; 
     commsMenu.addMenuItem("None", commsNone, 0);
     commsMenu.addMenuItem("OSC", commsOSC, 0);
     commsMenu.addMenuItem("ArtNet", commsArtNet, 0);
-    commsMenu.addMenuItem("DMX", commsDMX, 0);
+    commsMenu.addMenuItem("DMX In", commsDMXIn, 0);
+    commsMenu.addMenuItem("DMX Out", commsDMXOut, 0);
 
     mainMenu.title = "Main Menu";
     mainMenu.addMenuItem(&mixModeMenu);
@@ -278,9 +355,29 @@
     while (1) {
 
         //// Task background things
-        if (commsMenu.selectedPayload1() == commsOSC || commsMenu.selectedPayload1() == commsArtNet)
+        if (ethernet && rj45Mode == rj45Ethernet)
+        {
+            if (debug) debug->printf("net poll");
+            Net::poll();
+        }
+
+        //// RJ45 SWITCH
+        
+        if (rj45ModeDIN != rj45Mode)
         {
-            Net::poll();
+            // update state
+            rj45Mode = rj45ModeDIN;
+            if (rj45Mode == rj45Ethernet) commsMenu.title = "Network Mode [Ethernet]";
+            if (rj45Mode == rj45DMX) commsMenu.title = "Network Mode [DMX]";
+            
+            // cancel old comms
+            commsMode = commsNone;
+            commsMenu = commsMode;
+            
+            // refresh display
+            if (selectedMenu == &commsMenu) screen.textToBuffer(selectedMenu->title, kMenuLine1);
+            if (rj45Mode == rj45Ethernet) screen.textToBuffer("RJ45: Ethernet Engaged", kCommsStatusLine);
+            if (rj45Mode == rj45DMX) screen.textToBuffer("RJ45: DMX Engaged", kCommsStatusLine);
         }
 
         //// MENU
@@ -299,7 +396,6 @@
             screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
             
             if (debug) debug->printf("%s \r\n", selectedMenu->selectedString().c_str());
-
         }
         
         // Action menu item
@@ -352,6 +448,8 @@
             // With that out of the way, we should be actioning a specific menu's payload?
             else if (selectedMenu == &mixModeMenu)
             {
+                mixMode = mixModeMenu.selectedPayload1();
+            
                 bool ok = false;
                 std::string sentOK;
                 std::stringstream sentMSG;
@@ -414,19 +512,31 @@
             }
             else if (selectedMenu == &commsMenu)
             {
-                std::string commsType = "Network: --";
+                std::string commsTypeString = "Network: --";
                 std::stringstream commsStatus;
             
                 // Tear down any existing comms
                 // This is the action of commsNone
                 // And also clears the way for other comms actions
-                if (osc) {delete osc; osc = NULL;}  
-                if (ethernet) {delete ethernet; ethernet = NULL;}
-                if (artNet) {delete artNet; artNet = NULL;}
-
-                if (commsMenu.selectedPayload1() == commsOSC) 
+                if (osc)        {delete osc; osc = NULL;}  
+                if (ethernet)   {delete ethernet; ethernet = NULL;}
+                if (artNet)     {delete artNet; artNet = NULL;}
+                if (dmx)        {delete dmx; dmx = NULL;}
+                
+                // Ensure we can't change to comms modes the hardware isn't switched to
+                if (rj45Mode == rj45DMX && (commsMenu.selectedPayload1() == commsOSC || commsMenu.selectedPayload1() == commsArtNet))
                 {
-                    commsType = "OSC: ";                    
+                    commsTypeString = "RJ45 not in Ethernet mode";
+                }
+                else if (rj45Mode == rj45Ethernet && (commsMenu.selectedPayload1() == commsDMXIn || commsMenu.selectedPayload1() == commsDMXOut))
+                {
+                    commsTypeString = "RJ45 not in DMX mode";
+                }
+                // Action!
+                else if (commsMenu.selectedPayload1() == commsOSC) 
+                {
+                    commsMode = commsOSC;
+                    commsTypeString = "OSC: ";                    
                     
                     ethernet = new EthernetNetIf(
                     IpAddr(kOSCMbedIPAddress), 
@@ -440,7 +550,7 @@
                     {
                         if (debug) debug->printf("Ethernet setup error, %d", ethError);
                         commsStatus << "Ethernet setup failed";
-                        // commsMenu = commsNone; //FIXME: this should set the selected menu item to none, but errors. wtf?
+                        commsMenu = commsNone;
                         // break out of here. this setup should be a function that returns a boolean
                     }
 
@@ -452,7 +562,8 @@
                 }
                 else if (commsMenu.selectedPayload1() == commsArtNet) 
                 {
-                    commsType = "ArtNet: ";                    
+                    commsMode = commsArtNet;
+                    commsTypeString = "ArtNet: ";                    
 
                     artNet = new DmxArtNet();
                     
@@ -470,13 +581,27 @@
                     
                     commsStatus << "Listening";
                 }
-                else if (commsMenu.selectedPayload1() == commsDMX) 
+                else if (commsMenu.selectedPayload1() == commsDMXIn) 
                 {
+                    commsMode = commsDMXIn;
+                    commsTypeString = "DMX In: ";
                     
+                    dmxDirectionDOUT = 0;
+                    
+                    dmx = new DMX(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);
                 }
-                
+                else if (commsMenu.selectedPayload1() == commsDMXOut) 
+                {
+                    commsMode = commsDMXOut;
+                    commsTypeString = "DMX Out: ";
+                    
+                    dmxDirectionDOUT = 1;
+                    
+                    dmx = new DMX(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);
+                }
+                                
                 screen.clearBufferRow(kCommsStatusLine);
-                screen.textToBuffer(commsType + commsStatus.str(), kCommsStatusLine);
+                screen.textToBuffer(commsTypeString + commsStatus.str(), kCommsStatusLine);
             }
             else
             {
@@ -486,9 +611,9 @@
         
         // Send any updates to the display
         screen.sendBuffer();
-       
+        
         
-        //// MIX MIX MIX MIX MIX MIX MIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIX
+        //// MIX MIX MIX MIX MIX MIX MIX MIX MIX MIX MIX MIXMIX MIX MIXMIX MIX MIX MIX MIX MIXMIX MIX MIX
 
         bool updateFade = false;
         float xFade = 0;
@@ -497,32 +622,39 @@
         //// TASK: Process control surface
         
         // Get new states of tap buttons, remembering at end of loop() assign these current values to the previous variables
-        const bool tapLeft = (tapLeftDIN) ? false : true;
-        const bool tapRight = (tapRightDIN) ? false : true;
+        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 = xFadeAIN.read();
+        const float xFadeAINCached = 1-xFadeAIN.read();
         const float fadeUpAINCached = fadeUpAIN.read();
         
         // When a tap is depressed, we can ignore any move of the crossfader but not fade to black
         if (tapLeft || tapRight) 
         {
-            // If both are pressed, which was not pressed in the last loop?
+            // If both are pressed, take to the one that is new, ie. not the first pressed.
             if (tapLeft && tapRight) 
             {
-                if (!tapLeftPrevious) xFade = 0;
-                if (!tapRightPrevious) xFade = 1;
+                xFade = tapLeftWasFirstPressed ? 1 : 0;
             }
-            // If just one is pressed, is this it going high or the other going low?
-            else if (tapLeft && (!tapLeftPrevious || tapRightPrevious)) xFade = 0;
-            else if (tapRight && (!tapRightPrevious || tapLeftPrevious)) xFade = 1;
-        } 
+            // If just one is pressed, take to that and remember which is pressed
+            else if (tapLeft) 
+            {
+                xFade = 0;
+                tapLeftWasFirstPressed = 1;
+            }
+            else if (tapRight) 
+            {
+                xFade = 1;
+                tapLeftWasFirstPressed = 0;
+            }
+        }
         else xFade = fadeCalc(xFadeAINCached, xFadeTolerance);
 
         fadeUp = 1.0 - fadeCalc(fadeUpAINCached, fadeUpTolerance);
 
         //// TASK: Process Network Comms
-        if (commsMenu.selectedPayload1() == commsOSC)
+        if (commsMode == commsOSC)
         {
             if (osc->newMessage) 
             {
@@ -531,11 +663,21 @@
             }
         }
 
-        if (commsMenu.selectedPayload1() == commsArtNet)
+        if (commsMode == commsArtNet)
         {
             if (artNet->Work()) processArtNet(xFade, fadeUp);
         }
 
+        if (commsMode == commsDMXIn)
+        {
+            processDMXIn(xFade, fadeUp);
+        }
+
+        if (commsMode == commsDMXOut)
+        {
+            processDMXOut(xFade, fadeUp);
+        }
+
         // WISH: Really, we should have B at 100% and A fading in over that, with fade to black implemented as a fade in black layer on top of that correct mix.
         // There is no way to implement that though, and the alphas get messy, so this is the only way (afaik).
         
@@ -543,7 +685,7 @@
         int newFadeAPercent = 0;
         int newFadeBPercent = 0;
 
-        switch (mixModeMenu.selectedPayload1()) {
+        switch (mixMode) {
         case blend:
         case additive: 
             newFadeAPercent = (1.0-xFade) * fadeUp * 100.0;
@@ -581,9 +723,6 @@
             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);
         }
-        
-        // END OF LOOP - Reset
-        tapLeftPrevious = tapLeft;
-        tapRightPrevious = tapRight;
+
     }
 }