KAMUI OSC-CV Example refer to OSCReceiver by xshige http://mbed.org/users/xshige/programs/OSCReceiver/

Dependencies:   NetServices TextLCD mbed

main.cpp

Committer:
radiojunkbox
Date:
2012-05-06
Revision:
0:eabe87e89290

File content as of revision 0:eabe87e89290:

//-------------------------------------------------------------
// KAMUI OSC-CV Exapmple
//   referred to xshige's OSCReceiver
//   http://mbed.org/users/xshige/programs/OSCReceiver/
// Copyright (C) 2012 RJB RadioJunkBox
// Released under the MIT License: http://mbed.org/license/mit
//-------------------------------------------------------------

#include "mbed.h"
#include "TextLCD.h"
#include "EthernetNetIf.h"
#include "UDPSocket.h"
#include "OSCReceiver.h"
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

//-------------------------------------------------------------
// Define

#define AD5551                      // 14bitDAC

#define SPI_RATE            1000000 // 1Mbps
#define MIDI_RATE           31250   // 31.25kbps
#define BEEP_FREQ           1760.0  // 1760Hz
#define UPDATE_INTERVAL     100     // 100us
#define SW_WATCH_INTERVAL   (25000/UPDATE_INTERVAL) // 25ms
#define PARAM_GLIDE         6554.0

#define UPDATE_MODE0        0       // Update Interval CV ch1-6 1200us, ch7,8 400us
#define UPDATE_MODE1        1       // Update Interval CV ch1-6 N/A,    ch7,8 200us

#define GATE1               0x01
#define GATE2               0x02
#define GATE3               0x04
#define GATE4               0x08

#define SYNC1CLK            0x01
#define SYNC1RUN            0x02
#define SYNC2CLK            0x04
#define SYNC2RUN            0x08

#define MODE_CV             0x00
#define MODE_GATE           0x40
#define MODE_SYNC           0x80
#define MODE_SET_SYNC       0xC0

#define SW1                 0x01
#define SW2                 0x02
#define SW3                 0x04
#define SW4                 0x08
#define SYNC1CLK_IN         0x10
#define SYNC1RUN_IN         0x20
#define SYNC2CLK_IN         0x40
#define GATE_IN             0x80

#define _ENABLE             0
#define _DISABLE            1

//-------------------------------------------------------------
// Functions

void            InitKamui(void);
void            UpdateCV(void);
unsigned char   CheckSW(unsigned char);

void            SetCV(void);
int             SetupEthNetIf(void);
void            onUDPSocketEvent(UDPSocketEvent);

//-------------------------------------------------------------
// Global Variables

int gUpdateMode;
unsigned short gCV[8];
unsigned char  gGATE;
unsigned char  gSYNC;
unsigned char  gSW;

union {
    unsigned short    WORD;    
    struct {
        unsigned char L;
        unsigned char H; 
    } BYTE;
} gDAC;

float           gGLIDE[8];
float           gOSC_CV[8];

//-------------------------------------------------------------
// mbed Functions

// TextLCD
TextLCD gLCD(p23, p24, p25, p26, p29, p30); // rs, e, d4-d7

// SPI
SPI gSPI(p11,p12,p13);
DigitalOut gCSA(p14);
DigitalOut gCSB(p22);

// Sirial MIDI
//Serial gMIDI(p9,p10);

// AnalogIn
AnalogIn    gAIN1(p15);   // VR1
AnalogIn    gAIN2(p16);   // VR2
AnalogIn    gAIN3(p17);   // VR3
AnalogIn    gAIN4(p18);   // VR4
AnalogIn    gAIN5(p19);   // IN1
AnalogIn    gAIN6(p20);   // IN2

// BEEP
PwmOut gBEEP(p21);

// LED
DigitalOut gLED1(LED1);
DigitalOut gLED2(LED2);
DigitalOut gLED3(LED3);
DigitalOut gLED4(LED4);
BusOut gLEDS(LED1,LED2,LED3,LED4);

// Ticker
Ticker gTICKER;

// Ethernet
EthernetNetIf gEth;
UDPSocket gUdp;

//-------------------------------------------------------------
// main

