(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.
Revision 3:f58c63b78853, committed 2014-05-17
- 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 |
diff -r 61caa2495215 -r f58c63b78853 OSCBundle.cpp --- /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; +} +
diff -r 61caa2495215 -r f58c63b78853 OSCBundle.h --- /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