![](/media/cache/profiles/68a15b5278e4f7c4c056df9d5f1d3b1f.jpg.50x50_q85.jpg)
save loops
Diff: mbedOSC.cpp
- Revision:
- 0:df6fdd9b99f0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbedOSC.cpp Tue Dec 02 04:39:15 2014 +0000 @@ -0,0 +1,638 @@ +/* + mbedOSC.cpp +*/ + +#include "mbed.h" +#include "mbedOSC.h" +#include "stdarg.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_RECEIVE_PORT, NULL); +} + +/* + Set PortNo for the OSC Message + @param[in] _port PortNo (unsigned int) + @return None + */ +void OSCMessage::setPort(uint16_t _port){ + host.setPort(_port); +} + +/* + Set IP Address of the OSC Message (for SENDING messages - for receiving this will be done when receiving something ) + param[in] <-- _ip pointer of IP Address array (byte *) + Example: IP=192.168.0.99, then we have to do: ip[]={192,168,0,1}, then setIp(ip) + */ +void OSCMessage::setIp(uint8_t *_ip){ + host.setIp(IpAddr(_ip[0], _ip[1], _ip[2], _ip[3])); +} + + +/*! + Set IP Address to the OSC Message container (not through pointer) + Example: IP=192.168.0.99 => setIp(192,168,0,99) + */ +void OSCMessage::setIp( uint8_t _ip1, + uint8_t _ip2, + uint8_t _ip3, + uint8_t _ip4 ){ + + host.setIp(IpAddr(_ip1, _ip2, _ip3, _ip4)); +} + +const IpAddr& OSCMessage::getIp(){ + return host.getIp(); +} + + + const int& OSCMessage::getPort(){ + return host.getPort(); +} + + +/* + Gets the number of the OSC message address + param[in] None + return number of the OSC message address (byte) + Examples: "/ard" --> the number of the addresses is 1 + "/ard/test" --> the number of the addresses is 2 + Attention: the maximum number of addresses is 2 (MAX_ADDRESS) +*/ +uint8_t OSCMessage::getAddressNum(){ + + return addressNum; +} + + +/* + Gets the number of the OSC message args + param[in] None + return number of the args (byte) + Example: "i" 123 --> number of the OSC message args is 1 + "if" 123 54.24 --> number of the OSC message args is 2 + Attention: the maximum number of args is 2 (MAX_ARG) + */ +uint8_t OSCMessage::getArgNum(){ + + return argNum; +} + + +/* + Gets the address string of the OSC message + param [in] <-- _index is the index of the address string (byte) + return pointer of the address string (char *) + @note ex. "/ard/test"<br> + getAddress(0) = "/ard"<br> + getAddress(1) = "/test" + @attention It is maximum number of the addresses is 2<br> + In this case "/ard/test1/test2"<br> + ignore it after "/test2" + */ +char * OSCMessage::getAddress(uint8_t _index){ + if(_index>MAX_ADDRESS) _index=MAX_ADDRESS-1; + return address[_index]; + +} + + +/* + Gets the TopAddress string of the OSC message (this is just the address with index 0) + param[in] None + return pointer of the TopAddress string (char *), i.e. address[0] + Example: In the case "/ard/test", getTopAddress() = "/ard" (WITH the slash "/") + */ +char * OSCMessage::getTopAddress(){ + + return getAddress(0); + +} + +/* + Gets the "SubAddress" string of the OSC message (this is just the address with index 1) + param[in] None + return pointer of the SubAddress string (char *), i.e. address[1] + Example: in the case "/ard/test", getSubAddress() = "/test" (WITH the slash "/") + */ +char * OSCMessage::getSubAddress(){ + + return getAddress(1); + +} + +/* + Gets the TypeTag string (with index) of the OSC message + param[in] <--_index is the index of the TypeTag string (byte) + return: TypeTag char (char) + Example: in the case of a total typetag string equal to "if", getTypeTag(0) = 'i' and getTypeTag(1) = 'f' + Attention: MAX_ARG is maximum number of the args, if the index argument is larger, it will be constrained to this max. + */ +char OSCMessage::getTypeTag(uint8_t _index){ + if(_index>MAX_ARG) _index=MAX_ARG-1; + return typeTag[_index]; +} + +/* + Get the args of the OSC message with an integer value + param[in] <--_index is (an int, or uint8_t), corresponding to the index of the args (byte) + return: integer value (long, or int32_t) + Example: in the case "if" 123 54.24, getArgInt(0) = 123 + Noe: "i" is integer, but the return type is "long" + Note: When a index is bigger than the number of the args, it is set to the number of the args + */ +int32_t OSCMessage::getArgInt(uint8_t _index){ + int32_t *value; + if(_index > argNum) _index=argNum; + value = (int32_t *)arg[_index]; // cast to int32_t + return *value; +} + +/* + Get the args of the OSC message with a float value + param[in] <--_index is the index of the args + return: float value (double) + note: In this case "if" 123 54.24, getArgFloat(1) = 54.24 + attention: arg declared as float, but return value cast as "double" + attention: When index is bigger than the number of the args, it is set to the number of the args + */ +double OSCMessage::getArgFloat(uint8_t _index){ + double *value; + if(_index > argNum) _index=argNum; + value = (double *)arg[_index]; + return *value; +} + +/* + Set TopAddress string of OSC Message + param[in] <-- _address is a string pointer for the TopAddress String (char *). NOTE: is this a good idea? why not pass as const, and do allocation here? + return: None + Example: if the complete address string is "/ard/test", we set the topaddress as follows: char top[]="/ard" (allocation done here!), then setTopAddress(top) + */ +void OSCMessage::setTopAddress(char *_address){ + address[0]=_address; + address[1]=0; + addressNum=1; // Note: this "erases" the subaddress! (is this a good idea?) +} + +/* + Set SubAddress string of the OSC Message + param[in] <-- _address is a string pointer for the SubAddress String (char *) + return: None + Example: if the complete address string is "/ard/test", we set the subaddress as follows: char sub[]="/test" (allocation done here!), then setSubAddress(sub) + Attention: we should call first setTopAddress, and then setSubAddress. The order is important. This does not seems like a good idea... + */ +void OSCMessage::setSubAddress(char *_address){ + address[1]=_address; + addressNum=2; // Note: this assumes the top address was already set! +} + + +/* + Set the complete Address string of the OSC Message (top and sub addresses) + param[in] <-- _topAddress and _subAddress are the string pointers to top and sub addresses (char *) + return: None + Example: in the case "/ard/test", we need to do: char top[]="/ard", char sub[]="/test", and then setAddress(top,sub) + Reminder: in this implementation, the maximum number of addresses is MAX_ADDRESS=2 + */ +void OSCMessage::setAddress(char *_topAddress,char *_subAddress){ + setTopAddress(_topAddress); + setSubAddress(_subAddress); + addressNum=2; // (unnecessary...) +} + +/* + Set address string using index (here 0 or 1) + Example: "/ard/test", char adr[]="/ard", setAddress(0,adr), char adr2[]="/test", setAddress(1,adr) + */ +void OSCMessage::setAddress(uint8_t _index, char *_address){ + if(_index>MAX_ADDRESS) _index=MAX_ADDRESS-1; + address[_index]=_address; + addressNum=_index+1; +} + + +/* + Set TypeTag and args to the OSC Message container + @param[in] types TypeTag string "i"(integer) or"f"(float) (char *) + @param[in] ... Pointer of the Args(variable argument) .. + @return None + @Example: + (1) integer 123: (NOTE: integers are LONG) + long v1=123; sendMes.setArgs("i",&v1) + (2)integer:123 and float:52.14 + long v1=123; double v2=52.14; sendMes.setArgs("if",&v1,&v2) + Attention: in this implementation, the maximum number of the args is 2 + (if setArgs("iff",&v1,&v2,&v3), data is ignored after &v3) + */ +void OSCMessage::setArgs(char *types,...){ + + va_list argList; + + argNum = strlen(types); + if(argNum>MAX_ARG) argNum=MAX_ARG-1; + + va_start( argList, types ); + for(uint8_t i=0 ; i < argNum ; i++){ + + typeTag[i]=types[i]; + + switch(types[i]) { + case 'i': + arg[i]=(uint32_t *)va_arg(argList, uint32_t *); + break; + case 'f': + arg[i]=va_arg(argList, double *); + break; + // case 'b': // blob + // arg[i]=va_arg(argList, double *); + // break; + } + + } + +} + +void OSCMessage::clearArgs() { + argNum=0; +} + +// ================================================================================================================================================ +// ==================================== 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(){ + newMessage=false; +} + +/* + This sets "binds" the received message to the receiver container of the communication object + param[in]<--_mes is a pointer to the "receiveing" OSC message (OSCMessage *) + */ +OSCClass::OSCClass(OSCMessage *_mes){ + receiverMessage = _mes; // note: receiverMessage MUST be a pointer to the message, because we will modify things in it + newMessage=false; +} + +/* + This initializes the OSC communication object with default receiving port (DEFAULT_REC_PORT) + param[in]: None + return: None + */ +void OSCClass::begin(void (*pcallbackOnPacketArrival)(UDPSocketEvent)) +{ + // setup receiver udp socket, as well as callback function: + udpRec.bind(receiverMessage->host); + udpRec.setOnEvent(pcallbackOnPacketArrival); // note: onUDPSocketEvent is a member of OSCClass +} + +/* + Initialize an OSC object with arbitrary listening port + param[in] <-- _recievePort, is the listening ("receiving") Port No (unsigned int) + return: None + */ +void OSCClass::begin(uint16_t _recievePort, void (*pcallbackOnPacketArrival)(UDPSocketEvent)) +{ + receiverMessage->host.setPort(_recievePort); + // setup receiver udp socket, as well as callback function: + udpRec.bind(receiverMessage->host); + udpRec.setOnEvent(pcallbackOnPacketArrival); +} + +/* + Set a OSC receive message container + param[in] _mes Pointer to the OSC receive message container (OSCMessage *) + return None + */ +void OSCClass::setReceiveMessage(OSCMessage *_mes){ + receiverMessage = _mes; +} + +/* + callback function when an upd message arrives (it will be transformed as OSC message) + */ +void OSCClass::onUDPSocketEvent(UDPSocketEvent e) +{ + switch(e) + { + case UDPSOCKET_READABLE: //The only event for now + //char buf[256] = {0}; + Host auxhost; + buflength = udpRec.recvfrom( rcvBuff, 256, &auxhost ); // QUESTION: auxhost should be equal to the receiver host I guess... + if ( buflength > 0 ) { + //printf("\r\nFrom %d.%d.%d.%d:\r\n", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]); + decodePacket(receiverMessage); // convert to OSC message, and save it in receiverMessage + newMessage=true; + } + break; + } +} + +/* + Decode UDP packet and save it in the OSCMessage structure + */ +void OSCClass::decodePacket( OSCMessage *_mes) { + + //uint16_t lenBuff; + uint8_t d; + uint8_t messagePos=0; + uint8_t adrCount=0; + uint8_t adrMesPos=0; + uint8_t packetCount=0; + uint8_t packetPos=4; + + + //W5100.writeSn(socketNo, SnIR, SnIR::RECV); + //lenBuff=recvfrom(socketNo, rcvBuff, 1, receiverMessage->ip, &receiverMessage->port); + + 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(int i=0;i<tempArgNum;i++){ + + adrMesPos=3; + + receiverMessage->arg[i]=tempArg[i]; + + for(int j=0;j<4;j++){ + + tempArg[i][adrMesPos]=rcvBuff[messagePos]; + + messagePos++; + adrMesPos--; + } + + } + + +} + + +/* + Get the received OSC message (note: this is another way to access the message directly from the OSCClass object). + The advantage is that we will signal that we read the message, and will be able to query if a NEW message arrived + (Alternatively, one could have a function pointer to pass to the OSC object, that will be called each time a new packet is received: TO DO) + */ +OSCMessage * OSCClass::getMessage(){ + newMessage=false; // this indicate the user READ the message + return receiverMessage; +} + +/* + Send an OSC Message (message contain the host ip and port where the message data has to be sent) + param[in] _mes Pointer to the OSC message container (OSCMessage *) + return None + */ +void OSCClass::sendOsc( OSCMessage *_mes ) +{ + uint8_t lengthEnd; + uint8_t lengthStart; + char buff[128]; + + sendContainer = _mes; + + //バッファ初期値 + buff[0]=0; + + //1) Add name spaces: + for(int 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=strlen(buff); + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + lengthStart=lengthEnd; + + //2) Add TypeTag: + buff[lengthEnd++]=','; // Note: type tag is for instance: ",if" + for(int 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(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + //3) add argument values (Note: here only big endian, this is, FIRST the MOST SIGNIFICANT BYTE): + uint8_t *v; + for(int i=0;i<sendContainer->argNum;i++){ + uint8_t valuePos=3; + v=(uint8_t *)sendContainer->arg[i]; + + buff[lengthEnd++]=v[valuePos--]; + buff[lengthEnd++]=v[valuePos--]; + buff[lengthEnd++]=v[valuePos--]; + buff[lengthEnd++]=v[valuePos]; + + } + + //4) Send udp packet: + //sendto( socketNo, (uint8_t *)buff, lengthEnd, sendContainer->ip, sendContainer->port ); + udpSend.sendto(buff , lengthEnd, &(sendContainer->host)); +} + +// this is bad, should be integrated on the above, but no time: +void OSCClass::sendOscBlob( uint8_t * myblob, int sizeblob, OSCMessage *_mes ) +{ + + // esto es mamarrachezco: + sendContainer = _mes; + + uint8_t lengthEnd; + uint8_t lengthStart; + + char buff[50+sizeblob]; + buff[0]=0; + + //1) Add name spaces (will be just '/posblob' for the blob) + strcat(buff,"/posblob"); + + // pad with 0s to align in multiples of 4: + lengthStart=strlen(buff); + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + lengthStart=lengthEnd; + + //2) Add TypeTag: + buff[lengthEnd++]=','; //here type tag is just ",b" (one blob) + buff[lengthEnd++]='b'; + + // pad with 0s to align in multiples of 4: + lengthStart=lengthEnd; + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + //3) add blob (Note: here it is up to the user to get the values right - big endian?): + // First the size (as an int32, where the type int32 is a 32-bit big-endian two's complement integer) + buff[lengthEnd++]=0; + buff[lengthEnd++]=0; + buff[lengthEnd++]=0; + buff[lengthEnd++]=(char)sizeblob; // note: the loops always have less than 255 points... + // Add blob data: + memcpy(&(buff[lengthEnd]), myblob, sizeblob); + // pad with 0s to align in multiples of 4: + lengthStart=lengthEnd+sizeblob; + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + //4) Send udp packet: + //sendto( socketNo, (uint8_t *)buff, lengthEnd, sendContainer->ip, sendContainer->port ); + udpSend.sendto(buff , lengthEnd, &(sendContainer->host)); +} + +// NOT FINISHED!!!! +void OSCClass::sendOscString( uint8_t * myblob, int sizeblob, OSCMessage *_mes ) +{ + uint8_t lengthEnd; + uint8_t lengthStart; + + char buff[50+sizeblob]; + buff[0]=0; + + //1) Add name spaces (will be just '/posblob' for the blob) + strcat(buff,"/posString"); + + // pad with 0s to align in multiples of 4: + lengthStart=strlen(buff); + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + lengthStart=lengthEnd; + + //2) Add TypeTag: + buff[lengthEnd++]=','; //here type tag is just ",b" (one blob) + buff[lengthEnd++]='s'; + + // pad with 0s to align in multiples of 4: + lengthStart=lengthEnd; + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + // Add blob data: + memcpy(&(buff[lengthEnd]), myblob, sizeblob); + // pad with 0s to align in multiples of 4: + lengthStart=lengthEnd+sizeblob; + lengthEnd=lengthStart+(4-(lengthStart%4)); + for(int i=lengthStart ; i<lengthEnd; i++){ + buff[i]=0; + } + + //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() ){} +} +*/ + +/* + Stop OSC communication (in fact, only the receiver - the server side) + */ +void OSCClass::stop() { + //close( socketNo ); + udpSend.resetOnEvent(); // disables callback +} + +