int main() {

    int i;
    int pot[4],_pot[4];
    unsigned char ch = 0;
    unsigned char mode = 7; // for Intialize
    unsigned char edit[4];
    int val[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

    // Initialize
    for( i=0; i<4; i++) {
        pot[i] = _pot[i] = 0;
        edit[i] = 0;
        gGLIDE[i] = 1.0 / expf(val[i]*656.0/PARAM_GLIDE);
        gGLIDE[i+4] = 1.0 / expf(val[i+4]*656.0/PARAM_GLIDE);
    }
    gSW = SW4; // for Intialize
    
    InitKamui();
    if(SetupEthNetIf() == -1)
    {
        gBEEP.write(0.5);
        wait(1);
        gBEEP.write(0.0);
        return -1;
    }

    // loop
    while(1) {
    
        // Ethernet Polling
        Net::poll();

        // Read pot
        pot[0] =  gAIN1.read_u16();
        pot[1] =  gAIN2.read_u16();
        pot[2] =  gAIN3.read_u16();
        pot[3] =  gAIN4.read_u16();
        
        // change pot amount?
        if(abs(pot[ch] - _pot[ch]) > 0x2000) edit[ch] = 1;

        if(edit[ch]) {
            switch(mode) {
                case 0:
                    gGLIDE[ch] = 1.0 / expf(pot[ch]/PARAM_GLIDE);
                    val[ch] = pot[ch] / 656;
                    break;
                case 1:
                    gGLIDE[ch+4] = 1.0 / expf(pot[ch]/PARAM_GLIDE);
                    val[ch+4] = pot[ch] / 656;
                    break;
                default:
                    break;
            }
        }
        
        // Push Mode SW
        if(gSW & SW4) {
            mode++;
            mode &= 0x01;                      
            for( i=0; i<4; i++) {
                _pot[i] = pot[i];
                edit[i] = 0;
            }
        }
        gSW = 0;

        // LCD Display
        gLCD.locate( 0, 1 );
        switch(mode) {
            case 0:
                gLCD.printf("G1-4 %02d %02d %02d %02d",
                    val[0], val[1], val[2], val[3]);
                break;
            case 1:
                gLCD.printf("G5-8 %02d %02d %02d %02d",
                    val[4], val[5], val[6], val[7]);
                break;
        }

        ch++;
        ch &= 0x03;
    }
}

//-------------------------------------------------------------
// Initialize KAMUI

void InitKamui()
{
    // Init. Variables
    for( int i=0; i<8; i++) {
        gCV[i] = 0x8000;
    }
    gGATE = 0;
    gSYNC = 0;

    gUpdateMode = UPDATE_MODE0;
  
    // Init. SPI
    gCSA = _DISABLE;
    gCSB = _DISABLE;
    gSPI.format(8,0);
    gSPI.frequency(SPI_RATE);

    // Init. Serial MIDI
//    gMIDI.baud(MIDI_RATE);
    
    // Ticker
    gTICKER.attach_us(&UpdateCV, UPDATE_INTERVAL);

    // Beep
    gBEEP.period(1.0/BEEP_FREQ);
    gBEEP.write(0.5);
    wait(0.2);
    gBEEP.write(0.0);

    // Init Display
    gLCD.locate( 0, 0 );
              // 123456789ABCDEF
    gLCD.printf("OSC-CV Example ");
}

//-------------------------------------------------------------
// Update CV, GATE, SYNC

void UpdateCV()
{ 
    unsigned char rcv,ch;
    unsigned char ptn[] = { 0,1,6,7,2,3,6,7,4,5,6,7 };
    const int numptn = (sizeof ptn / sizeof ptn[0]) - 1;
    static unsigned char  cnt;

    __disable_irq();

    // SET DAC 
    ch = ptn[cnt];
    if(gUpdateMode) ch |= 0x06;

#ifdef AD5551 // 14bitDAC
    gDAC.WORD = gCV[ch] >> 2;
#else
    gDAC.WORD = gCV[ch];    
#endif
    
    gCSA = _ENABLE;
    gSPI.write(gDAC.BYTE.H);
    gSPI.write(gDAC.BYTE.L);
    gCSA = _DISABLE;        

    // GATE or SYNC OUT
    if(cnt & 0x01) {
        // GATE OUT
        gCSB = _ENABLE;
        rcv = gSPI.write(gGATE | MODE_GATE) & 0x0F;
        gCSB = _DISABLE;
    }
    else {
        // SYNC OUT
        gCSB = _ENABLE;
        rcv = gSPI.write(gSYNC | MODE_SYNC);
        gCSB = _DISABLE;
    }

    // SEL CV CHANNEL
    gCSB = _ENABLE;
    gSPI.write(ch);
    gCSB = _DISABLE;

    cnt < numptn ? cnt++ : cnt = 0;

    __enable_irq();

    gSW |= CheckSW(rcv);
    SetCV();
}

//-------------------------------------------------------------
// Check SW

unsigned char CheckSW(unsigned char c) {

    static unsigned char  swbuf[2];
    static unsigned int   cntsw;
    unsigned char ret = 0;

    if(cntsw > SW_WATCH_INTERVAL) {
        if(c &= 0x0F) {
            if(!swbuf[1]) {
                if( swbuf[0] == c) {
                    swbuf[1] = c;
                    ret = c;
                }
                else {
                    swbuf[0] = c;
                }
            }
        }
        else {
            swbuf[1] = 0;
            swbuf[0] = 0;
        }
        cntsw = 0;
    }
    cntsw++;
    return ret;
}

//-------------------------------------------------------------
// Set CV

void SetCV()
{
    static unsigned char ch;
    static float cvf[8];
    unsigned int cv;
    
    // Calculate CV
    cvf[ch] = (gOSC_CV[ch] - cvf[ch]) * gGLIDE[ch] + cvf[ch];       
    cv = (unsigned int)cvf[ch] + 0x8000;
    if(cv > 0xFFFF) cv = 0xFFFF;
    gCV[ch] = cv;

    ch++;
    ch &= 0x07;
}

//-------------------------------------------------------------
// Setup Ethernet port

int SetupEthNetIf()
{
    gLCD.locate( 0, 1 );
    gLCD.printf("Setting up...   ");
//    printf("Setting up...\r\n");

    EthernetErr ethErr = gEth.setup();
    if(ethErr)
    {
        gLCD.locate( 0, 1 );
        gLCD.printf("Error in setup.");
//        printf("Error %d in setup.\r\n", ethErr);
        return -1;
    }
//    printf("Setup OK\r\n");

//    printf("IP address %d.%d.%d.%d\r\n", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]);
    Host broadcast(IpAddr(gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], 255), 12345, NULL);
    gUdp.setOnEvent(&onUDPSocketEvent);
    gUdp.bind(broadcast);

    gLCD.locate( 0, 1 );
    gLCD.printf("%03d.%03d.%03d.%03d", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]);
    wait(2.0);
    
    return 0;
}

