modded version CNMAT/OSC https://github.com/CNMAT/OSC

Dependents:   CVtoOSCConverter

Fork of osc-cnmat by Asperius van Hansen

Revision:
3:f58c63b78853
Child:
4:107c23eb31b6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OSCBundle.cpp	Sat May 17 12:42:29 2014 +0000
@@ -0,0 +1,340 @@
+/*
+ Written by Yotam Mann, The Center for New Music and Audio Technologies,
+ University of California, Berkeley.  Copyright (c) 2012, The Regents of
+ the University of California (Regents).
+ 
+ Permission to use, copy, modify, distribute, and distribute modified versions
+ of this software and its documentation without fee and without a signed
+ licensing agreement, is hereby granted, provided that the above copyright
+ notice, this paragraph and the following two paragraphs appear in all copies,
+ modifications, and distributions.
+ 
+ IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
+ OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+ BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+ REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+ HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ 
+ For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
+ */
+
+#include "OSCBundle.h"
+#include <stdlib.h>
+
+ /*=============================================================================
+    CONSTRUCTORS / DESTRUCTOR
+=============================================================================*/
+
+OSCBundle::OSCBundle(uint64_t _timetag){
+    setTimetag(_timetag);
+    numMessages = 0;
+    error = OSC_OK;
+    messages = NULL;
+    incomingBuffer = NULL;
+    incomingBufferSize = 0;
+    decodeState = STANDBY;
+}
+
+OSCBundle::~OSCBundle(){
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage * msg = getOSCMessage(i);
+        delete msg;
+    }
+    free(messages);
+    free(incomingBuffer);
+}
+
+//clears all of the OSCMessages inside
+void OSCBundle::empty(){
+    error = OSC_OK;
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage * msg = getOSCMessage(i);
+        delete msg;
+    }
+    free(messages);
+    messages = NULL;
+    clearIncomingBuffer();
+    numMessages = 0;
+}
+
+/*=============================================================================
+ SETTERS
+ =============================================================================*/
+
+OSCMessage & OSCBundle::add(char * _address){
+    OSCMessage * msg = new OSCMessage(_address);
+    if (!msg->hasError()){
+        //realloc the array to fit the message
+        OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
+        if (messageMem != NULL){
+            messages = messageMem;
+            messages[numMessages] = msg;
+            numMessages++;
+        } else {
+            error = ALLOCFAILED;
+        }
+    }
+    return *msg;
+}
+
+OSCMessage & OSCBundle::add(){
+    OSCMessage * msg = new OSCMessage();
+    //realloc the array to fit the message
+    OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
+    if (messageMem != NULL){
+        messages = messageMem;
+        messages[numMessages] = msg;
+        numMessages++;
+    } else {
+        error = ALLOCFAILED;
+    }
+    return *msg;
+}
+
+OSCMessage & OSCBundle::add(OSCMessage & _msg){
+    OSCMessage * msg = new OSCMessage(_msg);
+    if (!msg->hasError()){
+        //realloc the array to fit the message
+        OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
+        if (messageMem != NULL){
+            messages = messageMem;
+            messages[numMessages] = msg;
+            numMessages++;
+        } else {
+            error = ALLOCFAILED;
+        }
+    }
+    return *msg;
+}
+
+/*=============================================================================
+    GETTERS
+ =============================================================================*/
+
+//returns the first fullMatch.
+OSCMessage * OSCBundle::getOSCMessage( char * addr){
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage * msg = getOSCMessage(i);
+        if (msg->fullMatch(addr)){
+            return msg;
+        }
+    }
+}
+
+//the position is the same as the order they were declared in
+OSCMessage * OSCBundle::getOSCMessage(int pos){
+    if (pos < numMessages){
+        return messages[pos];
+    }        
+}
+
+/*=============================================================================
+    PATTERN MATCHING
+ =============================================================================*/
+
+
+bool OSCBundle::dispatch(const char * pattern, void (*callback)(OSCMessage&), int initial_offset){
+    bool called = false;
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage msg = getOSCMessage(i);
+        called |= msg.dispatch(pattern, callback, initial_offset);
+    }
+    return called;
+}
+
+
+bool OSCBundle::route(const char * pattern, void (*callback)(OSCMessage&, int), int initial_offset){
+    bool called = false;
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage msg = getOSCMessage(i);
+        called |= msg.route(pattern, callback, initial_offset);
+    }
+    return called;
+}
+
+/*=============================================================================
+    SIZE
+ =============================================================================*/
+
+
+int OSCBundle::size(){
+    return numMessages;
+}
+
+/*=============================================================================
+ ERROR HANDLING
+ =============================================================================*/
+
+bool OSCBundle::hasError(){
+    bool retError = error != OSC_OK;
+    //test each of the data
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage * msg = getOSCMessage(i);
+        retError |= msg->hasError();
+    }
+    return retError;
+}
+
+OSCErrorCode OSCBundle::getError(){
+    return error;
+}
+
+
+/*=============================================================================
+ SENDING
+ =============================================================================*/
+
+/*void OSCBundle::send(Print &p){
+    //don't send a bundle with errors
+    if (hasError()){
+        return;
+    }
+    //write the bundle header
+    static uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0};
+    p.write(header, 8);
+    //write the timetag
+    uint64_t t64 = BigEndian(timetag);
+    uint8_t * tptr = (uint8_t *) &t64;
+    p.write(tptr, 8);
+    //send the messages
+    for (int i = 0; i < numMessages; i++){
+        OSCMessage * msg = getOSCMessage(i);
+        int msgSize = msg->bytes();
+        //turn the message size into a pointer
+        uint32_t s32 = BigEndian((uint32_t) msgSize);
+        uint8_t * sptr = (uint8_t *) &s32;
+        //write the messsage size
+        p.write(sptr, 4);
+        msg->send(p);
+    }
+}*/
+
+/*=============================================================================
+    FILLING
+ =============================================================================*/
+
+void OSCBundle::fill(uint8_t incomingByte){
+    decode(incomingByte);
+}
+
+void OSCBundle::fill(uint8_t * incomingBytes, int length){
+    while (length--){
+        decode(*incomingBytes++);
+    }
+}
+
+/*=============================================================================
+    DECODING
+ =============================================================================*/
+
+void OSCBundle::decodeTimetag(){
+    //parse the incoming buffer as a uint64
+    setTimetag(incomingBuffer);
+    //make sure the endianness is right
+    timetag = BigEndian(timetag);
+    decodeState = MESSAGE_SIZE;
+    clearIncomingBuffer();
+}
+
+void OSCBundle::decodeHeader(){
+    const char * header = "#bundle";
+    if (strcmp(header, (char *) incomingBuffer)!=0){
+        //otherwise go back to the top and wait for a new bundle header
+        decodeState = STANDBY;
+        error = INVALID_OSC;
+    } else {
+        decodeState = TIMETAG;
+    }
+    clearIncomingBuffer();
+}
+
+void OSCBundle::decodeMessage(uint8_t incomingByte){
+    //get the current message
+    if (numMessages > 0){
+       OSCMessage * lastMessage = messages[numMessages - 1];
+        //put the bytes in there
+        lastMessage->fill(incomingByte);
+        //if it's all done
+        if (incomingBufferSize == incomingMessageSize){
+            //move onto the next message
+            decodeState = MESSAGE_SIZE;
+            clearIncomingBuffer();
+        } else if (incomingBufferSize > incomingMessageSize){
+            error = INVALID_OSC;
+        }
+    }
+}
+
+//does not validate the incoming OSC for correctness
+void OSCBundle::decode(uint8_t incomingByte){
+    addToIncomingBuffer(incomingByte);
+    switch (decodeState){
+        case STANDBY:
+            if (incomingByte == '#'){
+                decodeState = HEADER;
+            } else if (incomingByte == '/'){
+                decodeState = MESSAGE;
+            }
+            break;
+        case HEADER:
+            if (incomingBufferSize == 8){
+                decodeHeader();
+                decodeState = TIMETAG;
+            }
+            break;
+        case TIMETAG:
+            if (incomingBufferSize == 8){
+                decodeTimetag();
+                decodeState = MESSAGE_SIZE;
+            }
+            break;
+        case MESSAGE_SIZE:
+            if (incomingBufferSize == 4){
+                //make sure the message size is valid
+                int32_t msgSize;
+                memcpy(&msgSize, incomingBuffer, 4);
+                msgSize = BigEndian(msgSize);
+                if (msgSize % 4 != 0 || msgSize == 0){
+                    error = INVALID_OSC;
+                } else {
+                    //add a message to the buffer
+                    decodeState = MESSAGE;
+                    incomingMessageSize = msgSize;
+                    clearIncomingBuffer();
+                    //add a new empty message
+                    add();
+                }
+            }
+            break;
+        case MESSAGE:
+            decodeMessage(incomingByte);
+            break;
+    }
+}
+
+
+/*=============================================================================
+ INCOMING BUFFER MANAGEMENT
+ =============================================================================*/
+
+void OSCBundle::addToIncomingBuffer(uint8_t incomingByte){
+    //realloc some space for the new byte and stick it on the end
+    incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1);
+    if (incomingBuffer != NULL){
+        incomingBuffer[incomingBufferSize++] = incomingByte;
+    } else {
+        error = ALLOCFAILED;
+    }
+}
+
+void OSCBundle::clearIncomingBuffer(){
+    incomingBufferSize = 0;
+    free(incomingBuffer);
+    incomingBuffer = NULL;
+}
+