Uses *spark d-fuser controller hardware as a USB-DMX interface. Developed for visualising Laurel Pardue’s augmented violin with lights.

Dependencies:   DMX mbed spk_oled_ssd1305

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "DMX.h"
00003 #include "spk_oled_ssd1305.h"
00004 #include "spk_oled_gfx.h"
00005 
00006 // https://developer.mbed.org/forum/mbed/post/4526/
00007 // 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600
00008 #define kUSB_BAUD 57600
00009 
00010 // MBED PINS
00011 
00012 #define kMBED_AIN_XFADE     p20
00013 #define kMBED_AIN_FADEUP    p19
00014 #define kMBED_DIN_TAP_L     p24
00015 #define kMBED_DIN_TAP_R     p23
00016 #define kMBED_ENC_SW        p15
00017 #define kMBED_ENC_A         p16
00018 #define kMBED_ENC_B         p17
00019 
00020 #define kMBED_RS232_TTLTX   p13
00021 #define kMBED_RS232_TTLRX   p14
00022 
00023 #define kMBED_OLED_MOSI     p5
00024 #define kMBED_OLED_SCK      p7
00025 #define kMBED_OLED_CS       p8
00026 #define kMBED_OLED_RES      p9
00027 #define kMBED_OLED_DC       p10
00028 
00029 #define kMBED_DIN_ETHLO_DMXHI       p30
00030 #define kMBED_DOUT_RS485_TXHI_RXLO  p29
00031 #define kMBED_RS485_TTLTX           p28
00032 #define kMBED_RS485_TTLRX           p27
00033 
00034 // DMX Fixtures
00035 
00036 #define kDMX_PARCAN_1 8 - 1
00037 #define kDMX_PARCAN_2 12 - 1
00038 #define kDMX_PARCAN_3 16 - 1
00039 #define kDMX_PARCAN_4 20 - 1
00040 
00041 #define kDMX_PARCAN_LUMA 0
00042 #define kDMX_PARCAN_R 1
00043 #define kDMX_PARCAN_G 2
00044 #define kDMX_PARCAN_B 3
00045 
00046 #define kDMX_SPOT_DIMMER 32 - 1
00047 
00048 #define kDMX_PAN 36 - 1
00049 #define kDMX_TILT_MSB 37 - 1
00050 #define kDMX_TILT_LSB 38 - 1
00051 
00052 #define kDMX_HAZER_HAZE 128
00053 #define kDMX_HAZER_FAN  129
00054 
00055 // MISC Defines
00056 
00057 #define kStringBufferLength 30
00058 #define kUSBSerialBufferLength 256
00059 
00060 //// USB Serial
00061 
00062 Serial usbSerial(USBTX, USBRX);
00063 
00064 //// DMX
00065 
00066 DigitalIn rj45ModeDIN(kMBED_DIN_ETHLO_DMXHI);
00067 DigitalOut dmxDirectionDOUT(kMBED_DOUT_RS485_TXHI_RXLO);
00068 enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit
00069 
00070 DMX dmx(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);
00071 
00072 //// Display
00073 
00074 // SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
00075 SPKDisplay screen(kMBED_OLED_MOSI, kMBED_OLED_SCK, kMBED_OLED_CS, kMBED_OLED_DC, kMBED_OLED_RES, NULL);
00076 
00077 //// mbed input
00078 
00079 DigitalIn button(kMBED_DIN_TAP_L);
00080 DigitalIn buttonR(kMBED_DIN_TAP_R);
00081 bool buttonLastState;
00082 
00083 char usbSerialBuffer[kUSBSerialBufferLength];
00084 int  usbSerialBufferPosition = 0;
00085 bool newStringData = false;
00086 bool newBowData = false;
00087 
00088 //// LAUREL VIOLIN DATA
00089 
00090 // [T: A, B] - T = timestamp.  A is the time count (in minutes or something.  Not presently very useful), B is sample count.  I can change what is creating the stamp.  Also, as I'm using sample count, this is only useful/changes when I record.
00091 int TA, TB; 
00092 
00093 // [P: A, B] - P = pitch.  A is hardware estimate- i.e the pitch estimate that is determined solely from the fingerboard data.  B is the combined hardware + audio data (more accurate, slightly slower). -1 = no data/not confident enough to estimate
00094 float P1A, P1B, P2A, P2B, P3A, P3B, P4A, P4B;
00095 
00096 // [S: A] = signal strength.  A is RMS of audio signal in the buffer.
00097 float S1, S2, S3, S4;
00098 
00099 // [F: A, B, C, D] = finger on string raw data.  generally ranges 1 (no contact) to like .4, 1 being no string down, .9 being low pitch near nut, .4 higher up in pitch closer to the bridge.  A is G string (i think)
00100 float F1, F2, F3, F4;
00101 
00102 // [B: A, B, C, D] = raw bow data, A is sensor closest to frog, D closest to tip. 
00103 float B1, B2, B3, B4;
00104 
00105 // [E: A, B, C]  = bow Estimate. (currently broken)  This should be A - pos estimate (0 to 1 normalized frog to tip), B- pressure (0 -400?) and C- on string/off (0, 1 if B is > 40)  0 for A/B means it isn't ready to estimate.  -1 means bow off string.
00106 float EA, EB;
00107 int EC;
00108 
00109 // TOBY VIOLIN EXTRAS
00110  
00111 float sMaxFixed = 0.1;
00112 float sMultiplier = 255.0/sMaxFixed;
00113 
00114 float eMaxFixed = 400;
00115 float eMultiplier = 255.0/eMaxFixed;
00116 
00117 void testDMX()
00118 {
00119     static char state = 1;
00120     
00121     if (state == 5)
00122     {
00123         dmx.put(kDMX_SPOT_DIMMER, 255);
00124     }
00125     else
00126     {
00127         dmx.put(kDMX_SPOT_DIMMER, 0);
00128         
00129         int address;
00130         
00131         switch (state)
00132         {
00133             case 1: address = kDMX_PARCAN_1; break;
00134             case 2: address = kDMX_PARCAN_2; break;
00135             case 3: address = kDMX_PARCAN_3; break;
00136             case 4: address = kDMX_PARCAN_4; break;
00137         }
00138         
00139         unsigned char parCanData[4];
00140         parCanData[kDMX_PARCAN_R] = 255; 
00141         parCanData[kDMX_PARCAN_G] = 255; 
00142         parCanData[kDMX_PARCAN_B] = 255;
00143         parCanData[kDMX_PARCAN_LUMA] = 0;
00144         dmx.put(parCanData, kDMX_PARCAN_1, 4);
00145         dmx.put(parCanData, kDMX_PARCAN_2, 4);
00146         dmx.put(parCanData, kDMX_PARCAN_3, 4);
00147         dmx.put(parCanData, kDMX_PARCAN_4, 4);
00148     
00149         parCanData[kDMX_PARCAN_LUMA] = 255;
00150         dmx.put(parCanData, address, 4);
00151     }
00152     
00153     if (++state > 5) state = 1; 
00154 }
00155 
00156 inline void processData()
00157 {
00158     float sMax = S1;
00159     if (sMax < S2) sMax = S2;
00160     if (sMax < S3) sMax = S3;
00161     if (sMax < S4) sMax = S4;
00162     
00163     float threshold = sMax * 0.7;
00164     
00165     if (S1 < threshold) S1 = 0;
00166     if (S2 < threshold) S2 = 0;
00167     if (S3 < threshold) S3 = 0;
00168     if (S4 < threshold) S4 = 0;    
00169 } 
00170  
00171 void usbSerialReceive(void) 
00172 {
00173     char receivedChar;
00174  
00175     //if data is ready in the buffer
00176     while (usbSerial.readable()) 
00177     {
00178         receivedChar = usbSerial.getc();
00179  
00180         // Is end of line?
00181         if (receivedChar == '\n' || receivedChar == '\r')
00182         {
00183             // [T: 352, 16896000],[P: 196, -1, 196, -1, 196, -1, 196, -1],[S: 0, 0, 0, 0],[F: 1, 1, 1, 1],[B: 0.5346, 0.5781, 0.9043, 0.9029],[E: 0, 0, 0]            
00184             int scanCount;
00185 //            scanCount = sscanf(
00186 //                                usbSerialString.c_str(), 
00187 //                                "[T: %d, %d],[P: %f, %f, %f, %f, %f, %f, %f, %f],[S: %f, %f, %f, %f],[F: %f, %f, %f, %f],[B: %f, %f, %f, %f],[E: %f, %f, %d]",
00188 //                                &TA, &TB, &P1A, &P1B, &P2A, &P2B, &P3A, &P3B, &P4A, &P4B, &S1, &S2, &S3, &S4, &F1, &F2, &F3, &F4, &B1, &B2, &B3, &B4, &EA, &EB, &EC
00189 //                               );
00190 //            if (scanCount == 25)
00191             scanCount = sscanf(
00192                                 usbSerialBuffer, 
00193                                 "[S: %f, %f, %f, %f],[E: %f, %f, %d]",
00194                                 &S1, &S2, &S3, &S4, &EA, &EB, &EC
00195                                );
00196             
00197             if (scanCount == 7)
00198             {
00199                 newStringData = true;
00200                 newBowData = true;
00201                 processData();
00202             }
00203             else if (scanCount == 4)
00204             {
00205                 newStringData = true;
00206                 processData();    
00207             }
00208             else
00209             {
00210                 screen.textToBuffer("Read vars failed", 6);        
00211             }   
00212             
00213             // Clear to start again
00214             usbSerialBufferPosition = 0;
00215         }
00216         else if (usbSerialBufferPosition < kUSBSerialBufferLength)
00217         {
00218             // Build string up
00219             usbSerialBuffer[usbSerialBufferPosition++] = receivedChar;
00220             usbSerialBuffer[usbSerialBufferPosition] = 0;
00221             
00222             screen.textToBuffer(usbSerialBuffer,4);
00223         }
00224     }
00225 }
00226 
00227 ////  M A I N
00228 int main() {
00229 
00230     // Set display font
00231     screen.fontStartCharacter = &characterBytesStartChar;
00232     screen.fontEndCharacter = &characterBytesEndChar;
00233     screen.fontCharacters = characterBytes;
00234     
00235     // Splash screen
00236     screen.imageToBuffer(spkDisplayLogo);
00237     screen.textToBuffer("SPK:DMXer",0);
00238     screen.textToBuffer("FRATRES 2015",1);
00239     screen.textToBuffer("SW v01",2);
00240     screen.sendBuffer();
00241     
00242     if (rj45ModeDIN == rj45DMX) screen.textToBuffer("RJ45: DMX Mode", 3);
00243     else screen.textToBuffer("RJ45: Ethernet Mode", 3);
00244     screen.sendBuffer();
00245     
00246     dmxDirectionDOUT = 1;
00247     dmx.start();
00248 
00249     dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_R, 255);
00250     dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_G, 255);
00251     dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_B, 255);
00252     dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_LUMA, 0);
00253 
00254     dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_R, 255);
00255     dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_G, 255);
00256     dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_B, 255);
00257     dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_LUMA, 0);
00258         
00259     dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_R, 255);
00260     dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_G, 255);
00261     dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_B, 255);
00262     dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_LUMA, 0);
00263     
00264     dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_R, 255);
00265     dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_G, 255);
00266     dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_B, 255);
00267     dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_LUMA, 0);
00268 
00269     dmx.put(kDMX_PAN, 50);
00270     
00271     //// Serial
00272     usbSerial.baud(kUSB_BAUD);
00273     usbSerial.attach(usbSerialReceive);
00274 
00275     //// TASK: Prime button change detection
00276     buttonLastState = button;
00277 
00278     //// TASK: GO!
00279 
00280     // We've finished setting up, now loop this forever...
00281     while (true) 
00282     {            
00283         if (newStringData)
00284         {   
00285             char S1DMX = S1 * sMultiplier;
00286             char S2DMX = S2 * sMultiplier;
00287             char S3DMX = S3 * sMultiplier;
00288             char S4DMX = S4 * sMultiplier;        
00289             
00290             unsigned char parCanData[4];
00291             parCanData[kDMX_PARCAN_R] = 255; 
00292             parCanData[kDMX_PARCAN_G] = 255; 
00293             parCanData[kDMX_PARCAN_B] = 255;
00294             
00295             parCanData[kDMX_PARCAN_LUMA] = S1DMX;
00296             dmx.put(parCanData, kDMX_PARCAN_1, 4);
00297              
00298             parCanData[kDMX_PARCAN_LUMA] = S2DMX;
00299             dmx.put(parCanData, kDMX_PARCAN_2, 4);
00300             
00301             parCanData[kDMX_PARCAN_LUMA] = S3DMX;            
00302             dmx.put(parCanData, kDMX_PARCAN_3, 4);
00303             
00304             parCanData[kDMX_PARCAN_LUMA] = S4DMX;
00305             dmx.put(parCanData, kDMX_PARCAN_4, 4);
00306             
00307             char dmxSummary[kStringBufferLength];
00308             snprintf(dmxSummary, kStringBufferLength, "S %03u %03u %03u %03u", S1DMX, S2DMX, S3DMX, S4DMX);
00309             screen.textToBuffer(dmxSummary,6);
00310             
00311             newStringData = false;
00312         }
00313         
00314         if (newBowData)
00315         {
00316             // EA = Position, EB = Pressure, EC = On string
00317             if (EB < 0) EB = 0;
00318             char bowDMX = EB * eMultiplier;
00319             if (EC) 
00320             {
00321                 dmx.put(kDMX_SPOT_DIMMER, bowDMX);
00322             }
00323             else
00324             {
00325                 dmx.put(kDMX_SPOT_DIMMER, 0);
00326             }
00327             
00328             dmx.put(kDMX_TILT_MSB, 15 + EA * 50);
00329         }
00330         
00331         // Has the button changed?
00332         if (button != buttonLastState) {
00333             // If so, lets update the lastState variable and then send an OSC message
00334             buttonLastState = button;
00335             
00336             if (button) 
00337             {
00338                 testDMX();
00339                 screen.textToBuffer("Sent: /mbed/button 1",5);
00340                 //dmx.put(kDMX_HAZER_HAZE, 128);
00341                 //dmx.put(kDMX_HAZER_FAN, 255);
00342             }
00343             else        
00344             {
00345                 screen.textToBuffer("Sent: /mbed/button 0",5);
00346                 dmx.put(kDMX_HAZER_HAZE, 0);
00347                 dmx.put(kDMX_HAZER_FAN, 0);
00348             }            
00349         }
00350 
00351         screen.sendBuffer();
00352     }
00353 }