support OSC-string

Dependents:   OSCtoCVConverter

Fork of OSC by Toby Harris

mbedOSC.cpp

Committer:
casiotone401
Date:
2016-03-08
Revision:
8:73bce95a6853
Parent:
7:498455cded21

File content as of revision 8:73bce95a6853:

/*
 mbedOSC.cpp 
*/                    
 
#pragma O3
#pragma Otime
   
#include "mbed.h"
#include "mbedOSC.h"
#include "stdarg.h"
#include <string.h>
 
OSCMessage::OSCMessage() {
 // Initialize host address and port by default (as if this where the receiver message):
 //    host=new Host(IpAddr(10, 0, 0, 1), DEFAULT_RECEIVEport, NULL);
}
 
inline size_t strlength(const char *s) 
{
    size_t len = 0;
    
    for (;;) 
    {
        unsigned x = *(unsigned*)s;
        if ((x & 0xFF) == 0) return len;
        if ((x & 0xFF00) == 0) return len + 1;
        if ((x & 0xFF0000) == 0) return len + 2;
        if ((x & 0xFF000000) == 0) return len + 3;
        s += 4, len += 4;
    }
}

 
const IpAddr& OSCMessage::getIp() {
    
    return host.getIp();
}
 
 
const int& OSCMessage::getPort() {
     
    return host.getPort();
}
 
 
uint8_t OSCMessage::getAddressNum(){
    
    return addressNum;
}
 
 
uint8_t OSCMessage::getArgNum() {
    
    return argNum;
}
 
 
char * OSCMessage::getAddress(uint8_t index) {
    
    if (index > MAX_ADDRESS) {
        
        index = (MAX_ADDRESS - 1);
    }
     
    return address[index];    
}
 
 
char * OSCMessage::getTopAddress() {
    
    return getAddress(0);    
}
 
 
char * OSCMessage::getSubAddress() {
    
    return getAddress(1); 
}
 
 
char OSCMessage::getTypeTag(uint8_t index) {
    
    if (index > MAX_ARG) {
        
      index = (MAX_ARG - 1);  
    }
    
    return typeTag[index];
}
 
 
int OSCMessage::getArgInt(uint8_t index) {

    if (index > argNum) {
        
        index = argNum;  
    }

    return oscArgs[index].i;
}
 
 
float OSCMessage::getArgFloat(uint8_t index) {
    
    if (index > argNum) {
        
        index = argNum;  
    }
    
    return oscArgs[index].f;
}

double OSCMessage::getArgDouble(uint8_t index) {
    
    if (index > argNum) {
        
        index = argNum;  
    }
    
    return oscArgs[index].d;
}

char * OSCMessage::getArgString(uint8_t index) {
    
    if (index > argNum) {
        
        index = argNum;  
    }
    
    return oscArgs[index].s;
}
 
//-------------------------------------------------
// setup SendHost IP&Port
 
void OSCMessage::setIp(uint8_t *ip) {
    
    host.setIp(IpAddr(ip[0], ip[1], ip[2], ip[3]));
}

 
void OSCMessage::setIp( uint8_t ip1,
                        uint8_t ip2,
                        uint8_t ip3,
                        uint8_t ip4 ) {
    
    host.setIp(IpAddr(ip1, ip2, ip3, ip4));
}


void OSCMessage::setPort(uint16_t port) {
    
     host.setPort(port);
}


//-------------------------------------------------
//  Construct  OSC messages 

void OSCMessage::setTopAddress(char * topAddress) {
    
    address[0] = topAddress;
    address[1] = 0;
    addressNum = 1; // Note: this "erases" the subaddress! (is this a good idea?)
}
 
 
void OSCMessage::setSubAddress(char * subAddress) {
    
    address[1] = subAddress;
    addressNum = 2; // Note: this assumes the top address was already set!
}
 
 
void OSCMessage::setAddress(char * topAddress, char *subAddress) {
    
    setTopAddress(topAddress);
    setSubAddress(subAddress);
    
    addressNum = 2; // (unnecessary...)
}
 
 
void OSCMessage::setAddress(uint8_t index, char * oscAddress) {
    
    if (index > MAX_ADDRESS) {
        
      index = (MAX_ADDRESS - 1);  
    }
    
    address[index] = oscAddress;
    addressNum = (index + 1);
}
 
 
 
