Main Page   Compound List   File List   Compound Members   File Members  

OSC-client.c

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 1996.  The Regents of the University of California (Regents).
00003 All Rights Reserved.
00004 
00005 Permission to use, copy, modify, and distribute this software and its
00006 documentation for educational, research, and not-for-profit purposes, without
00007 fee and without a signed licensing agreement, is hereby granted, provided that
00008 the above copyright notice, this paragraph and the following two paragraphs
00009 appear in all copies, modifications, and distributions.  Contact The Office of
00010 Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley,
00011 CA 94720-1620, (510) 643-7201, for commercial licensing opportunities.
00012 
00013 Written by Matt Wright, The Center for New Music and Audio Technologies,
00014 University of California, Berkeley.
00015 
00016      IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
00017      SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
00018      ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
00019      REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00020 
00021      REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
00022      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023      FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
00024      DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
00025      REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
00026      ENHANCEMENTS, OR MODIFICATIONS.
00027 */
00028 
00029 
00030 /* 
00031   Author: Matt Wright
00032   Version 2.2: Calls htonl in the right places 20000620
00033   Version 2.3: Gets typed messages right.
00034  */
00035 
00036 
00037 /* Here are the possible values of the state field: */
00038 
00039 #define EMPTY 0        /* Nothing written to packet yet */
00040 #define ONE_MSG_ARGS 1 /* Packet has a single message; gathering arguments */
00041 #define NEED_COUNT 2   /* Just opened a bundle; must write message name or
00042                           open another bundle */
00043 #define GET_ARGS 3     /* Getting arguments to a message.  If we see a message
00044                           name or a bundle open/close then the current message
00045                           will end. */
00046 #define DONE 4         /* All open bundles have been closed, so can't write 
00047                           anything else */
00048 
00049 
00050 #include "OSC-client.h"
00051 
00052 // defines to make this work with the atmel
00053 //
00054 #include "progmem.h"
00055 #include "debug.h"
00056 #define printf  debug
00057 //
00058 
00059 char *OSC_errorMessage;
00060 
00061 static int OSC_padString(char *dest, char PROGMEM *str);
00062 static int OSC_WritePadding(char *dest, int i);
00063 static int CheckTypeTag(OSCbuf *buf, char expectedType);
00064 
00065 void OSC_initBuffer(OSCbuf *buf, int size, char *byteArray) {
00066     buf->buffer = byteArray;
00067     buf->size = size;
00068     OSC_resetBuffer(buf);
00069 }
00070 
00071 void OSC_resetBuffer(OSCbuf *buf) {     
00072     buf->bufptr = buf->buffer;
00073     buf->state = EMPTY;
00074     buf->bundleDepth = 0;
00075     buf->prevCounts[0] = 0;
00076     buf->gettingFirstUntypedArg = 0;
00077     buf->typeStringPtr = 0;
00078 }
00079 
00080 int OSC_isBufferEmpty(OSCbuf *buf) {
00081     return buf->bufptr == buf->buffer;
00082 }
00083 
00084 int OSC_freeSpaceInBuffer(OSCbuf *buf) {
00085     return buf->size - (buf->bufptr - buf->buffer);
00086 }
00087 
00088 int OSC_isBufferDone(OSCbuf *buf) {
00089     return (buf->state == DONE || buf->state == ONE_MSG_ARGS);
00090 }
00091 
00092 char *OSC_getPacket(OSCbuf *buf) {
00093 #ifdef ERROR_CHECK_GETPACKET
00094     if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
00095         return buf->buffer;
00096     } else {
00097         OSC_errorMessage = "Packet has unterminated bundles";
00098         return 0;
00099     }
00100 #else
00101     return buf->buffer;
00102 #endif
00103 }
00104 
00105 int OSC_packetSize(OSCbuf *buf) {
00106 #ifdef ERROR_CHECK_PACKETSIZE
00107     if (buf->state == DONE || buf->state == ONE_MSG_ARGS) {
00108         return (buf->bufptr - buf->buffer);
00109     } else {
00110         OSC_errorMessage = "Packet has unterminated bundles";
00111         return 0;
00112     }
00113 #else
00114     return (buf->bufptr - buf->buffer);
00115 #endif
00116 }
00117 
00118 #define CheckOverflow(buf, bytesNeeded) { \
00119     if ((bytesNeeded) > OSC_freeSpaceInBuffer(buf)) { \
00120         OSC_errorMessage = "buffer overflow"; \
00121         return 1; \
00122     } \
00123 }
00124 
00125 static void PatchMessageSize(OSCbuf *buf) {
00126     int4byte size;
00127     size = buf->bufptr - ((char *) buf->thisMsgSize) - 4;
00128     *(buf->thisMsgSize) = htonl(size);
00129 }
00130 
00131 int OSC_openBundle(OSCbuf *buf, OSCTimeTag tt) {
00132     if (buf->state == ONE_MSG_ARGS) {
00133         OSC_errorMessage = "Can't open a bundle in a one-message packet";
00134         return 3;
00135     }
00136 
00137     if (buf->state == DONE) {
00138         OSC_errorMessage = "This packet is finished; can't open a new bundle";
00139         return 4;
00140     }
00141 
00142     if (++(buf->bundleDepth) >= MAX_BUNDLE_NESTING) {
00143         OSC_errorMessage = "Bundles nested too deeply; change MAX_BUNDLE_NESTING in OpenSoundControl.h";
00144         return 2;
00145     }
00146 
00147     if (CheckTypeTag(buf, '\0')) return 9;
00148 
00149     if (buf->state == GET_ARGS) {
00150         PatchMessageSize(buf);
00151     }
00152 
00153     if (buf->state == EMPTY) {
00154         /* Need 16 bytes for "#bundle" and time tag */
00155         CheckOverflow(buf, 16);
00156     } else {
00157         /* This bundle is inside another bundle, so we need to leave
00158            a blank size count for the size of this current bundle. */
00159         CheckOverflow(buf, 20);
00160         *((int4byte *)buf->bufptr) = 0xaaaaaaaa;
00161         buf->prevCounts[buf->bundleDepth] = (int4byte *)buf->bufptr;
00162 
00163         buf->bufptr += 4;
00164     }
00165 
00166     buf->bufptr += OSC_padString(buf->bufptr, "#bundle");
00167 
00168 
00169     *((OSCTimeTag *) buf->bufptr) = tt;
00170 
00171     if (htonl(1L) != 1L) {
00172         /* Byte swap the 8-byte integer time tag */
00173         int4byte *intp = (int4byte *)buf->bufptr;
00174         intp[0] = htonl(intp[0]);
00175         intp[1] = htonl(intp[1]);
00176 
00177 #ifdef HAS8BYTEINT
00178         { /* tt is a 64-bit int so we have to swap the two 32-bit words. 
00179             (Otherwise tt is a struct of two 32-bit words, and even though
00180              each word was wrong-endian, they were in the right order
00181              in the struct.) */
00182             int4byte temp = intp[0];
00183             intp[0] = intp[1];
00184             intp[1] = temp;
00185         }
00186 #endif
00187     }
00188 
00189     buf->bufptr += sizeof(OSCTimeTag);
00190 
00191     buf->state = NEED_COUNT;
00192 
00193     buf->gettingFirstUntypedArg = 0;
00194     buf->typeStringPtr = 0;
00195     return 0;
00196 }
00197 
00198 
00199 int OSC_closeBundle(OSCbuf *buf) {
00200     if (buf->bundleDepth == 0) {
00201         /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
00202         OSC_errorMessage = "Can't close bundle; no bundle is open!";
00203         return 5;
00204     }
00205 
00206     if (CheckTypeTag(buf, '\0')) return 9;
00207 
00208     if (buf->state == GET_ARGS) {
00209         PatchMessageSize(buf);
00210     }
00211 
00212     if (buf->bundleDepth == 1) {
00213         /* Closing the last bundle: No bundle size to patch */
00214         buf->state = DONE;
00215     } else {
00216         /* Closing a sub-bundle: patch bundle size */
00217         int4byte size = buf->bufptr - ((char *) buf->prevCounts[buf->bundleDepth]) - 4;
00218         *(buf->prevCounts[buf->bundleDepth]) = htonl(size);
00219         buf->state = NEED_COUNT;
00220     }
00221 
00222     --buf->bundleDepth;
00223     buf->gettingFirstUntypedArg = 0;
00224     buf->typeStringPtr = 0;
00225     return 0;
00226 }
00227 
00228 
00229 int OSC_closeAllBundles(OSCbuf *buf) {
00230     if (buf->bundleDepth == 0) {
00231         /* This handles EMPTY, ONE_MSG, ARGS, and DONE */
00232         OSC_errorMessage = "Can't close all bundles; no bundle is open!";
00233         return 6;
00234     }
00235 
00236     if (CheckTypeTag(buf, '\0')) return 9;
00237 
00238     while (buf->bundleDepth > 0) {
00239         OSC_closeBundle(buf);
00240     }
00241     buf->typeStringPtr = 0;
00242     return 0;
00243 }
00244 
00245 int OSC_writeAddress(OSCbuf *buf, char PROGMEM *name) {
00246     int4byte paddedLength;
00247 
00248     if (buf->state == ONE_MSG_ARGS) {
00249                 debug(PSTR("This packet is not a bundle, so you can't write another address"));
00250                 return 7;
00251     }
00252 
00253     if (buf->state == DONE) {
00254        debug(PSTR("This packet is finished; can't write another address"));
00255         return 8;
00256     }
00257 
00258     if (CheckTypeTag(buf, '\0')) return 9;
00259 
00260     paddedLength = OSC_effectiveStringLength(name);
00261 
00262     if (buf->state == EMPTY) {
00263         /* This will be a one-message packet, so no sizes to worry about */
00264                 CheckOverflow(buf, paddedLength);
00265                 buf->state = ONE_MSG_ARGS;
00266     } else {
00267         /* GET_ARGS or NEED_COUNT */
00268                 CheckOverflow(buf, 4+paddedLength);
00269                 if (buf->state == GET_ARGS) {
00270                 /* Close the old message */
00271                 PatchMessageSize(buf);
00272                 }
00273                 buf->thisMsgSize = (int4byte *)buf->bufptr;
00274                 *(buf->thisMsgSize) = 0xbbbbbbbb;
00275                 buf->bufptr += 4;
00276                 buf->state = GET_ARGS;
00277     }
00278 
00279     /* Now write the name */
00280     buf->bufptr += OSC_padString(buf->bufptr, name);
00281     buf->typeStringPtr = 0;
00282     buf->gettingFirstUntypedArg = 1;
00283 
00284     return 0;
00285 }
00286 
00287 int OSC_writeAddressAndTypes(OSCbuf *buf, char PROGMEM *name, char PROGMEM *types) {
00288     int result;
00289     int4byte paddedLength;
00290 
00291     if (CheckTypeTag(buf, '\0')) return 9;
00292 
00293     result = OSC_writeAddress(buf, name);
00294 
00295     if (result) return result;
00296 
00297     paddedLength = OSC_effectiveStringLength(types);
00298 
00299     CheckOverflow(buf, paddedLength);    
00300 
00301     buf->typeStringPtr = buf->bufptr + 1; /* skip comma */
00302     buf->bufptr += OSC_padString(buf->bufptr, types);
00303 
00304     buf->gettingFirstUntypedArg = 0;
00305     return 0;
00306 }
00307 
00308 static int CheckTypeTag(OSCbuf *buf, char expectedType) {
00309     if (buf->typeStringPtr) {
00310         if (*(buf->typeStringPtr) != expectedType) {
00311             if (expectedType == '\0') {
00312                 OSC_errorMessage =
00313                     "According to the type tag I expected more arguments.";
00314             } else if (*(buf->typeStringPtr) == '\0') {
00315                 OSC_errorMessage =
00316                     "According to the type tag I didn't expect any more arguments.";
00317             } else {
00318                 OSC_errorMessage =
00319                     "According to the type tag I expected an argument of a different type.";
00320 //              printf("* Expected %c, string now %s\n", expectedType, buf->typeStringPtr);
00321             }
00322             return 9; 
00323         }
00324         ++(buf->typeStringPtr);
00325     }
00326     return 0;
00327 }
00328 
00329 
00330 int OSC_writeFloatArg(OSCbuf *buf, float arg) {
00331     int4byte *intp;
00332 
00333     CheckOverflow(buf, 4);
00334 
00335     if (CheckTypeTag(buf, 'f')) return 9;
00336 
00337     /* Pretend arg is a long int so we can use htonl() */
00338     intp = ((int4byte *) &arg);
00339     *((int4byte *) buf->bufptr) = htonl(*intp);
00340 
00341     buf->bufptr += 4;
00342 
00343     buf->gettingFirstUntypedArg = 0;
00344     return 0;
00345 }
00346 
00347 
00348 
00349 int OSC_writeFloatArgs(OSCbuf *buf, int numFloats, float *args) {
00350     int i;
00351     int4byte *intp;
00352 
00353     CheckOverflow(buf, 4 * numFloats);
00354 
00355     /* Pretend args are long ints so we can use htonl() */
00356     intp = ((int4byte *) args);
00357 
00358     for (i = 0; i < numFloats; i++) {
00359         if (CheckTypeTag(buf, 'f')) return 9;
00360         *((int4byte *) buf->bufptr) = htonl(intp[i]);
00361         buf->bufptr += 4;
00362     }
00363 
00364     buf->gettingFirstUntypedArg = 0;
00365     return 0;
00366 }
00367 
00368 int OSC_writeIntArg(OSCbuf *buf, int4byte arg) {
00369     CheckOverflow(buf, 4);
00370     if (CheckTypeTag(buf, 'i')) return 9;
00371 
00372     *((int4byte *) buf->bufptr) = htonl(arg);
00373     buf->bufptr += 4;
00374 
00375     buf->gettingFirstUntypedArg = 0;
00376     return 0;
00377 }
00378 
00379 int OSC_writeStringArg(OSCbuf *buf, char PROGMEM *arg) {
00380     int len;
00381 
00382     if (CheckTypeTag(buf, 's')) return 9;
00383 
00384     len = OSC_effectiveStringLength(arg);
00385 
00386         CheckOverflow(buf, len);
00387         buf->bufptr += OSC_padString(buf->bufptr, arg);
00388 
00389     buf->gettingFirstUntypedArg = 0;
00390     return 0;
00391 
00392 }
00393 
00394 #define STRING_ALIGN_PAD 4
00395 int OSC_effectiveStringLength(char PROGMEM *string) {
00396     int len = strlen_P(string) + 1;  /* We need space for the null char. */
00397     
00398     /* Round up len to next multiple of STRING_ALIGN_PAD to account for alignment padding */
00399     if ((len % STRING_ALIGN_PAD) != 0) {
00400         len += STRING_ALIGN_PAD - (len % STRING_ALIGN_PAD);
00401     }
00402     return len;
00403 }
00404 
00405 static int OSC_padString(char *dest, char PROGMEM *str) {
00406     int i;
00407          char c;
00408     
00409     for (i = 0; (c = PRG_RDB(str+i)) != '\0'; i++) {
00410         dest[i] = c;
00411     }
00412     
00413     return OSC_WritePadding(dest, i);
00414 }
00415 
00416 static int OSC_WritePadding(char *dest, int i) {
00417     dest[i] = '\0';
00418     i++;
00419 
00420     for (; (i % STRING_ALIGN_PAD) != 0; i++) {
00421         dest[i] = '\0';
00422     }
00423 
00424     return i;
00425 }

Generated at Mon Oct 14 00:10:51 2002 for avrlib by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001