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

main.cpp

Committer:
tobyspark
Date:
2016-06-17
Revision:
7:7f3140672370
Parent:
6:cd5846520ea6

File content as of revision 7:7f3140672370:

#include "mbed.h"
#include "DMX.h"
#include "spk_oled_ssd1305.h"
#include "spk_oled_gfx.h"

// https://developer.mbed.org/forum/mbed/post/4526/
// 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600
#define kUSB_BAUD 57600

// 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

// DMX Fixtures

#define kDMX_PARCAN_1 8 - 1
#define kDMX_PARCAN_2 12 - 1
#define kDMX_PARCAN_3 16 - 1
#define kDMX_PARCAN_4 20 - 1

#define kDMX_PARCAN_LUMA 0
#define kDMX_PARCAN_R 1
#define kDMX_PARCAN_G 2
#define kDMX_PARCAN_B 3

#define kDMX_SPOT_DIMMER 32 - 1

#define kDMX_PAN 36 - 1
#define kDMX_TILT_MSB 37 - 1
#define kDMX_TILT_LSB 38 - 1

#define kDMX_HAZER_HAZE 128
#define kDMX_HAZER_FAN  129

// MISC Defines

#define kStringBufferLength 30
#define kUSBSerialBufferLength 256

//// USB Serial

Serial usbSerial(USBTX, USBRX);

//// DMX

DigitalIn rj45ModeDIN(kMBED_DIN_ETHLO_DMXHI);
DigitalOut dmxDirectionDOUT(kMBED_DOUT_RS485_TXHI_RXLO);
enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit

DMX dmx(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);

//// Display

// SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
SPKDisplay screen(kMBED_OLED_MOSI, kMBED_OLED_SCK, kMBED_OLED_CS, kMBED_OLED_DC, kMBED_OLED_RES, NULL);

//// mbed input

DigitalIn button(kMBED_DIN_TAP_L);
DigitalIn buttonR(kMBED_DIN_TAP_R);
bool buttonLastState;

char usbSerialBuffer[kUSBSerialBufferLength];
int  usbSerialBufferPosition = 0;
bool newStringData = false;
bool newBowData = false;

//// LAUREL VIOLIN DATA

// [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.
int TA, TB; 

// [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
float P1A, P1B, P2A, P2B, P3A, P3B, P4A, P4B;

// [S: A] = signal strength.  A is RMS of audio signal in the buffer.
float S1, S2, S3, S4;

// [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)
float F1, F2, F3, F4;

// [B: A, B, C, D] = raw bow data, A is sensor closest to frog, D closest to tip. 
float B1, B2, B3, B4;

// [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.
float EA, EB;
int EC;

// TOBY VIOLIN EXTRAS
 
float sMaxFixed = 0.1;
float sMultiplier = 255.0/sMaxFixed;

float eMaxFixed = 400;
float eMultiplier = 255.0/eMaxFixed;

void testDMX()
{
    static char state = 1;
    
    if (state == 5)
    {
        dmx.put(kDMX_SPOT_DIMMER, 255);
    }
    else
    {
        dmx.put(kDMX_SPOT_DIMMER, 0);
        
        int address;
        
        switch (state)
        {
            case 1: address = kDMX_PARCAN_1; break;
            case 2: address = kDMX_PARCAN_2; break;
            case 3: address = kDMX_PARCAN_3; break;
            case 4: address = kDMX_PARCAN_4; break;
        }
        
        unsigned char parCanData[4];
        parCanData[kDMX_PARCAN_R] = 255; 
        parCanData[kDMX_PARCAN_G] = 255; 
        parCanData[kDMX_PARCAN_B] = 255;
        parCanData[kDMX_PARCAN_LUMA] = 0;
        dmx.put(parCanData, kDMX_PARCAN_1, 4);
        dmx.put(parCanData, kDMX_PARCAN_2, 4);
        dmx.put(parCanData, kDMX_PARCAN_3, 4);
        dmx.put(parCanData, kDMX_PARCAN_4, 4);
    
        parCanData[kDMX_PARCAN_LUMA] = 255;
        dmx.put(parCanData, address, 4);
    }
    
    if (++state > 5) state = 1; 
}

inline void processData()
{
    float sMax = S1;
    if (sMax < S2) sMax = S2;
    if (sMax < S3) sMax = S3;
    if (sMax < S4) sMax = S4;
    
    float threshold = sMax * 0.7;
    
    if (S1 < threshold) S1 = 0;
    if (S2 < threshold) S2 = 0;
    if (S3 < threshold) S3 = 0;
    if (S4 < threshold) S4 = 0;    
} 
 