void OSCMessage::setArgs(char *types,...) {
 
    uint8_t i;
    va_list argList;
    
    argNum = strlength(types);
    
    if (argNum > MAX_ARG) {
        
        argNum = (MAX_ARG - 1);
    } 
    
    va_start(argList, types);
    
    for (i = 0 ; i < argNum ; ++i) {
        
        typeTag[i] = types[i];
        
        switch(types[i]) {
            
            case 's':
                oscArgs[i].s = va_arg(argList, char *);
                break;
 
            case 'i':
                oscArgs[i].i = va_arg(argList, int);
                break;
 
            case 'f':
                oscArgs[i].f = va_arg(argList, double);
                break;
            
            case 'd':
                oscArgs[i].d = va_arg(argList, double);
                break;
                
            default:
                break;
        }   
    }
}
 
// ================================================================================================================================================
// ====================================  OSCClass for sending and receiving OSC messages using UDP protocol =======================================
// ================================================================================================================================================
//The class define an object wrapping the UDP functions to send and receive OSC messages
 
OSCClass::OSCClass() {
    
    udpRec.setOnEvent(this, &OSCClass::onUDPSocketEvent);
    newMessage = false;
}
 
OSCClass::~OSCClass() {
    
    udpSend.resetOnEvent();
    udpRec.close();
}
 
OSCClass::OSCClass(OSCMessage *mes) {
    
    udpRec.setOnEvent(this, &OSCClass::onUDPSocketEvent);
    receiverMessage = mes; // note: receiverMessage MUST be a pointer to the message, because we will modify things in it
    newMessage = false;
}
 
void OSCClass::begin() {    
  // setup receiver udp socket:
  udpRec.bind(receiverMessage->host);
}
 
 
void OSCClass::begin(uint16_t recievePort) {
    
  receiverMessage->host.setPort(recievePort);
  // setup receiver udp socket:
  udpRec.bind(receiverMessage->host);
}
 
 
void OSCClass::setReceiveMessage(OSCMessage *mes) {
    
    receiverMessage = mes;
}
 
void OSCClass::onUDPSocketEvent(UDPSocketEvent e) {
    
  switch(e) {
      
      case UDPSOCKET_READABLE: //The only event for now
      
            buflength = udpRec.recvfrom(rcvBuff, MAX_RECEIVEBUFF_SIZE, &auxhost); // QUESTION: auxhost should be equal to the receiver host I guess...
           
            if (buflength > 0) {
                
                decodePacket(receiverMessage); // convert to OSC message, and save it in receiverMessage
                newMessage = true;
      
                messageReceivedCallback.call();
            }
            break;
        }
}
 
/*
 Decode UDP packet and save it in the OSCMessage structure
 */
void OSCClass::decodePacket(OSCMessage *mes) {
    int i;
    uint8_t        d;    
    uint8_t        messagePos = 0;    
    uint8_t        adrCount = 0;
    uint8_t        adrMesPos = 0;    
    uint8_t        packetCount = 0;
    uint8_t        packetPos = 4;
    
    receiverMessage->address[0] = tempAddress[0];
 
    //(1) address process start =========================================
    do {
        d = rcvBuff[messagePos];
        
        if ( (d == '/') && (messagePos > 0) ) {
 
            if (adrCount < MAX_ADDRESS) {
                
                tempAddress[adrCount][adrMesPos] = 0;
 
                ++adrCount;
                adrMesPos = 0;
 
                receiverMessage->address[adrCount] = tempAddress[adrCount];
            }
 
        }
        
        if (adrCount < MAX_ADDRESS) {
            //Added this in to remove the slashes out of final output
            if (d != '/') {
                
                tempAddress[adrCount][adrMesPos] = d;            
    
                if (packetCount > 3) {
                    
                    packetCount = 0;
                    packetPos += 4;
                }
        
                ++adrMesPos;
            }
        }
        
        ++messagePos;
        ++packetCount;
        
    } while(d != 0);
    
    if (adrCount < MAX_ADDRESS) {
        ++adrCount;  
    }
    
    receiverMessage->addressNum = adrCount;
    
    messagePos = packetPos;
 
    //(2) type tag process starts =========================================
    packetCount = 0;
    packetPos += 4;
 
    uint8_t  typeTagPos = 0;
    uint8_t  tempArgNum = 0;
 
    while(rcvBuff[messagePos] != 0) {
            
        if (rcvBuff[messagePos] != ',') {
            
            if (typeTagPos < MAX_ARG) {
                    
                receiverMessage->typeTag[tempArgNum] = rcvBuff[messagePos];
                ++tempArgNum;
            }
                
            ++typeTagPos;
                
        }
        
        ++packetCount;
        
        if (packetCount > 3) {
            
            packetCount = 0;
            packetPos += 4;
        }
        
        ++messagePos;
    }
    
    receiverMessage->argNum = tempArgNum;
 
    messagePos = packetPos;
 
    //(3) tempArg process starts =========================================
    for (i = 0; i < tempArgNum; ++i) {
        
        adrMesPos = 3;
        
        switch(receiverMessage->typeTag[i]) {
            
            case 's':
                
                receiverMessage->oscArgs[i].s = (char *)tempArg[i];
                break;
 
            case 'i':
                
                union {
                    int i;
                    uint8_t b[4];
                } ui;
                
                memcpy(ui.b, tempArg[i], 4);
                receiverMessage->oscArgs[i].i = ui.i;
                break;
 
            case 'f':
                
                union {
                    float f;
                    uint8_t b[4];
                } uf;
            
                memcpy(uf.b, tempArg[i], 4);
                receiverMessage->oscArgs[i].f = uf.f;
                break;
            
            case 'd':
            
                union {
                    double d;
                    uint8_t b[8];
                } ud;
        
                memcpy(ud.b, tempArg[i], 8);
                receiverMessage->oscArgs[i].d = ud.d;
                break;
                
            default:
                break;
        }
    
        tempArg[i][adrMesPos--] = rcvBuff[messagePos++];
        tempArg[i][adrMesPos--] = rcvBuff[messagePos++];
        tempArg[i][adrMesPos--] = rcvBuff[messagePos++];
        tempArg[i][adrMesPos--] = rcvBuff[messagePos++];
    
    }
}
 

