Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
OSCBundle.cpp
00001 /* 00002 Written by Yotam Mann, The Center for New Music and Audio Technologies, 00003 University of California, Berkeley. Copyright (c) 2012, The Regents of 00004 the University of California (Regents). 00005 00006 Permission to use, copy, modify, distribute, and distribute modified versions 00007 of this software and its documentation without fee and without a signed 00008 licensing agreement, is hereby granted, provided that the above copyright 00009 notice, this paragraph and the following two paragraphs appear in all copies, 00010 modifications, and distributions. 00011 00012 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 00013 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING 00014 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS 00015 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00016 00017 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 00018 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00019 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED 00020 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE 00021 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 00022 00023 For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu 00024 */ 00025 00026 #include "OSCBundle.h" 00027 00028 #include <stdlib.h> 00029 #include <string.h> 00030 00031 /*============================================================================= 00032 CONSTRUCTORS / DESTRUCTOR 00033 =============================================================================*/ 00034 00035 OSCBundle::OSCBundle(osctime_t _timetag){ 00036 setTimetag(_timetag); 00037 numMessages = 0; 00038 error = OSC_OK; 00039 messages = NULL; 00040 incomingBuffer = NULL; 00041 incomingBufferSize = 0; 00042 decodeState = STANDBY; 00043 } 00044 00045 OSCBundle::~OSCBundle(){ 00046 for (int i = 0; i < numMessages; i++){ 00047 OSCMessage * msg = getOSCMessage(i); 00048 delete msg; 00049 } 00050 free(messages); 00051 free(incomingBuffer); 00052 } 00053 00054 //clears all of the OSCMessages inside 00055 OSCBundle& OSCBundle::empty(){ 00056 error = OSC_OK; 00057 for (int i = 0; i < numMessages; i++){ 00058 OSCMessage * msg = getOSCMessage(i); 00059 delete msg; 00060 } 00061 free(messages); 00062 messages = NULL; 00063 clearIncomingBuffer(); 00064 numMessages = 0; 00065 return *this; 00066 } 00067 00068 /*============================================================================= 00069 SETTERS 00070 =============================================================================*/ 00071 00072 OSCMessage & OSCBundle::add(const char * _address){ 00073 OSCMessage * msg = new OSCMessage(_address); 00074 if (!msg->hasError()){ 00075 //realloc the array to fit the message 00076 OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1)); 00077 if (messageMem != NULL){ 00078 messages = messageMem; 00079 messages[numMessages] = msg; 00080 numMessages++; 00081 } else { 00082 error = ALLOCFAILED; 00083 } 00084 } 00085 return *msg; 00086 } 00087 00088 OSCMessage & OSCBundle::add(){ 00089 OSCMessage * msg = new OSCMessage(); 00090 //realloc the array to fit the message 00091 OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1)); 00092 if (messageMem != NULL){ 00093 messages = messageMem; 00094 messages[numMessages] = msg; 00095 numMessages++; 00096 } else { 00097 error = ALLOCFAILED; 00098 } 00099 return *msg; 00100 } 00101 00102 OSCMessage & OSCBundle::add(OSCMessage & _msg){ 00103 OSCMessage * msg = new OSCMessage(&_msg); 00104 if (!msg->hasError()){ 00105 //realloc the array to fit the message 00106 OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1)); 00107 if (messageMem != NULL){ 00108 messages = messageMem; 00109 messages[numMessages] = msg; 00110 numMessages++; 00111 } else { 00112 error = ALLOCFAILED; 00113 } 00114 } 00115 return *msg; 00116 } 00117 00118 /*============================================================================= 00119 GETTERS 00120 =============================================================================*/ 00121 00122 //returns the first fullMatch. 00123 OSCMessage * OSCBundle::getOSCMessage( char * addr){ 00124 for (int i = 0; i < numMessages; i++){ 00125 OSCMessage * msg = getOSCMessage(i); 00126 if (msg->fullMatch(addr)){ 00127 return msg; 00128 } 00129 } 00130 return NULL; 00131 } 00132 00133 //the position is the same as the order they were declared in 00134 OSCMessage * OSCBundle::getOSCMessage(int pos){ 00135 if (pos < numMessages){ 00136 return messages[pos]; 00137 } 00138 return NULL; 00139 } 00140 00141 /*============================================================================= 00142 PATTERN MATCHING 00143 =============================================================================*/ 00144 00145 00146 bool OSCBundle::dispatch(const char * pattern, void (*callback)(OSCMessage&), int initial_offset){ 00147 bool called = false; 00148 for (int i = 0; i < numMessages; i++){ 00149 OSCMessage msg = getOSCMessage(i); 00150 called = msg.dispatch(pattern, callback, initial_offset) || called ; 00151 } 00152 return called; 00153 } 00154 00155 00156 bool OSCBundle::route(const char * pattern, void (*callback)(OSCMessage&, int), int initial_offset){ 00157 bool called = false; 00158 for (int i = 0; i < numMessages; i++){ 00159 OSCMessage msg = getOSCMessage(i); 00160 called = msg.route(pattern, callback, initial_offset) || called; 00161 } 00162 return called; 00163 } 00164 00165 /*============================================================================= 00166 SIZE 00167 =============================================================================*/ 00168 00169 00170 int OSCBundle::size(){ 00171 return numMessages; 00172 } 00173 00174 /*============================================================================= 00175 ERROR HANDLING 00176 =============================================================================*/ 00177 00178 bool OSCBundle::hasError(){ 00179 bool retError = error != OSC_OK; 00180 //test each of the data 00181 for (int i = 0; i < numMessages; i++){ 00182 OSCMessage * msg = getOSCMessage(i); 00183 retError |= msg->hasError(); 00184 } 00185 return retError; 00186 } 00187 00188 OSCErrorCode OSCBundle::getError(){ 00189 return error; 00190 } 00191 00192 00193 /*============================================================================= 00194 SENDING 00195 =============================================================================*/ 00196 00197 OSCBundle& OSCBundle::send(UDPSocket &p, const SocketAddress &address){ 00198 00199 char buff[128]; 00200 uint8_t lengthEnd; 00201 uint8_t lengthStart; 00202 uint8_t nullChar = '\0'; 00203 buff[0]=nullChar; 00204 00205 //don't send a bundle with errors 00206 if (hasError()){ 00207 return *this; 00208 } 00209 //write the bundle header 00210 static const uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0}; 00211 strcat(buff, (char *)header); 00212 lengthEnd=strlen(buff); 00213 00214 // p.write(header, 8); 00215 //write the timetag 00216 { 00217 osctime_t time = timetag; 00218 uint32_t d = BigEndian(time.seconds); 00219 uint8_t * ptr = (uint8_t *) &d; 00220 for(int i = 0; i < 4; i++){ 00221 buff[lengthEnd++]=ptr[i]; 00222 } 00223 // p.write(ptr, 4); 00224 d = BigEndian(time.fractionofseconds); 00225 ptr = (uint8_t *) &d; 00226 for(int i = 0; i < 4; i++){ 00227 buff[lengthEnd++]=ptr[i]; 00228 } 00229 // p.write(ptr, 4); 00230 } 00231 00232 //send the messages 00233 for (int i = 0; i < numMessages; i++){ 00234 OSCMessage * msg = getOSCMessage(i); 00235 int msgSize = msg->bytes(); 00236 //turn the message size into a pointer 00237 uint32_t s32 = BigEndian((uint32_t) msgSize); 00238 uint8_t * sptr = (uint8_t *) &s32; 00239 //write the messsage size 00240 for(int i = 0; i < 4; i++){ 00241 buff[lengthEnd++]=sptr[i]; 00242 } 00243 00244 // p.write(sptr, 4); 00245 msg->send(p, address); 00246 } 00247 p.sendto(address, buff, lengthEnd); 00248 return *this; 00249 } 00250 00251 /*============================================================================= 00252 FILLING 00253 =============================================================================*/ 00254 00255 OSCBundle& OSCBundle::fill(uint8_t incomingByte){ 00256 decode(incomingByte); 00257 return *this; 00258 } 00259 00260 OSCBundle& OSCBundle::fill(const uint8_t * incomingBytes, int length){ 00261 while (length--){ 00262 decode(*incomingBytes++); 00263 } 00264 return *this; 00265 } 00266 00267 /*============================================================================= 00268 DECODING 00269 =============================================================================*/ 00270 00271 void OSCBundle::decodeTimetag(){ 00272 //parse the incoming buffer as a uint64 00273 setTimetag(incomingBuffer); 00274 //make sure the endianness is right 00275 //xxx time tag timetag = BigEndian(timetag); 00276 decodeState = MESSAGE_SIZE; 00277 clearIncomingBuffer(); 00278 } 00279 00280 void OSCBundle::decodeHeader(){ 00281 const char * header = "#bundle"; 00282 if (strcmp(header, (char *) incomingBuffer)!=0){ 00283 //otherwise go back to the top and wait for a new bundle header 00284 decodeState = STANDBY; 00285 error = INVALID_OSC; 00286 } else { 00287 decodeState = TIMETAG; 00288 } 00289 clearIncomingBuffer(); 00290 } 00291 00292 void OSCBundle::decodeMessage(uint8_t incomingByte){ 00293 //get the current message 00294 if (numMessages > 0){ 00295 OSCMessage * lastMessage = messages[numMessages - 1]; 00296 //put the bytes in there 00297 lastMessage->fill(incomingByte); 00298 //if it's all done 00299 if (incomingBufferSize == incomingMessageSize){ 00300 //move onto the next message 00301 decodeState = MESSAGE_SIZE; 00302 clearIncomingBuffer(); 00303 } else if (incomingBufferSize > incomingMessageSize){ 00304 error = INVALID_OSC; 00305 } 00306 } 00307 } 00308 00309 //does not validate the incoming OSC for correctness 00310 void OSCBundle::decode(uint8_t incomingByte){ 00311 addToIncomingBuffer(incomingByte); 00312 switch (decodeState){ 00313 case STANDBY: 00314 if (incomingByte == '#'){ 00315 decodeState = HEADER; 00316 } else if (incomingByte == '/'){ 00317 add();//add a simple message to the bundle 00318 decodeMessage(incomingByte); 00319 decodeState = MESSAGE; 00320 } 00321 break; 00322 case HEADER: 00323 if (incomingBufferSize == 8){ 00324 decodeHeader(); 00325 decodeState = TIMETAG; 00326 } 00327 break; 00328 case TIMETAG: 00329 if (incomingBufferSize == 8){ 00330 decodeTimetag(); 00331 decodeState = MESSAGE_SIZE; 00332 } 00333 break; 00334 case MESSAGE_SIZE: 00335 if (incomingBufferSize == 4){ 00336 //make sure the message size is valid 00337 int32_t msgSize; 00338 memcpy(&msgSize, incomingBuffer, 4); 00339 msgSize = BigEndian(msgSize); 00340 if (msgSize % 4 != 0 || msgSize == 0){ 00341 error = INVALID_OSC; 00342 } else { 00343 //add a message to the buffer 00344 decodeState = MESSAGE; 00345 incomingMessageSize = msgSize; 00346 clearIncomingBuffer(); 00347 //add a new empty message 00348 add(); 00349 } 00350 } 00351 break; 00352 case MESSAGE: 00353 decodeMessage(incomingByte); 00354 break; 00355 } 00356 } 00357 00358 00359 /*============================================================================= 00360 INCOMING BUFFER MANAGEMENT 00361 =============================================================================*/ 00362 00363 void OSCBundle::addToIncomingBuffer(uint8_t incomingByte){ 00364 //realloc some space for the new byte and stick it on the end 00365 incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1); 00366 if (incomingBuffer != NULL){ 00367 incomingBuffer[incomingBufferSize++] = incomingByte; 00368 } else { 00369 error = ALLOCFAILED; 00370 } 00371 } 00372 00373 void OSCBundle::clearIncomingBuffer(){ 00374 incomingBufferSize = 0; 00375 free(incomingBuffer); 00376 incomingBuffer = NULL; 00377 } 00378 00379 00380
Generated on Sun Jul 24 2022 13:23:54 by
1.7.2