void usbSerialReceive(void) 
{
    char receivedChar;
 
    //if data is ready in the buffer
    while (usbSerial.readable()) 
    {
        receivedChar = usbSerial.getc();
 
        // Is end of line?
        if (receivedChar == '\n' || receivedChar == '\r')
        {
            // [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]            
            int scanCount;
//            scanCount = sscanf(
//                                usbSerialString.c_str(), 
//                                "[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]",
//                                &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
//                               );
//            if (scanCount == 25)
            scanCount = sscanf(
                                usbSerialBuffer, 
                                "[S: %f, %f, %f, %f],[E: %f, %f, %d]",
                                &S1, &S2, &S3, &S4, &EA, &EB, &EC
                               );
            
            if (scanCount == 7)
            {
                newStringData = true;
                newBowData = true;
                processData();
            }
            else if (scanCount == 4)
            {
                newStringData = true;
                processData();    
            }
            else
            {
                screen.textToBuffer("Read vars failed", 6);        
            }   
            
            // Clear to start again
            usbSerialBufferPosition = 0;
        }
        else if (usbSerialBufferPosition < kUSBSerialBufferLength)
        {
            // Build string up
            usbSerialBuffer[usbSerialBufferPosition++] = receivedChar;
            usbSerialBuffer[usbSerialBufferPosition] = 0;
            
            screen.textToBuffer(usbSerialBuffer,4);
        }
    }
}

////  M A I N
int main() {

    // Set display font
    screen.fontStartCharacter = &characterBytesStartChar;
    screen.fontEndCharacter = &characterBytesEndChar;
    screen.fontCharacters = characterBytes;
    
    // Splash screen
    screen.imageToBuffer(spkDisplayLogo);
    screen.textToBuffer("SPK:DMXer",0);
    screen.textToBuffer("FRATRES 2015",1);
    screen.textToBuffer("SW v01",2);
    screen.sendBuffer();
    
    if (rj45ModeDIN == rj45DMX) screen.textToBuffer("RJ45: DMX Mode", 3);
    else screen.textToBuffer("RJ45: Ethernet Mode", 3);
    screen.sendBuffer();
    
    dmxDirectionDOUT = 1;
    dmx.start();

    dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_R, 255);
    dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_G, 255);
    dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_B, 255);
    dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_LUMA, 0);

    dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_R, 255);
    dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_G, 255);
    dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_B, 255);
    dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_LUMA, 0);
        
    dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_R, 255);
    dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_G, 255);
    dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_B, 255);
    dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_LUMA, 0);
    
    dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_R, 255);
    dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_G, 255);
    dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_B, 255);
    dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_LUMA, 0);

    dmx.put(kDMX_PAN, 50);
    
    //// Serial
    usbSerial.baud(kUSB_BAUD);
    usbSerial.attach(usbSerialReceive);

    //// TASK: Prime button change detection
    buttonLastState = button;

    //// TASK: GO!

    // We've finished setting up, now loop this forever...
    while (true) 
    {            
        if (newStringData)
        {   
            char S1DMX = S1 * sMultiplier;
            char S2DMX = S2 * sMultiplier;
            char S3DMX = S3 * sMultiplier;
            char S4DMX = S4 * sMultiplier;        
            
            unsigned char parCanData[4];
            parCanData[kDMX_PARCAN_R] = 255; 
            parCanData[kDMX_PARCAN_G] = 255; 
            parCanData[kDMX_PARCAN_B] = 255;
            
            parCanData[kDMX_PARCAN_LUMA] = S1DMX;
            dmx.put(parCanData, kDMX_PARCAN_1, 4);
             
            parCanData[kDMX_PARCAN_LUMA] = S2DMX;
            dmx.put(parCanData, kDMX_PARCAN_2, 4);
            
            parCanData[kDMX_PARCAN_LUMA] = S3DMX;            
            dmx.put(parCanData, kDMX_PARCAN_3, 4);
            
            parCanData[kDMX_PARCAN_LUMA] = S4DMX;
            dmx.put(parCanData, kDMX_PARCAN_4, 4);
            
            char dmxSummary[kStringBufferLength];
            snprintf(dmxSummary, kStringBufferLength, "S %03u %03u %03u %03u", S1DMX, S2DMX, S3DMX, S4DMX);
            screen.textToBuffer(dmxSummary,6);
            
            newStringData = false;
        }
        
        if (newBowData)
        {
            // EA = Position, EB = Pressure, EC = On string
            if (EB < 0) EB = 0;
            char bowDMX = EB * eMultiplier;
            if (EC) 
            {
                dmx.put(kDMX_SPOT_DIMMER, bowDMX);
            }
            else
            {
                dmx.put(kDMX_SPOT_DIMMER, 0);
            }
            
            dmx.put(kDMX_TILT_MSB, 15 + EA * 50);
        }
        
        // Has the button changed?
        if (button != buttonLastState) {
            // If so, lets update the lastState variable and then send an OSC message
            buttonLastState = button;
            
            if (button) 
            {
                testDMX();
                screen.textToBuffer("Sent: /mbed/button 1",5);
                //dmx.put(kDMX_HAZER_HAZE, 128);
                //dmx.put(kDMX_HAZER_FAN, 255);
            }
            else        
            {
                screen.textToBuffer("Sent: /mbed/button 0",5);
                dmx.put(kDMX_HAZER_HAZE, 0);
                dmx.put(kDMX_HAZER_FAN, 0);
            }            
        }

        screen.sendBuffer();
    }
}