|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /*
- 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(osctime_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
- OSCBundle& 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;
- return *this;
- }
-
- /*=============================================================================
- SETTERS
- =============================================================================*/
-
- OSCMessage & OSCBundle::add(const 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;
- }
- }
- return NULL;
- }
-
- //the position is the same as the order they were declared in
- OSCMessage * OSCBundle::getOSCMessage(int pos){
- if (pos < numMessages){
- return messages[pos];
- }
- return NULL;
- }
-
- /*=============================================================================
- 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) || called ;
- }
- 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) || called;
- }
- 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
- =============================================================================*/
-
- OSCBundle& OSCBundle::send(Print &p){
- //don't send a bundle with errors
- if (hasError()){
- return *this;
- }
- //write the bundle header
- static uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0};
- p.write(header, 8);
- //write the timetag
- {
- osctime_t time = timetag;
- uint32_t d = BigEndian(time.seconds);
- uint8_t * ptr = (uint8_t *) &d;
- p.write(ptr, 4);
- d = BigEndian(time.fractionofseconds);
- ptr = (uint8_t *) &d;
- p.write(ptr, 4);
- }
-
- //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);
- }
- return *this;
- }
-
- /*=============================================================================
- FILLING
- =============================================================================*/
-
- OSCBundle& OSCBundle::fill(uint8_t incomingByte){
- decode(incomingByte);
- return *this;
- }
-
- OSCBundle& OSCBundle::fill(uint8_t * incomingBytes, int length){
- while (length--){
- decode(*incomingBytes++);
- }
- return *this;
- }
-
- /*=============================================================================
- DECODING
- =============================================================================*/
-
- void OSCBundle::decodeTimetag(){
- //parse the incoming buffer as a uint64
- setTimetag(incomingBuffer);
- //make sure the endianness is right
- //xxx time tag 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;
- }
-
-
-
|