OSCMessage * OSCClass::getMessage() {
    
    newMessage = false; // this indicate the user READ the message
    return receiverMessage;
}
 
 
void OSCClass::sendOsc(OSCMessage *mes) {
    uint8_t i, j = 0;
    uint8_t lengthStart, lengthEnd;   
    char buff[MAX_SENDBUFF_SIZE] = {0};
    
    sendContainer = mes;
    
    //1) Add name spaces:
    for (i = 0; i < sendContainer->addressNum; ++i) {
        
        strcat(buff, sendContainer->address[i]); // note: an address is for instance: "/test" (including the "/")
    }
 
    // pad with 0s to align in multiples of 4:
    lengthStart = strlength(buff);
 
    lengthEnd = lengthStart + (4 - (lengthStart % 4));
    
    for (i = lengthStart; i < lengthEnd; ++i) {
        
        buff[i] = '\0';  
    }

    //2) Add TypeTag:
    buff[lengthEnd++] = ','; // Note: type tag is for instance: ",if"
 
    for (i = 0; i < sendContainer->argNum; ++i) {
        
        buff[lengthEnd++] = sendContainer->typeTag[i];
    }
 
    // pad with 0s to align in multiples of 4:
    lengthStart = lengthEnd;
    
    lengthEnd = lengthStart + (4 - (lengthStart % 4));
    
    for (i = lengthStart; i < lengthEnd; ++i) {
        
        buff[i] = '\0';
    }
    
    //3) add argument values (Note: here only big endian):
    
    for (i = 0; i < sendContainer->argNum; ++i) {
        
        switch (sendContainer->typeTag[i])
        {
            case 's':
    
                while (sendContainer->oscArgs[i].s[j] != '\0') {
        
                    buff[lengthEnd++] = sendContainer->oscArgs[i].s[j++];
                }
    
                // pad with 0s to align in multiples of 4:
                lengthStart = lengthEnd;

                lengthEnd = lengthStart + (4 - (lengthStart % 4));

                for (i = lengthStart; i < lengthEnd; ++i) {

                    buff[i] = '\0';
                }
        
                break;

            case 'i':
            case 'f':
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[3];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[2];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[1];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[0];
                break;
        
            case 'd':
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[7];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[6];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[5];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[4];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[3];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[2];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[1];
                buff[lengthEnd++] = sendContainer->oscArgs[i]._b[0];
                break;

            default:
                break;
    
        }

    }
    
    //4) Send udp packet: 
    //sendto(    socketNo, (uint8_t *)buff, lengthEnd, sendContainer->ip, sendContainer->port );
    udpSend.sendto(buff , lengthEnd, &(sendContainer->host));
}
 
 
/*
 flush a receive buffer
void OSCClass::flush() {    
    while ( available() ){}
}
*/
 
 
void OSCClass::stop() {
    //close( socketNo );
    udpSend.resetOnEvent(); // disables callback
}