//-------------------------------------------------------------
// Handller receive UDP Packet

void onUDPSocketEvent(UDPSocketEvent e)
{
    union OSCarg msg[10];
    int num;

    switch(e)
    {
        case UDPSOCKET_READABLE: //The only event for now
            char buf[256] = {0};
            Host host;
            
            while( int len = gUdp.recvfrom( buf, 256, &host ) )
            {
                if(len <= 0)  break;
                // printf("\r\nFrom %d.%d.%d.%d:\r\n", 
                // host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]);
      
                getOSCmsg(buf,msg);
//                printf("OSCmsg: %s %s %f %i\r\n", 
//                    msg[0].address, msg[1].typeTag, msg[2].f, msg[2].i);
                
                len = strlen(msg[0].address);
                if(isdigit(msg[0].address[len-1])) num = msg[0].address[len-1] - '0' - 1;
                else num = -1;

                // address pattern CV
                if((strncmp(msg[0].address,"/kamui/cv",9)==0) && (num != -1)) {

                    if(num > 7) break;
                    if(msg[1].typeTag[1] == 'f') gOSC_CV[num] = msg[2].f * 3072.0;
                    if(msg[1].typeTag[1] == 'i') gOSC_CV[num] = msg[2].i * 3072.0;

                    break;
                }

                // address pattern GATE
                if((strncmp(msg[0].address,"/kamui/gate",11)==0) && (num != -1)) {

                    if(num > 3) break;
                        if(msg[2].i) gGATE |=  (0x01 << num);
                        else         gGATE &= ~(0x01 << num);

                    break;
                }
            
                //  printf("undefined OSCmsg:%s %s\r\n",msg[0].address, msg[1].typeTag);
        }
        break;
    }
}