(uncpomplete) port of the cnmat osc library for Arduino/Teensy. Upstream url: https://github.com/CNMAT/OSC

(uncpomplete) port of the cnmat osc library for Arduino/Teensy. Upstream url: https://github.com/CNMAT/OSC

Compiles, but not Tested in any kind. OSCMessage::send(); and OSCBundle::send() don't work/are commented out due to Platform specifics I first have to figure out.

Readme

Files at this revision

API Documentation at this revision

Comitter:
aspeteRakete
Date:
Sat May 17 12:42:29 2014 +0000
Parent:
2:61caa2495215
Commit message:
init. Compiles, not tested. OSCMessage::send(Print &p) and OSC::Bundle::send(Print &p) commented out

Changed in this revision

OSCBundle.cpp Show annotated file Show diff for this revision Revisions of this file
OSCBundle.h Show annotated file Show diff for this revision Revisions of this file
--- /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;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OSCBundle.h	Sat May 17 12:42:29 2014 +0000
@@ -0,0 +1,172 @@
+/*
+ Written by Yotam Mann, The Center for New Music and Audio Technologies,
+ University of California, Berkeley.  Copyright (c) 2012, 2013, 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.
+ 
+
+ */
+
+#ifndef OSCBUNDLE_h
+#define OSCBUNDLE_h
+
+#include "OSCMessage.h"
+
+class OSCBundle
+{
+
+private:
+
+/*=============================================================================
+    PRIVATE VARIABLES
+=============================================================================*/
+
+    //the array of messages contained in the bundle
+    OSCMessage ** messages;
+
+    //the number of messages in the array
+    int numMessages;
+    
+    uint64_t timetag;
+    
+    //error codes
+    OSCErrorCode error;
+    
+/*=============================================================================
+ DECODING INCOMING BYTES
+ =============================================================================*/
+    
+    //the decoding states for incoming bytes
+    enum DecodeState {
+        STANDBY,
+        HEADER,
+        TIMETAG,
+        MESSAGE_SIZE,
+        MESSAGE,
+    } decodeState;
+    
+    //stores incoming bytes until they can be decoded
+    uint8_t * incomingBuffer;
+    int incomingBufferSize;
+    
+    //the size of the incoming message
+    int incomingMessageSize;
+    
+    //adds a byte to the buffer
+    void addToIncomingBuffer(uint8_t);
+    //clears the incoming buffer
+    void clearIncomingBuffer();
+    
+    //decoding functions
+    void decode(uint8_t);
+    void decodeTimetag();
+    void decodeHeader();
+    void decodeMessage(uint8_t);
+    
+    //just a placeholder while filling
+    OSCMessage & add();
+
+
+public:
+
+/*=============================================================================
+    CONSTRUCTORS / DESTRUCTOR
+=============================================================================*/
+        
+    //default timetag of 1
+    OSCBundle(uint64_t = 1);
+
+    //DESTRUCTOR
+    ~OSCBundle();
+
+    //clears all of the OSCMessages inside
+    void empty();
+    
+/*=============================================================================
+    SETTERS
+=============================================================================*/
+    
+    //start a new OSC Message in the bundle
+    OSCMessage & add( char * address);
+    //add with nothing in it produces an invalid osc message
+    //copies an existing message into the bundle
+    OSCMessage & add(OSCMessage & msg);
+    
+    template <typename T>
+    void setTimetag(T t){
+        timetag = (uint64_t) t;
+    }
+    //sets the timetag from a buffer
+    void setTimetag(uint8_t * buff){
+        memcpy(&timetag, buff, 8);
+    }
+    
+/*=============================================================================
+    GETTERS
+ =============================================================================*/
+
+    //gets the message the matches the address string
+    //will do regex matching
+    OSCMessage * getOSCMessage(char * addr);
+    
+    //get message by position
+    OSCMessage * getOSCMessage(int position);
+    
+/*=============================================================================
+    MATCHING
+=============================================================================*/
+
+    //if the bundle contains a message that matches the pattern, 
+    //call the function callback on that message
+    bool dispatch(const char * pattern, void (*callback)(OSCMessage&), int = 0);
+    
+    //like dispatch, but allows for partial matches
+    //the address match offset is sent as an argument to the callback
+    bool route(const char * pattern, void (*callback)(OSCMessage&, int), int = 0);
+    
+/*=============================================================================
+     SIZE
+=============================================================================*/
+    //returns the number of messages in the bundle;
+    int size();
+    
+/*=============================================================================
+    ERROR
+ =============================================================================*/
+    
+    bool hasError();
+    
+    OSCErrorCode getError();
+    
+/*=============================================================================
+    SENDING
+ =============================================================================*/
+    
+    //void send(Print &p);
+    
+/*=============================================================================
+    FILLING
+ =============================================================================*/
+    
+    void fill(uint8_t incomingByte);
+    
+    void fill(uint8_t * incomingBytes, int length);
+};
+
+#endif
\ No newline at end of file