Control of mbed using OSC. Based on code from the Make Controller. Right now you can turn the onboard LEDs on/off and toggle 8 digital out pins. More I/O will be done in the future.

Dependencies:   mbed

Committer:
pehrhovey
Date:
Wed Mar 17 03:17:38 2010 +0000
Revision:
0:439354122597

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pehrhovey 0:439354122597 1 /*
pehrhovey 0:439354122597 2 * osc_sys.cpp
pehrhovey 0:439354122597 3 * adapting Make controller's OSC to mBed platform
pehrhovey 0:439354122597 4 * Pehr Hovey
pehrhovey 0:439354122597 5 */
pehrhovey 0:439354122597 6 /*********************************************************************************
pehrhovey 0:439354122597 7
pehrhovey 0:439354122597 8 Copyright 2006-2009 MakingThings
pehrhovey 0:439354122597 9
pehrhovey 0:439354122597 10 Licensed under the Apache License,
pehrhovey 0:439354122597 11 Version 2.0 (the "License"); you may not use this file except in compliance
pehrhovey 0:439354122597 12 with the License. You may obtain a copy of the License at
pehrhovey 0:439354122597 13
pehrhovey 0:439354122597 14 http://www.apache.org/licenses/LICENSE-2.0
pehrhovey 0:439354122597 15
pehrhovey 0:439354122597 16 Unless required by applicable law or agreed to in writing, software distributed
pehrhovey 0:439354122597 17 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
pehrhovey 0:439354122597 18 CONDITIONS OF ANY KIND, either express or implied. See the License for
pehrhovey 0:439354122597 19 the specific language governing permissions and limitations under the License.
pehrhovey 0:439354122597 20
pehrhovey 0:439354122597 21 *********************************************************************************/
pehrhovey 0:439354122597 22
pehrhovey 0:439354122597 23 /** @defgroup OSC OSC
pehrhovey 0:439354122597 24 Communicate with the Make Controller Kit via OSC.
pehrhovey 0:439354122597 25
pehrhovey 0:439354122597 26 \section osc OSC
pehrhovey 0:439354122597 27 "Open Sound Control (OSC) is a protocol for communication among computers, sound synthesizers,
pehrhovey 0:439354122597 28 and other multimedia devices that is optimized for modern networking technology."
pehrhovey 0:439354122597 29 With OSC implemented on the Make Controller Kit, it can already talk to
pehrhovey 0:439354122597 30 a wide variety of environments and devices like Java, Max/MSP, Pd, Flash, Processing, SuperCollider,
pehrhovey 0:439354122597 31 and many others.
pehrhovey 0:439354122597 32
pehrhovey 0:439354122597 33 OSC is based on the notion of \b messages, which are composed of an address, and the data to
pehrhovey 0:439354122597 34 be sent to that address. The address looks a lot like a URL that you might type into
pehrhovey 0:439354122597 35 your internet browser. Each element in the address is like a directory, with other
pehrhovey 0:439354122597 36 elements inside it, and each element is separated from the next by a slash (/). Each OSC
pehrhovey 0:439354122597 37 message must also start with a slash.
pehrhovey 0:439354122597 38
pehrhovey 0:439354122597 39 \par Example:
pehrhovey 0:439354122597 40 For instance, the OSC address
pehrhovey 0:439354122597 41 \code /make/controller/kit \endcode
pehrhovey 0:439354122597 42 says, "start in the 'make' directory, go down to the 'controller' directory, and
pehrhovey 0:439354122597 43 finally to the 'kit' directory.
pehrhovey 0:439354122597 44
pehrhovey 0:439354122597 45 Any number of \b argument \b values can be sent to that address by including them in the message
pehrhovey 0:439354122597 46 after the address. These values can be integers (ints), floats, or strings.
pehrhovey 0:439354122597 47
pehrhovey 0:439354122597 48 \par Example:
pehrhovey 0:439354122597 49 If we wanted to send the value 35.4 to the address above, we would create the message
pehrhovey 0:439354122597 50 \code /make/controller/kit 35.4 \endcode
pehrhovey 0:439354122597 51 with a space between the address and the data.\n\n
pehrhovey 0:439354122597 52 Additional data can be added, each separated by a space
pehrhovey 0:439354122597 53 \code /make/controller/kit 35.4 lawn 12 \endcode
pehrhovey 0:439354122597 54
pehrhovey 0:439354122597 55 \section osc_mck OSC & the Make Controller Kit
pehrhovey 0:439354122597 56 Many devices on the Make Controller Kit can be addressed via OSC. In sending messages to them,
pehrhovey 0:439354122597 57 we need to know the OSC address, and the appropriate argument values to send.
pehrhovey 0:439354122597 58
pehrhovey 0:439354122597 59 The Make Controller Kit is orgranized, for OSC, into \b subsystems. Each subsystem has one or more
pehrhovey 0:439354122597 60 \b devices, and each device has one or more \b properties. To address a particular device, you'll
pehrhovey 0:439354122597 61 need to create an OSC message specifying the address in that format:
pehrhovey 0:439354122597 62 \code /subsystem/device/property \endcode
pehrhovey 0:439354122597 63 Each of the modules above provide the details for each of the subsystems on the board, along with their
pehrhovey 0:439354122597 64 devices and properties. A simple example is given below.
pehrhovey 0:439354122597 65
pehrhovey 0:439354122597 66 \par Example:
pehrhovey 0:439354122597 67 To create an OSC message to turn an LED on, first identify the appropriate \b subsystem.
pehrhovey 0:439354122597 68 In this case, the subsystem is called \b appled.\n\n
pehrhovey 0:439354122597 69 There are 4 LEDs, so we need to specify which one to control.
pehrhovey 0:439354122597 70 The LEDs are numbered 0 -3, so choosing the first LED means the \b device value is 0.\n\n
pehrhovey 0:439354122597 71 The \b property of the LED that turns it on and off is its 'state'.\n\n
pehrhovey 0:439354122597 72 Lastly, we must specify what the state should actually be, by including an \b argument value after the address.
pehrhovey 0:439354122597 73 To turn it on, this value should be 1. 0 would turn it off.\n
pehrhovey 0:439354122597 74 The complete OSC message looks like
pehrhovey 0:439354122597 75 \code /appled/0/state 1 \endcode
pehrhovey 0:439354122597 76 */
pehrhovey 0:439354122597 77
pehrhovey 0:439354122597 78
pehrhovey 0:439354122597 79 #include "osc_sys.h"
pehrhovey 0:439354122597 80 #include "lwip/udp.h"
pehrhovey 0:439354122597 81
pehrhovey 0:439354122597 82
pehrhovey 0:439354122597 83 #include <string.h>
pehrhovey 0:439354122597 84 #include <stdio.h>
pehrhovey 0:439354122597 85
pehrhovey 0:439354122597 86 #include <ctype.h>
pehrhovey 0:439354122597 87 #include <stdarg.h>
pehrhovey 0:439354122597 88
pehrhovey 0:439354122597 89
pehrhovey 0:439354122597 90
pehrhovey 0:439354122597 91 int Osc_Quicky( int channel, char* preamble, char* string );
pehrhovey 0:439354122597 92 char* Osc_WritePaddedString( char* buffer, int* length, char* string );
pehrhovey 0:439354122597 93 char* Osc_WritePaddedBlob( char* buffer, int* length, char* blob, int blen );
pehrhovey 0:439354122597 94 char* Osc_WriteTimetag( char* buffer, int* length, int a, int b );
pehrhovey 0:439354122597 95 int Osc_EndianSwap( int a );
pehrhovey 0:439354122597 96 int Osc_ReceiveMessage( int channel, char* message, int length );
pehrhovey 0:439354122597 97 char* Osc_CreateBundle( char* buffer, int* length, int a, int b );
pehrhovey 0:439354122597 98 int Osc_PropertyLookup( char** properties, char* property );
pehrhovey 0:439354122597 99 int Osc_ReadInt( char* buffer );
pehrhovey 0:439354122597 100 float Osc_ReadFloat( char* buffer );
pehrhovey 0:439354122597 101
pehrhovey 0:439354122597 102
pehrhovey 0:439354122597 103 //void Osc_AsyncTask( void* p );
pehrhovey 0:439354122597 104
pehrhovey 0:439354122597 105 void Osc_ResetChannel( OscChannel* ch );
pehrhovey 0:439354122597 106 int Osc_SendPacketInternal( OscChannel* ch );
pehrhovey 0:439354122597 107
pehrhovey 0:439354122597 108 int Osc_SendMessage( int channel, char* message, int length );
pehrhovey 0:439354122597 109 int Osc_ReceiveMessage( int channel, char* message, int length );
pehrhovey 0:439354122597 110 int Osc_Poll( int channel, char* buffer, int maxLength, int* length );
pehrhovey 0:439354122597 111
pehrhovey 0:439354122597 112 //osc_patternmatch.c
pehrhovey 0:439354122597 113 bool Osc_PatternMatch(const char * pattern, const char * test);
pehrhovey 0:439354122597 114
pehrhovey 0:439354122597 115 int Osc_Quicky( int channel, char* preamble, char* string );
pehrhovey 0:439354122597 116 char* Osc_WritePaddedString( char* buffer, int* length, char* string );
pehrhovey 0:439354122597 117 char* Osc_WriteTimetag( char* buffer, int* length, int a, int b );
pehrhovey 0:439354122597 118 int Osc_EndianSwap( int a );
pehrhovey 0:439354122597 119
pehrhovey 0:439354122597 120 char* Osc_CreateBundle( char* buffer, int* length, int a, int b );
pehrhovey 0:439354122597 121 char* Osc_CreateMessageInternal( char* bp, int* length, char* address, char* format, va_list args );
pehrhovey 0:439354122597 122 int Osc_CreateMessageToBuf( char* bp, int* length, char* address, char* format, ... );
pehrhovey 0:439354122597 123
pehrhovey 0:439354122597 124 int Osc_ReadInt( char* buffer );
pehrhovey 0:439354122597 125 float Osc_ReadFloat( char* buffer );
pehrhovey 0:439354122597 126 int Osc_UdpPacketSend( char* packet, int length, struct ip_addr * replyAddress, int replyPort );
pehrhovey 0:439354122597 127
pehrhovey 0:439354122597 128 int OscBusy;
pehrhovey 0:439354122597 129
pehrhovey 0:439354122597 130 //Structures
pehrhovey 0:439354122597 131
pehrhovey 0:439354122597 132
pehrhovey 0:439354122597 133
pehrhovey 0:439354122597 134 typedef struct OscSubsystem_
pehrhovey 0:439354122597 135 {
pehrhovey 0:439354122597 136 const char* name;
pehrhovey 0:439354122597 137 int (*receiveMessage)( int channel, char* buffer, int length );
pehrhovey 0:439354122597 138 int (*async)( int channel );
pehrhovey 0:439354122597 139 }OscSubsystem;
pehrhovey 0:439354122597 140
pehrhovey 0:439354122597 141 typedef struct Osc_
pehrhovey 0:439354122597 142 {
pehrhovey 0:439354122597 143 int users;
pehrhovey 0:439354122597 144 int running;
pehrhovey 0:439354122597 145 int subsystemHighest;
pehrhovey 0:439354122597 146
pehrhovey 0:439354122597 147 OscChannel* channel[ OSC_CHANNEL_COUNT ];
pehrhovey 0:439354122597 148 OscSubsystem* subsystem[ OSC_SUBSYSTEM_COUNT ];
pehrhovey 0:439354122597 149 int registeredSubsystems; //counter
pehrhovey 0:439354122597 150 char scratch1[ OSC_SCRATCH_SIZE ], scratch2[ OSC_SCRATCH_SIZE ];
pehrhovey 0:439354122597 151 //UDP stuff
pehrhovey 0:439354122597 152 struct udp_pcb * osc_pcb; //used to send packets
pehrhovey 0:439354122597 153
pehrhovey 0:439354122597 154 }OscStruct;//OscStruct is the type name
pehrhovey 0:439354122597 155
pehrhovey 0:439354122597 156 OscStruct* Osc; //The allocated Osc struct that we refer to
pehrhovey 0:439354122597 157
pehrhovey 0:439354122597 158
pehrhovey 0:439354122597 159 void Osc_SystemInit( struct udp_pcb * pcb )
pehrhovey 0:439354122597 160 {
pehrhovey 0:439354122597 161
pehrhovey 0:439354122597 162 Osc = (OscStruct *) malloc( sizeof( OscStruct ));
pehrhovey 0:439354122597 163 Osc->subsystemHighest = 0;
pehrhovey 0:439354122597 164 Osc->registeredSubsystems = 0;
pehrhovey 0:439354122597 165
pehrhovey 0:439354122597 166 int i;
pehrhovey 0:439354122597 167 for( i = 0; i < OSC_CHANNEL_COUNT; i++ )
pehrhovey 0:439354122597 168 Osc->channel[ i ] = NULL;
pehrhovey 0:439354122597 169 for( i = 0; i < OSC_SUBSYSTEM_COUNT; i++ )
pehrhovey 0:439354122597 170 Osc->subsystem[ i ] = NULL;
pehrhovey 0:439354122597 171
pehrhovey 0:439354122597 172 Osc->users = 1;
pehrhovey 0:439354122597 173 Osc->running = true;
pehrhovey 0:439354122597 174
pehrhovey 0:439354122597 175 Osc_UdpInit(OSC_CHANNEL_UDP, pcb);
pehrhovey 0:439354122597 176
pehrhovey 0:439354122597 177 return;
pehrhovey 0:439354122597 178 }
pehrhovey 0:439354122597 179
pehrhovey 0:439354122597 180 OscChannel * Osc_GetChannel(int channel){
pehrhovey 0:439354122597 181 if(channel < OSC_CHANNEL_COUNT)
pehrhovey 0:439354122597 182 return Osc->channel[channel];
pehrhovey 0:439354122597 183 else
pehrhovey 0:439354122597 184 return NULL;
pehrhovey 0:439354122597 185
pehrhovey 0:439354122597 186 }
pehrhovey 0:439354122597 187 //Initialize the UDP channel
pehrhovey 0:439354122597 188 void Osc_UdpInit( int channel, struct udp_pcb * pcb)
pehrhovey 0:439354122597 189 {
pehrhovey 0:439354122597 190 Osc->osc_pcb = pcb;
pehrhovey 0:439354122597 191 Osc->channel[ channel ] = (OscChannel *) malloc( sizeof( OscChannel ));
pehrhovey 0:439354122597 192 OscChannel *ch = Osc->channel[ channel ]; //get the struct so we can assign things to it
pehrhovey 0:439354122597 193
pehrhovey 0:439354122597 194 Osc_SetReplyPort( channel, UDP_BROADCAST_PORT); //broadcast by default
pehrhovey 0:439354122597 195 Osc_SetReplyAddress( channel, IP_ADDR_BROADCAST); //broadcast by default
pehrhovey 0:439354122597 196 ch->sendMessage = Osc_UdpPacketSend; //the function used to send packets
pehrhovey 0:439354122597 197 Osc_ResetChannel( ch );
pehrhovey 0:439354122597 198
pehrhovey 0:439354122597 199 ch->running = true;
pehrhovey 0:439354122597 200 //will get data from the udp_recv callback (external right now)
pehrhovey 0:439354122597 201 }
pehrhovey 0:439354122597 202
pehrhovey 0:439354122597 203 int Osc_UdpPacketSend( char* packet, int length, struct ip_addr * replyAddress, int replyPort )
pehrhovey 0:439354122597 204 {
pehrhovey 0:439354122597 205 if ( replyAddress != 0 && replyPort != 0 )
pehrhovey 0:439354122597 206 {
pehrhovey 0:439354122597 207 //Use LWIP raw API to send a packet
pehrhovey 0:439354122597 208 //make packet
pehrhovey 0:439354122597 209 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT,length,PBUF_RAM);
pehrhovey 0:439354122597 210 memcpy (p->payload, packet, length);
pehrhovey 0:439354122597 211 //send packet
pehrhovey 0:439354122597 212 int retval = udp_sendto(Osc->osc_pcb, p, replyAddress, replyPort);
pehrhovey 0:439354122597 213 //free packet
pehrhovey 0:439354122597 214 pbuf_free(p);
pehrhovey 0:439354122597 215
pehrhovey 0:439354122597 216 return retval;
pehrhovey 0:439354122597 217 }
pehrhovey 0:439354122597 218 else
pehrhovey 0:439354122597 219 return CONTROLLER_ERROR_NO_ADDRESS;
pehrhovey 0:439354122597 220 }
pehrhovey 0:439354122597 221
pehrhovey 0:439354122597 222
pehrhovey 0:439354122597 223 void Osc_AsyncTask( void* p )
pehrhovey 0:439354122597 224 {
pehrhovey 0:439354122597 225 // (void)p;
pehrhovey 0:439354122597 226 // int channel;
pehrhovey 0:439354122597 227 // int i;
pehrhovey 0:439354122597 228 // OscSubsystem* sub;
pehrhovey 0:439354122597 229 // int newMsgs = 0;
pehrhovey 0:439354122597 230 // while( 1 )
pehrhovey 0:439354122597 231 // {
pehrhovey 0:439354122597 232 // channel = System_GetAsyncDestination( );
pehrhovey 0:439354122597 233 // if( channel >= 0 )
pehrhovey 0:439354122597 234 // {
pehrhovey 0:439354122597 235 // for( i = 0; i < Osc->registeredSubsystems; i++ )
pehrhovey 0:439354122597 236 // {
pehrhovey 0:439354122597 237 // sub = Osc->subsystem[ i ];
pehrhovey 0:439354122597 238 // if( sub->async != NULL )
pehrhovey 0:439354122597 239 // newMsgs += (sub->async)( channel );
pehrhovey 0:439354122597 240 // }
pehrhovey 0:439354122597 241 // if( newMsgs > 0 )
pehrhovey 0:439354122597 242 // {
pehrhovey 0:439354122597 243 // Osc_SendPacket( channel );
pehrhovey 0:439354122597 244 // newMsgs = 0;
pehrhovey 0:439354122597 245 // }
pehrhovey 0:439354122597 246 // Sleep( System_GetAutoSendInterval( ) );
pehrhovey 0:439354122597 247 // }
pehrhovey 0:439354122597 248 // else
pehrhovey 0:439354122597 249 // Sleep( 1000 );
pehrhovey 0:439354122597 250 // }
pehrhovey 0:439354122597 251 }
pehrhovey 0:439354122597 252
pehrhovey 0:439354122597 253 int Osc_SetReplyAddress( int channel, struct ip_addr * replyAddress )
pehrhovey 0:439354122597 254 {
pehrhovey 0:439354122597 255 if ( channel < 0 || channel >= OSC_CHANNEL_COUNT )
pehrhovey 0:439354122597 256 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 257
pehrhovey 0:439354122597 258 OscChannel* ch = Osc->channel[ channel ];
pehrhovey 0:439354122597 259
pehrhovey 0:439354122597 260 ch->replyAddress = replyAddress;
pehrhovey 0:439354122597 261
pehrhovey 0:439354122597 262 return CONTROLLER_OK;
pehrhovey 0:439354122597 263 }
pehrhovey 0:439354122597 264
pehrhovey 0:439354122597 265 int Osc_SetReplyPort( int channel, int replyPort )
pehrhovey 0:439354122597 266 {
pehrhovey 0:439354122597 267 if ( channel < 0 || channel >= OSC_CHANNEL_COUNT )
pehrhovey 0:439354122597 268 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 269
pehrhovey 0:439354122597 270 OscChannel* ch = Osc->channel[ channel ];
pehrhovey 0:439354122597 271
pehrhovey 0:439354122597 272 ch->replyPort = replyPort;
pehrhovey 0:439354122597 273
pehrhovey 0:439354122597 274 return CONTROLLER_OK;
pehrhovey 0:439354122597 275 }
pehrhovey 0:439354122597 276
pehrhovey 0:439354122597 277 void Osc_ResetChannel( OscChannel* ch )
pehrhovey 0:439354122597 278 {
pehrhovey 0:439354122597 279 ch->bufferPointer = ch->buffer;
pehrhovey 0:439354122597 280 ch->bufferRemaining = OSC_MAX_MESSAGE_OUT;
pehrhovey 0:439354122597 281 ch->messages = 0;
pehrhovey 0:439354122597 282 }
pehrhovey 0:439354122597 283
pehrhovey 0:439354122597 284 int Osc_SendMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 285 {
pehrhovey 0:439354122597 286 (void)channel;
pehrhovey 0:439354122597 287 (void)message;
pehrhovey 0:439354122597 288 (void)length;
pehrhovey 0:439354122597 289 return CONTROLLER_OK;
pehrhovey 0:439354122597 290 }
pehrhovey 0:439354122597 291
pehrhovey 0:439354122597 292 int Osc_ReceivePacket( int channel, char* packet, int length )
pehrhovey 0:439354122597 293 {
pehrhovey 0:439354122597 294 // Got a packet. Unpacket.
pehrhovey 0:439354122597 295 int status = -1;
pehrhovey 0:439354122597 296 switch ( *packet )
pehrhovey 0:439354122597 297 {
pehrhovey 0:439354122597 298 case '/':
pehrhovey 0:439354122597 299 status = Osc_ReceiveMessage( channel, packet, length );
pehrhovey 0:439354122597 300 break;
pehrhovey 0:439354122597 301 case '#':
pehrhovey 0:439354122597 302 if ( strcmp( packet, "#bundle" ) == 0 )
pehrhovey 0:439354122597 303 {
pehrhovey 0:439354122597 304 // skip bundle text and timetag
pehrhovey 0:439354122597 305 packet += 16;
pehrhovey 0:439354122597 306 length -= 16;
pehrhovey 0:439354122597 307 while ( length > 0 )
pehrhovey 0:439354122597 308 {
pehrhovey 0:439354122597 309 // read the length (pretend packet is a pointer to integer)
pehrhovey 0:439354122597 310 int messageLength = Osc_EndianSwap( *((int*)packet) );
pehrhovey 0:439354122597 311 packet += 4;
pehrhovey 0:439354122597 312 length -= 4;
pehrhovey 0:439354122597 313 if ( messageLength <= length )
pehrhovey 0:439354122597 314 Osc_ReceivePacket( channel, packet, messageLength );
pehrhovey 0:439354122597 315 length -= messageLength;
pehrhovey 0:439354122597 316 packet += messageLength;
pehrhovey 0:439354122597 317 }
pehrhovey 0:439354122597 318 }
pehrhovey 0:439354122597 319 break;
pehrhovey 0:439354122597 320 default:
pehrhovey 0:439354122597 321 // Something else?
pehrhovey 0:439354122597 322 Osc_CreateMessage( channel, "/error", ",s", "Packet Error" );
pehrhovey 0:439354122597 323 break;
pehrhovey 0:439354122597 324 }
pehrhovey 0:439354122597 325
pehrhovey 0:439354122597 326 return Osc_SendPacket( channel );
pehrhovey 0:439354122597 327 }
pehrhovey 0:439354122597 328
pehrhovey 0:439354122597 329 int Osc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 330 {
pehrhovey 0:439354122597 331 // Got a packet. Unpacket.
pehrhovey 0:439354122597 332
pehrhovey 0:439354122597 333 // Confirm it's a message
pehrhovey 0:439354122597 334 if ( *message == '/' )
pehrhovey 0:439354122597 335 {
pehrhovey 0:439354122597 336 if( strlen(message) > (unsigned int)length )
pehrhovey 0:439354122597 337 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 338
pehrhovey 0:439354122597 339 int i;
pehrhovey 0:439354122597 340 char* nextChar = message + 1; // first, try to see if it was a "help" query
pehrhovey 0:439354122597 341 if( *nextChar == '\0' || *nextChar == ' ' )
pehrhovey 0:439354122597 342 {
pehrhovey 0:439354122597 343 for ( i = 0; i < Osc->registeredSubsystems; i++ )
pehrhovey 0:439354122597 344 {
pehrhovey 0:439354122597 345 OscSubsystem* sub = Osc->subsystem[ i ];
pehrhovey 0:439354122597 346 Osc_CreateMessage( channel, "/", ",s", sub->name );
pehrhovey 0:439354122597 347 }
pehrhovey 0:439354122597 348 return CONTROLLER_OK;
pehrhovey 0:439354122597 349 }
pehrhovey 0:439354122597 350
pehrhovey 0:439354122597 351 char* nextSlash = strchr( message + 1, '/' );
pehrhovey 0:439354122597 352 if ( nextSlash != NULL )
pehrhovey 0:439354122597 353 *nextSlash = 0;
pehrhovey 0:439354122597 354
pehrhovey 0:439354122597 355 int count = 0;
pehrhovey 0:439354122597 356 for ( i = 0; i < Osc->registeredSubsystems; i++ )
pehrhovey 0:439354122597 357 {
pehrhovey 0:439354122597 358 OscSubsystem* sub = Osc->subsystem[ i ];
pehrhovey 0:439354122597 359 if ( Osc_PatternMatch( message + 1, sub->name ) )
pehrhovey 0:439354122597 360 {
pehrhovey 0:439354122597 361 count++;
pehrhovey 0:439354122597 362 if ( nextSlash )
pehrhovey 0:439354122597 363 (sub->receiveMessage)( channel, nextSlash + 1, length - ( nextSlash - message ) - 1 );
pehrhovey 0:439354122597 364 else
pehrhovey 0:439354122597 365 {
pehrhovey 0:439354122597 366 char* noNextSlash = message + strlen(message);
pehrhovey 0:439354122597 367 (sub->receiveMessage)( channel, noNextSlash, 0 );
pehrhovey 0:439354122597 368 }
pehrhovey 0:439354122597 369 }
pehrhovey 0:439354122597 370 }
pehrhovey 0:439354122597 371 if ( count == 0 )
pehrhovey 0:439354122597 372 {
pehrhovey 0:439354122597 373
pehrhovey 0:439354122597 374 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "No Subsystem Match - %s", message + 1 );
pehrhovey 0:439354122597 375 Osc_CreateMessage( channel, "/error", ",s", Osc->scratch1 );
pehrhovey 0:439354122597 376
pehrhovey 0:439354122597 377 }
pehrhovey 0:439354122597 378 }
pehrhovey 0:439354122597 379 else
pehrhovey 0:439354122597 380 {
pehrhovey 0:439354122597 381 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 382 }
pehrhovey 0:439354122597 383 return CONTROLLER_OK;
pehrhovey 0:439354122597 384 }
pehrhovey 0:439354122597 385
pehrhovey 0:439354122597 386 int Osc_SendPacket( int channel )
pehrhovey 0:439354122597 387 {
pehrhovey 0:439354122597 388 if ( channel < 0 || channel >= OSC_CHANNEL_COUNT )
pehrhovey 0:439354122597 389 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 390
pehrhovey 0:439354122597 391 OscChannel* ch = Osc->channel[ channel ];
pehrhovey 0:439354122597 392
pehrhovey 0:439354122597 393 if ( ch->messages == 0 )
pehrhovey 0:439354122597 394 return CONTROLLER_OK;
pehrhovey 0:439354122597 395
pehrhovey 0:439354122597 396
pehrhovey 0:439354122597 397 int ret = Osc_SendPacketInternal( ch );
pehrhovey 0:439354122597 398 printf("Sent packets for channel # %d, ret=%d \r\n",channel,ret);
pehrhovey 0:439354122597 399
pehrhovey 0:439354122597 400 return ret;
pehrhovey 0:439354122597 401 }
pehrhovey 0:439354122597 402
pehrhovey 0:439354122597 403 int Osc_SendPacketInternal( OscChannel* ch )
pehrhovey 0:439354122597 404 {
pehrhovey 0:439354122597 405 //printf("Trying to send packets - we have %d msgs\r\n",ch->messages);
pehrhovey 0:439354122597 406 if ( ch->messages == 0 )
pehrhovey 0:439354122597 407 return CONTROLLER_OK;
pehrhovey 0:439354122597 408
pehrhovey 0:439354122597 409 // set the buffer and length up
pehrhovey 0:439354122597 410 char* buffer = ch->buffer;
pehrhovey 0:439354122597 411 int length = OSC_MAX_MESSAGE_OUT - ch->bufferRemaining;
pehrhovey 0:439354122597 412
pehrhovey 0:439354122597 413 // see if we can dispense with the bundle business
pehrhovey 0:439354122597 414 if ( ch->messages == 1 )
pehrhovey 0:439354122597 415 {
pehrhovey 0:439354122597 416 // skip 8 bytes of "#bundle" and 8 bytes of timetag and 4 bytes of size
pehrhovey 0:439354122597 417 buffer += 20;
pehrhovey 0:439354122597 418 // shorter too
pehrhovey 0:439354122597 419 length -= 20;
pehrhovey 0:439354122597 420 }
pehrhovey 0:439354122597 421 //call the stored function to do the sending (Osc_UdpPacketSend if its UDP)
pehrhovey 0:439354122597 422 (*ch->sendMessage)( buffer, length, ch->replyAddress, ch->replyPort );
pehrhovey 0:439354122597 423
pehrhovey 0:439354122597 424 Osc_ResetChannel( ch );
pehrhovey 0:439354122597 425
pehrhovey 0:439354122597 426 return CONTROLLER_OK;
pehrhovey 0:439354122597 427 }
pehrhovey 0:439354122597 428
pehrhovey 0:439354122597 429 int Osc_Poll( int channel, char* buffer, int maxLength, int* length )
pehrhovey 0:439354122597 430 {
pehrhovey 0:439354122597 431 (void)buffer;
pehrhovey 0:439354122597 432 (void)maxLength;
pehrhovey 0:439354122597 433 (void)length;
pehrhovey 0:439354122597 434 (void)channel;
pehrhovey 0:439354122597 435 return CONTROLLER_OK;
pehrhovey 0:439354122597 436 }
pehrhovey 0:439354122597 437
pehrhovey 0:439354122597 438 int Osc_Quicky( int channel, char* preamble, char* string )
pehrhovey 0:439354122597 439 {
pehrhovey 0:439354122597 440 return Osc_CreateMessage( channel, "/debug", ",ss", preamble, string );
pehrhovey 0:439354122597 441 }
pehrhovey 0:439354122597 442
pehrhovey 0:439354122597 443 /** @defgroup OSCAPI OSC API
pehrhovey 0:439354122597 444 Make use of the OSC infrastructure for your own subsystems.
pehrhovey 0:439354122597 445 You can use the existing OSC infrastructure to create your own OSC subsystems. It's expected that you'll have
pehrhovey 0:439354122597 446 a few things lined up to use this API:
pehrhovey 0:439354122597 447 -# The name of your subsystem
pehrhovey 0:439354122597 448 -# The properties that your subsystem will support. This must be in an array with '0' as the last element.
pehrhovey 0:439354122597 449 -# Getters and setters for each of those properties and functions to call them by property index.
pehrhovey 0:439354122597 450 -# A function to call the correct helper when Osc calls you.
pehrhovey 0:439354122597 451 -# Finally, once you've done all this, you'll need to add your subsystem to the list that Osc knows about.
pehrhovey 0:439354122597 452
pehrhovey 0:439354122597 453 \par Example
pehrhovey 0:439354122597 454 So this might look something like:
pehrhovey 0:439354122597 455 \code
pehrhovey 0:439354122597 456 // our system name and a function to get it
pehrhovey 0:439354122597 457 static char* MySubsystemOsc_Name = "my-system";
pehrhovey 0:439354122597 458 const char* MySubsystemOsc_GetName( void )
pehrhovey 0:439354122597 459 {
pehrhovey 0:439354122597 460 return MySubsystemOsc_Name;
pehrhovey 0:439354122597 461 }
pehrhovey 0:439354122597 462
pehrhovey 0:439354122597 463 // our property names
pehrhovey 0:439354122597 464 static char* MySubsystemOsc_PropertyNames[] = { "prop0", "prop1", 0 }; // must end with a zero
pehrhovey 0:439354122597 465
pehrhovey 0:439354122597 466 // A getter and setter, each dealing with the property given to us by the OSC system
pehrhovey 0:439354122597 467 int MyGPSOsc_PropertySet( int index, int property, int value )
pehrhovey 0:439354122597 468 {
pehrhovey 0:439354122597 469 switch ( property )
pehrhovey 0:439354122597 470 {
pehrhovey 0:439354122597 471 case 0:
pehrhovey 0:439354122597 472 MySubsystem_SetProperty0( index, value );
pehrhovey 0:439354122597 473 break;
pehrhovey 0:439354122597 474 case 1:
pehrhovey 0:439354122597 475 MySubsystem_SetProperty1( index, value );
pehrhovey 0:439354122597 476 break;
pehrhovey 0:439354122597 477 }
pehrhovey 0:439354122597 478 return CONTROLLER_OK;
pehrhovey 0:439354122597 479 }
pehrhovey 0:439354122597 480
pehrhovey 0:439354122597 481 int MySubsystemOsc_PropertyGet( int index, int property )
pehrhovey 0:439354122597 482 {
pehrhovey 0:439354122597 483 int value;
pehrhovey 0:439354122597 484 switch ( property )
pehrhovey 0:439354122597 485 {
pehrhovey 0:439354122597 486 case 0:
pehrhovey 0:439354122597 487 value = MySubsystem_GetProperty0( index );
pehrhovey 0:439354122597 488 break;
pehrhovey 0:439354122597 489 case 1:
pehrhovey 0:439354122597 490 value = MySubsystem_GetProperty1( index );
pehrhovey 0:439354122597 491 break;
pehrhovey 0:439354122597 492 }
pehrhovey 0:439354122597 493 return value;
pehrhovey 0:439354122597 494 }
pehrhovey 0:439354122597 495
pehrhovey 0:439354122597 496 // this is called when the OSC system determines an incoming message is for you.
pehrhovey 0:439354122597 497 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 498 {
pehrhovey 0:439354122597 499 // depending on your subsystem, use one of the OSC helpers to parse the incoming message
pehrhovey 0:439354122597 500 return Osc_IndexGeneralReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 501 MySubsystemOsc_Name,
pehrhovey 0:439354122597 502 MySubsystemOsc_PropertySet,
pehrhovey 0:439354122597 503 MySubsystemOsc_PropertyGet,
pehrhovey 0:439354122597 504 MySubsystemOsc_PropertyNames );
pehrhovey 0:439354122597 505 }
pehrhovey 0:439354122597 506
pehrhovey 0:439354122597 507 // lastly, we'll need to register our system with OSC
pehrhovey 0:439354122597 508 Run( ) // this is our startup task in make.c
pehrhovey 0:439354122597 509 {
pehrhovey 0:439354122597 510 // other startup stuff
pehrhovey 0:439354122597 511 Osc_RegisterSubsystem( MySubsystemOsc_GetName(), MySubsystemOsc_ReceiveMessage, NULL );
pehrhovey 0:439354122597 512 }
pehrhovey 0:439354122597 513 \endcode
pehrhovey 0:439354122597 514
pehrhovey 0:439354122597 515 Check the how-to at http://www.makingthings.com/documentation/how-to/create-your-own-osc-subsystem for details.
pehrhovey 0:439354122597 516
pehrhovey 0:439354122597 517 \ingroup Core
pehrhovey 0:439354122597 518 */
pehrhovey 0:439354122597 519
pehrhovey 0:439354122597 520 /**
pehrhovey 0:439354122597 521 Register your subsystem with the OSC system.
pehrhovey 0:439354122597 522 You'll usually want to do this on startup.
pehrhovey 0:439354122597 523 @param name The name of your subsystem.
pehrhovey 0:439354122597 524 @param subsystem_ReceiveMessage The function to call when an OSC message for this subsystem has arrived.
pehrhovey 0:439354122597 525 @param subsystem_Async The function to be called by the OSC Async system. This is a task that will call you at regular intervals,
pehrhovey 0:439354122597 526 if enabled, so you can check for status changes and send a message out automatically if you like. See the analog in source for
pehrhovey 0:439354122597 527 an example. Pass in NULL if you don't want to use the Async system.
pehrhovey 0:439354122597 528 \ingroup OSCAPI
pehrhovey 0:439354122597 529
pehrhovey 0:439354122597 530 \par Example
pehrhovey 0:439354122597 531 \code
pehrhovey 0:439354122597 532 Run( ) // this is our startup task in make.c
pehrhovey 0:439354122597 533 {
pehrhovey 0:439354122597 534 // other startup stuff
pehrhovey 0:439354122597 535 Osc_RegisterSubsystem( MySubsystemOsc_GetName(), MySubsystemOsc_ReceiveMessage, NULL );
pehrhovey 0:439354122597 536 }
pehrhovey 0:439354122597 537 \endcode
pehrhovey 0:439354122597 538 */
pehrhovey 0:439354122597 539 int Osc_RegisterSubsystem( const char *name, int (*subsystem_ReceiveMessage)( int channel, char* buffer, int length ), int (*subsystem_Async)( int channel ) )
pehrhovey 0:439354122597 540 {
pehrhovey 0:439354122597 541 int subsystem = Osc->registeredSubsystems;
pehrhovey 0:439354122597 542 if ( Osc->registeredSubsystems++ > OSC_SUBSYSTEM_COUNT )
pehrhovey 0:439354122597 543 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 544
pehrhovey 0:439354122597 545 Osc->subsystem[ subsystem ] = (OscSubsystem *) malloc( sizeof( OscSubsystem ));
pehrhovey 0:439354122597 546 OscSubsystem* sub = Osc->subsystem[ subsystem ];
pehrhovey 0:439354122597 547 sub->name = name;
pehrhovey 0:439354122597 548 sub->receiveMessage = subsystem_ReceiveMessage;
pehrhovey 0:439354122597 549 sub->async = subsystem_Async;
pehrhovey 0:439354122597 550 return CONTROLLER_OK;
pehrhovey 0:439354122597 551 }
pehrhovey 0:439354122597 552
pehrhovey 0:439354122597 553 /**
pehrhovey 0:439354122597 554 Send an error back via OSC from your subsystem.
pehrhovey 0:439354122597 555 You'll usually want to call this when the OSC system calls you with a new message, you've tried to
pehrhovey 0:439354122597 556 parse it, and you've gotten an error.
pehrhovey 0:439354122597 557 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 558 by the OSC system.
pehrhovey 0:439354122597 559 @param subsystem The name of the subsystem sending the error.
pehrhovey 0:439354122597 560 @param string The actual contents of the error message.
pehrhovey 0:439354122597 561 \ingroup OSCAPI
pehrhovey 0:439354122597 562
pehrhovey 0:439354122597 563 \par Example
pehrhovey 0:439354122597 564 \code
pehrhovey 0:439354122597 565 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 566 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 567 {
pehrhovey 0:439354122597 568 int status = Osc_IntReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 569 MySubsystemOsc_Name,
pehrhovey 0:439354122597 570 MySubsystemOsc_PropertySet, MySubsystemOsc_PropertyGet,
pehrhovey 0:439354122597 571 MySubsystemOsc_PropertyNames );
pehrhovey 0:439354122597 572
pehrhovey 0:439354122597 573 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 574 Osc_SubsystemError( channel, MySubsystemOsc_Name, "Oh no. Bad data." );
pehrhovey 0:439354122597 575 }
pehrhovey 0:439354122597 576 \endcode
pehrhovey 0:439354122597 577 */
pehrhovey 0:439354122597 578 int Osc_SubsystemError( int channel, char* subsystem, char* string )
pehrhovey 0:439354122597 579 {
pehrhovey 0:439354122597 580 int retval;
pehrhovey 0:439354122597 581
pehrhovey 0:439354122597 582 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s/error", subsystem );
pehrhovey 0:439354122597 583 retval = Osc_CreateMessage( channel, Osc->scratch1, ",s", string );
pehrhovey 0:439354122597 584
pehrhovey 0:439354122597 585 return retval;
pehrhovey 0:439354122597 586 }
pehrhovey 0:439354122597 587
pehrhovey 0:439354122597 588
pehrhovey 0:439354122597 589 /**
pehrhovey 0:439354122597 590 Receive an OSC blob for a subsystem with no indexes.
pehrhovey 0:439354122597 591 You'll usually want to call this when the OSC system calls you with a new message.
pehrhovey 0:439354122597 592 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 593 by the OSC system.
pehrhovey 0:439354122597 594 @param message The OSC message being received. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 595 @param length The length of the incoming message. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 596 @param subsystemName The name of your subsystem.
pehrhovey 0:439354122597 597 @param blobPropertySet A pointer to the function to be called in order to write a property of your subsystem.
pehrhovey 0:439354122597 598 @param blobPropertyGet A pointer to the function to be called in order to read a property of your subsystem.
pehrhovey 0:439354122597 599 @param blobPropertyNames An array of all the property names in your subsystem.
pehrhovey 0:439354122597 600 \ingroup OSCAPI
pehrhovey 0:439354122597 601
pehrhovey 0:439354122597 602 \par Example
pehrhovey 0:439354122597 603 \code
pehrhovey 0:439354122597 604 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 605 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 606 {
pehrhovey 0:439354122597 607 int status = Osc_BlobReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 608 MySubsystemOsc_Name,
pehrhovey 0:439354122597 609 MySubsystemOsc_BlobPropertySet, MySubsystemOsc_BlobPropertyGet,
pehrhovey 0:439354122597 610 MySubsystemOsc_BlobPropertyNames );
pehrhovey 0:439354122597 611
pehrhovey 0:439354122597 612 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 613 return Osc_SendError( channel, MySubsystemOsc_Name, status );
pehrhovey 0:439354122597 614 return CONTROLLER_OK;
pehrhovey 0:439354122597 615 }
pehrhovey 0:439354122597 616 \endcode
pehrhovey 0:439354122597 617 */
pehrhovey 0:439354122597 618 int Osc_BlobReceiverHelper( int channel, char* message, int length,
pehrhovey 0:439354122597 619 char* subsystemName,
pehrhovey 0:439354122597 620 int (*blobPropertySet)( int property, uchar* buffer, int length ),
pehrhovey 0:439354122597 621 int (*blobPropertyGet)( int property, uchar* buffer, int size ),
pehrhovey 0:439354122597 622 char* blobPropertyNames[] )
pehrhovey 0:439354122597 623 {
pehrhovey 0:439354122597 624 if ( message == NULL )
pehrhovey 0:439354122597 625 return CONTROLLER_ERROR_NO_PROPERTY;
pehrhovey 0:439354122597 626
pehrhovey 0:439354122597 627 int propertyIndex = Osc_PropertyLookup( blobPropertyNames, message );
pehrhovey 0:439354122597 628 if ( propertyIndex == -1 )
pehrhovey 0:439354122597 629 return CONTROLLER_ERROR_UNKNOWN_PROPERTY;
pehrhovey 0:439354122597 630
pehrhovey 0:439354122597 631 // Sometime after the address, the data tag begins - this is the description
pehrhovey 0:439354122597 632 // of the data in the rest of the message. It starts with a comma. Return
pehrhovey 0:439354122597 633 // where it is into 'type'. If there is no comma, this is bad.
pehrhovey 0:439354122597 634 char* type = Osc_FindDataTag( message, length ); //typetag
pehrhovey 0:439354122597 635 if ( type == NULL )
pehrhovey 0:439354122597 636 return CONTROLLER_ERROR_NO_TYPE_TAG;
pehrhovey 0:439354122597 637
pehrhovey 0:439354122597 638 // We can tell if there's data by seeing if the character after the comma
pehrhovey 0:439354122597 639 // is a zero or not.
pehrhovey 0:439354122597 640 if ( type[ 1 ] != 0 )
pehrhovey 0:439354122597 641 {
pehrhovey 0:439354122597 642 if ( type[ 1 ] == 'b' )
pehrhovey 0:439354122597 643 {
pehrhovey 0:439354122597 644 unsigned char *buffer;
pehrhovey 0:439354122597 645 int size;
pehrhovey 0:439354122597 646 int count = Osc_ExtractData( type, "b", &buffer, &size );
pehrhovey 0:439354122597 647 if ( count != 1 )
pehrhovey 0:439354122597 648 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 649
pehrhovey 0:439354122597 650 (*blobPropertySet)( propertyIndex, buffer, size );
pehrhovey 0:439354122597 651 }
pehrhovey 0:439354122597 652 else
pehrhovey 0:439354122597 653 {
pehrhovey 0:439354122597 654 if ( type[ 1 ] == 's' )
pehrhovey 0:439354122597 655 {
pehrhovey 0:439354122597 656 unsigned char *buffer;
pehrhovey 0:439354122597 657 int count = Osc_ExtractData( type, "s", &buffer );
pehrhovey 0:439354122597 658 if ( count != 1 )
pehrhovey 0:439354122597 659 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 660
pehrhovey 0:439354122597 661 (*blobPropertySet)( propertyIndex, buffer, strlen( (char*)buffer ) );
pehrhovey 0:439354122597 662 }
pehrhovey 0:439354122597 663 else
pehrhovey 0:439354122597 664 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 665 }
pehrhovey 0:439354122597 666
pehrhovey 0:439354122597 667 }
pehrhovey 0:439354122597 668 else
pehrhovey 0:439354122597 669 {
pehrhovey 0:439354122597 670 // No data, then. I guess it was a read. The XXXXOsc getters
pehrhovey 0:439354122597 671 // take the channel number and use it to call
pehrhovey 0:439354122597 672 // Osc_CreateMessage() which adds a new message to the outgoing
pehrhovey 0:439354122597 673 // stack
pehrhovey 0:439354122597 674
pehrhovey 0:439354122597 675 int size = (*blobPropertyGet)( propertyIndex, (uchar*)Osc->scratch1, OSC_SCRATCH_SIZE );
pehrhovey 0:439354122597 676 snprintf( Osc->scratch2, OSC_SCRATCH_SIZE, "/%s/%s", subsystemName, blobPropertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 677 Osc_CreateMessage( channel, Osc->scratch2, ",b", Osc->scratch1, size );
pehrhovey 0:439354122597 678
pehrhovey 0:439354122597 679 }
pehrhovey 0:439354122597 680
pehrhovey 0:439354122597 681 return CONTROLLER_OK;
pehrhovey 0:439354122597 682 }
pehrhovey 0:439354122597 683
pehrhovey 0:439354122597 684 /**
pehrhovey 0:439354122597 685 Receive an OSC blob for a subsystem with indexes.
pehrhovey 0:439354122597 686 You'll usually want to call this when the OSC system calls you with a new message.
pehrhovey 0:439354122597 687 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 688 by the OSC system.
pehrhovey 0:439354122597 689 @param message The OSC message being received. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 690 @param length The length of the incoming message. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 691 @param indexCount The number of indexes in your subsystem.
pehrhovey 0:439354122597 692 @param subsystemName The name of your subsystem.
pehrhovey 0:439354122597 693 @param blobPropertySet A pointer to the function to be called in order to write a property of your subsystem.
pehrhovey 0:439354122597 694 @param blobPropertyGet A pointer to the function to be called in order to read a property of your subsystem.
pehrhovey 0:439354122597 695 @param blobPropertyNames An array of all the property names in your subsystem.
pehrhovey 0:439354122597 696 \ingroup OSCAPI
pehrhovey 0:439354122597 697
pehrhovey 0:439354122597 698 \par Example
pehrhovey 0:439354122597 699 \code
pehrhovey 0:439354122597 700 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 701 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 702 {
pehrhovey 0:439354122597 703 int status = Osc_IndexBlobReceiverHelper( channel, message, length, 2,
pehrhovey 0:439354122597 704 MySubsystemOsc_Name,
pehrhovey 0:439354122597 705 MySubsystemOsc_BlobPropertySet, MySubsystemOsc_BlobPropertyGet,
pehrhovey 0:439354122597 706 MySubsystemOsc_BlobPropertyNames );
pehrhovey 0:439354122597 707
pehrhovey 0:439354122597 708 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 709 return Osc_SendError( channel, MySubsystemOsc_Name, status );
pehrhovey 0:439354122597 710 return CONTROLLER_OK;
pehrhovey 0:439354122597 711 }
pehrhovey 0:439354122597 712 \endcode
pehrhovey 0:439354122597 713 */
pehrhovey 0:439354122597 714 int Osc_IndexBlobReceiverHelper( int channel, char* message, int length,
pehrhovey 0:439354122597 715 int indexCount, char* subsystemName,
pehrhovey 0:439354122597 716 int (*blobPropertySet)( int index, int property, uchar* buffer, int length ),
pehrhovey 0:439354122597 717 int (*blobPropertyGet)( int index, int property, uchar* buffer, int length ),
pehrhovey 0:439354122597 718 char* blobPropertyNames[] )
pehrhovey 0:439354122597 719 {
pehrhovey 0:439354122597 720 // Look for the next slash - being the one that separates the index
pehrhovey 0:439354122597 721 // from the property. Note that this won't go off on a search through the buffer
pehrhovey 0:439354122597 722 // since there will soon be a string terminator (i.e. a 0)
pehrhovey 0:439354122597 723 char* prop = strchr( message, '/' );
pehrhovey 0:439354122597 724 if ( prop == NULL )
pehrhovey 0:439354122597 725 return CONTROLLER_ERROR_BAD_FORMAT;
pehrhovey 0:439354122597 726
pehrhovey 0:439354122597 727 // Now that we know where the property is, we can see if we can find it.
pehrhovey 0:439354122597 728 // This is a little cheap, since we're also implying that there are no
pehrhovey 0:439354122597 729 // more address terms after the property. That is, if testing for "speed", while
pehrhovey 0:439354122597 730 // "speed" would match, "speed/other_stuff" would not.
pehrhovey 0:439354122597 731 int propertyIndex = Osc_PropertyLookup( blobPropertyNames, prop + 1 );
pehrhovey 0:439354122597 732 if ( propertyIndex == -1 )
pehrhovey 0:439354122597 733 return CONTROLLER_ERROR_UNKNOWN_PROPERTY;
pehrhovey 0:439354122597 734
pehrhovey 0:439354122597 735 // Here's where we try to understand what index we got. In the world of
pehrhovey 0:439354122597 736 // OSC, this could be a pattern. So while we could get "0/speed" we could
pehrhovey 0:439354122597 737 // also get "*/speed" or "[0-4]/speed". This is kind of a drag, but it is
pehrhovey 0:439354122597 738 // quite nice from the user's perspective.
pehrhovey 0:439354122597 739 // So to deal with this take a look at the text "0" or "{1,2}" or whatever
pehrhovey 0:439354122597 740 // and produce either a nice integer in the simplest case or a set of bits
pehrhovey 0:439354122597 741 // where each bit corresponds to one of the indicies. Clearly we don't have
pehrhovey 0:439354122597 742 // to go crazy, since there are only a small finite number of them.
pehrhovey 0:439354122597 743 // Osc_NumberMatch() does the work for us, producing either number = -1 and
pehrhovey 0:439354122597 744 // bits == -1 if there was no index match, or number != -1 for there was a single
pehrhovey 0:439354122597 745 // number, or bits != -1 if there were several.
pehrhovey 0:439354122597 746
pehrhovey 0:439354122597 747 // note that we tweak the string a bit here to make sure the next '/' is not
pehrhovey 0:439354122597 748 // mixed up with this. Insert a string terminator.
pehrhovey 0:439354122597 749 *prop = 0;
pehrhovey 0:439354122597 750
pehrhovey 0:439354122597 751 int bits;
pehrhovey 0:439354122597 752 int number = Osc_NumberMatch( indexCount, message, &bits );
pehrhovey 0:439354122597 753 if ( number == -1 && bits == -1 )
pehrhovey 0:439354122597 754 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 755
pehrhovey 0:439354122597 756 // We tweaked the '/' before - now put it back
pehrhovey 0:439354122597 757 *prop = '/';
pehrhovey 0:439354122597 758
pehrhovey 0:439354122597 759 // Sometime after the address, the data tag begins - this is the description
pehrhovey 0:439354122597 760 // of the data in the rest of the message. It starts with a comma. Return
pehrhovey 0:439354122597 761 // where it is into 'type'. If there is no comma, this is bad.
pehrhovey 0:439354122597 762 char* type = Osc_FindDataTag( message, length );
pehrhovey 0:439354122597 763 if ( type == NULL )
pehrhovey 0:439354122597 764 return CONTROLLER_ERROR_NO_TYPE_TAG;
pehrhovey 0:439354122597 765
pehrhovey 0:439354122597 766 // We can tell if there's data by seeing if the character after the comma
pehrhovey 0:439354122597 767 // is a zero or not.
pehrhovey 0:439354122597 768 if ( type[ 1 ] == 'b' || type[ 1 ] == 's' )
pehrhovey 0:439354122597 769 {
pehrhovey 0:439354122597 770 // If there was blob or string data, it was a WRITE.
pehrhovey 0:439354122597 771 // So, sort of scanf-like, go get the data. Here we pass in where the data is
pehrhovey 0:439354122597 772 // thanks to the previous routine and then specify what we expect to find there
pehrhovey 0:439354122597 773 // in tag terms (i.e. "b", "s"). Finally we pass in a set
pehrhovey 0:439354122597 774 // of pointers to the data types we want to extract. Osc_ExtractData()
pehrhovey 0:439354122597 775 // will rummage around in the message magically grabbing values for you,
pehrhovey 0:439354122597 776 // reporting how many it got. It will grab convert strings if necessary.
pehrhovey 0:439354122597 777 unsigned char *buffer;
pehrhovey 0:439354122597 778 int size;
pehrhovey 0:439354122597 779 int count = Osc_ExtractData( type, "b", &buffer, &size );
pehrhovey 0:439354122597 780 if ( count != 1 )
pehrhovey 0:439354122597 781 return CONTROLLER_ERROR_INCORRECT_DATA_TYPE;
pehrhovey 0:439354122597 782
pehrhovey 0:439354122597 783 // Now with the data we need to decide what to do with it.
pehrhovey 0:439354122597 784 // Is there one or many here?
pehrhovey 0:439354122597 785 if ( number != -1 )
pehrhovey 0:439354122597 786 (*blobPropertySet)( number, propertyIndex, buffer, size );
pehrhovey 0:439354122597 787 else
pehrhovey 0:439354122597 788 {
pehrhovey 0:439354122597 789 int index = 0;
pehrhovey 0:439354122597 790 while ( bits > 0 && index < indexCount )
pehrhovey 0:439354122597 791 {
pehrhovey 0:439354122597 792 if ( bits & 1 )
pehrhovey 0:439354122597 793 (*blobPropertySet)( index, propertyIndex, buffer, size );
pehrhovey 0:439354122597 794 bits >>= 1;
pehrhovey 0:439354122597 795 index++;
pehrhovey 0:439354122597 796 }
pehrhovey 0:439354122597 797 }
pehrhovey 0:439354122597 798 }
pehrhovey 0:439354122597 799 else
pehrhovey 0:439354122597 800 {
pehrhovey 0:439354122597 801 // No data, then. I guess it was a read. The XXXXOsc getters
pehrhovey 0:439354122597 802 // take the channel number and use it to call
pehrhovey 0:439354122597 803 // Osc_CreateMessage() which adds a new message to the outgoing
pehrhovey 0:439354122597 804 // stack
pehrhovey 0:439354122597 805 if ( number != -1 )
pehrhovey 0:439354122597 806 {
pehrhovey 0:439354122597 807
pehrhovey 0:439354122597 808 int size = (*blobPropertyGet)( number, propertyIndex, (uchar*)Osc->scratch1, OSC_SCRATCH_SIZE );
pehrhovey 0:439354122597 809 snprintf( Osc->scratch2, OSC_SCRATCH_SIZE, "/%s/%d/%s", subsystemName, number, blobPropertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 810 Osc_CreateMessage( channel, Osc->scratch2, ",b", Osc->scratch1, size );
pehrhovey 0:439354122597 811
pehrhovey 0:439354122597 812 }
pehrhovey 0:439354122597 813 else
pehrhovey 0:439354122597 814 {
pehrhovey 0:439354122597 815 int index = 0;
pehrhovey 0:439354122597 816 while ( bits > 0 && index < indexCount )
pehrhovey 0:439354122597 817 {
pehrhovey 0:439354122597 818 if ( bits & 1 )
pehrhovey 0:439354122597 819 {
pehrhovey 0:439354122597 820
pehrhovey 0:439354122597 821 int size = (*blobPropertyGet)( index, propertyIndex, (uchar*)Osc->scratch1, OSC_SCRATCH_SIZE );
pehrhovey 0:439354122597 822 snprintf( Osc->scratch2, OSC_SCRATCH_SIZE, "/%s/%d/%s", subsystemName, index, blobPropertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 823 Osc_CreateMessage( channel, Osc->scratch2, ",b", Osc->scratch1, size );
pehrhovey 0:439354122597 824
pehrhovey 0:439354122597 825 }
pehrhovey 0:439354122597 826 bits >>= 1;
pehrhovey 0:439354122597 827 index++;
pehrhovey 0:439354122597 828 }
pehrhovey 0:439354122597 829 }
pehrhovey 0:439354122597 830 }
pehrhovey 0:439354122597 831
pehrhovey 0:439354122597 832 return CONTROLLER_OK;
pehrhovey 0:439354122597 833 }
pehrhovey 0:439354122597 834
pehrhovey 0:439354122597 835 /**
pehrhovey 0:439354122597 836 Receive an integer for a subsystem with no indexes.
pehrhovey 0:439354122597 837 You'll usually want to call this when the OSC system calls you with a new message.
pehrhovey 0:439354122597 838 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 839 by the OSC system.
pehrhovey 0:439354122597 840 @param message The OSC message being received. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 841 @param length The length of the incoming message. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 842 @param subsystemName The name of your subsystem.
pehrhovey 0:439354122597 843 @param propertySet A pointer to the function to be called in order to write a property of your subsystem.
pehrhovey 0:439354122597 844 @param propertyGet A pointer to the function to be called in order to read a property of your subsystem.
pehrhovey 0:439354122597 845 @param propertyNames An array of all the property names in your subsystem.
pehrhovey 0:439354122597 846 \ingroup OSCAPI
pehrhovey 0:439354122597 847
pehrhovey 0:439354122597 848 \par Example
pehrhovey 0:439354122597 849 \code
pehrhovey 0:439354122597 850 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 851 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 852 {
pehrhovey 0:439354122597 853 int status = Osc_IntReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 854 MySubsystemOsc_Name,
pehrhovey 0:439354122597 855 MySubsystemOsc_PropertySet, MySubsystemOsc_PropertyGet,
pehrhovey 0:439354122597 856 MySubsystemOsc_PropertyNames );
pehrhovey 0:439354122597 857
pehrhovey 0:439354122597 858 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 859 return Osc_SendError( channel, MySubsystemOsc_Name, status );
pehrhovey 0:439354122597 860 return CONTROLLER_OK;
pehrhovey 0:439354122597 861 }
pehrhovey 0:439354122597 862 \endcode
pehrhovey 0:439354122597 863 */
pehrhovey 0:439354122597 864 int Osc_IntReceiverHelper( int channel, char* message, int length,
pehrhovey 0:439354122597 865 char* subsystemName,
pehrhovey 0:439354122597 866 int (*propertySet)( int property, int value ),
pehrhovey 0:439354122597 867 int (*propertyGet)( int property ),
pehrhovey 0:439354122597 868 char* propertyNames[] )
pehrhovey 0:439354122597 869 {
pehrhovey 0:439354122597 870 if( *message == '\0' || *message == ' ' ) // first, try to see if it was a property "help" query
pehrhovey 0:439354122597 871 {
pehrhovey 0:439354122597 872 int i = 0;
pehrhovey 0:439354122597 873 while( true )
pehrhovey 0:439354122597 874 {
pehrhovey 0:439354122597 875 if( propertyNames[i] != 0 )
pehrhovey 0:439354122597 876 {
pehrhovey 0:439354122597 877
pehrhovey 0:439354122597 878 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s", subsystemName );
pehrhovey 0:439354122597 879 Osc_CreateMessage( channel, Osc->scratch1, ",s", propertyNames[i] );
pehrhovey 0:439354122597 880
pehrhovey 0:439354122597 881 i++;
pehrhovey 0:439354122597 882 }
pehrhovey 0:439354122597 883 else
pehrhovey 0:439354122597 884 return CONTROLLER_OK;
pehrhovey 0:439354122597 885 }
pehrhovey 0:439354122597 886 }
pehrhovey 0:439354122597 887
pehrhovey 0:439354122597 888 int propertyIndex = Osc_PropertyLookup( propertyNames, message );
pehrhovey 0:439354122597 889 if ( propertyIndex == -1 )
pehrhovey 0:439354122597 890 return CONTROLLER_ERROR_UNKNOWN_PROPERTY;
pehrhovey 0:439354122597 891
pehrhovey 0:439354122597 892 /*
pehrhovey 0:439354122597 893 int bits;
pehrhovey 0:439354122597 894 int number = Osc_NumberMatch( indexCount, message, &bits );
pehrhovey 0:439354122597 895 if ( number == -1 && bits == -1 )
pehrhovey 0:439354122597 896 return Osc_SubsystemError( channel, subsystemName, "Bad index" );
pehrhovey 0:439354122597 897 */
pehrhovey 0:439354122597 898
pehrhovey 0:439354122597 899 // Sometime after the address, the data tag begins - this is the description
pehrhovey 0:439354122597 900 // of the data in the rest of the message. It starts with a comma. Return
pehrhovey 0:439354122597 901 // where it is into 'type'. If there is no comma, this is bad.
pehrhovey 0:439354122597 902 char* type = Osc_FindDataTag( message, length );
pehrhovey 0:439354122597 903 if ( type == NULL )
pehrhovey 0:439354122597 904 return CONTROLLER_ERROR_NO_TYPE_TAG;
pehrhovey 0:439354122597 905
pehrhovey 0:439354122597 906 // We can tell if there's data by seeing if the character after the comma
pehrhovey 0:439354122597 907 // is a zero or not.
pehrhovey 0:439354122597 908 if ( type[ 1 ] == 'i' || type[ 1 ] == 'f' )
pehrhovey 0:439354122597 909 {
pehrhovey 0:439354122597 910 // If there was int or float data, it was a WRITE.
pehrhovey 0:439354122597 911 // So, sort of scanff-like, go get the data. Here we pass in where the data is
pehrhovey 0:439354122597 912 // thanks to the previous routine and then specify what we expect to find there
pehrhovey 0:439354122597 913 // in tag terms (i.e. "i", "s", "f" and others). Finally we pass in a set
pehrhovey 0:439354122597 914 // of pointers to the data types we want to extract. Osc_ExtractData()
pehrhovey 0:439354122597 915 // will rummage around in the message magically grabbing values for you,
pehrhovey 0:439354122597 916 // reporting how many it got. It will convert ints and floats if necessary.
pehrhovey 0:439354122597 917 int value;
pehrhovey 0:439354122597 918 int count = Osc_ExtractData( type, "i", &value );
pehrhovey 0:439354122597 919 if ( count != 1 )
pehrhovey 0:439354122597 920 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 921
pehrhovey 0:439354122597 922 (*propertySet)( propertyIndex, value );
pehrhovey 0:439354122597 923 }
pehrhovey 0:439354122597 924 else
pehrhovey 0:439354122597 925 {
pehrhovey 0:439354122597 926 // No data, then. I guess it was a read. The XXXXOsc getters
pehrhovey 0:439354122597 927 // take the channel number and use it to call
pehrhovey 0:439354122597 928 // Osc_CreateMessage() which adds a new message to the outgoing
pehrhovey 0:439354122597 929 // stack
pehrhovey 0:439354122597 930 int value = (*propertyGet)( propertyIndex );
pehrhovey 0:439354122597 931
pehrhovey 0:439354122597 932 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", subsystemName, propertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 933 Osc_CreateMessage( channel, Osc->scratch1, ",i", value );
pehrhovey 0:439354122597 934
pehrhovey 0:439354122597 935 }
pehrhovey 0:439354122597 936
pehrhovey 0:439354122597 937 return CONTROLLER_OK;
pehrhovey 0:439354122597 938 }
pehrhovey 0:439354122597 939
pehrhovey 0:439354122597 940 /**
pehrhovey 0:439354122597 941 Receive data for a subsystem that receives a variety of different data types.
pehrhovey 0:439354122597 942 An example of this kind of situation is the network system - you have a variety of different properties,
pehrhovey 0:439354122597 943 several of which are both ints and strings.
pehrhovey 0:439354122597 944
pehrhovey 0:439354122597 945 You'll usually want to call this when the OSC system calls you with a new message.
pehrhovey 0:439354122597 946 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 947 by the OSC system.
pehrhovey 0:439354122597 948 @param message The OSC message being received. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 949 @param length The length of the incoming message. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 950 @param subsystemName The name of your subsystem.
pehrhovey 0:439354122597 951 @param propertySet A pointer to the function to be called in order to write a property of your subsystem.
pehrhovey 0:439354122597 952 @param propertyGet A pointer to the function to be called in order to read a property of your subsystem.
pehrhovey 0:439354122597 953 @param propertyNames An array of all the property names in your subsystem.
pehrhovey 0:439354122597 954 \ingroup OSCAPI
pehrhovey 0:439354122597 955
pehrhovey 0:439354122597 956 \par Example
pehrhovey 0:439354122597 957 \code
pehrhovey 0:439354122597 958 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 959 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 960 {
pehrhovey 0:439354122597 961 int status = Osc_GeneralReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 962 MySubsystemOsc_Name,
pehrhovey 0:439354122597 963 MySubsystemOsc_PropertySet, MySubsystemOsc_PropertyGet,
pehrhovey 0:439354122597 964 MySubsystemOsc_PropertyNames );
pehrhovey 0:439354122597 965
pehrhovey 0:439354122597 966 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 967 return Osc_SendError( channel, MySubsystemOsc_Name, status );
pehrhovey 0:439354122597 968 return CONTROLLER_OK;
pehrhovey 0:439354122597 969 }
pehrhovey 0:439354122597 970 \endcode
pehrhovey 0:439354122597 971 */
pehrhovey 0:439354122597 972 int Osc_GeneralReceiverHelper( int channel, char* message, int length,
pehrhovey 0:439354122597 973 char* subsystemName,
pehrhovey 0:439354122597 974 int (*propertySet)( int property, char* typedata, int channel ),
pehrhovey 0:439354122597 975 int (*propertyGet)( int property, int channel ),
pehrhovey 0:439354122597 976 char* propertyNames[] )
pehrhovey 0:439354122597 977 {
pehrhovey 0:439354122597 978 if ( message == NULL )
pehrhovey 0:439354122597 979 return CONTROLLER_ERROR_NO_PROPERTY;
pehrhovey 0:439354122597 980
pehrhovey 0:439354122597 981 if( *message == '\0' || *message == ' ' ) // first, try to see if it was a property "help" query
pehrhovey 0:439354122597 982 {
pehrhovey 0:439354122597 983 int i = 0;
pehrhovey 0:439354122597 984 while( true )
pehrhovey 0:439354122597 985 {
pehrhovey 0:439354122597 986 if( propertyNames[i] != 0 )
pehrhovey 0:439354122597 987 {
pehrhovey 0:439354122597 988
pehrhovey 0:439354122597 989 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s", subsystemName );
pehrhovey 0:439354122597 990 Osc_CreateMessage( channel, Osc->scratch1, ",s", propertyNames[i] );
pehrhovey 0:439354122597 991
pehrhovey 0:439354122597 992 i++;
pehrhovey 0:439354122597 993 }
pehrhovey 0:439354122597 994 else
pehrhovey 0:439354122597 995 return CONTROLLER_OK;
pehrhovey 0:439354122597 996 }
pehrhovey 0:439354122597 997 }
pehrhovey 0:439354122597 998
pehrhovey 0:439354122597 999 int propertyIndex = Osc_PropertyLookup( propertyNames, message );
pehrhovey 0:439354122597 1000 if ( propertyIndex == -1 )
pehrhovey 0:439354122597 1001 return CONTROLLER_ERROR_UNKNOWN_PROPERTY;
pehrhovey 0:439354122597 1002
pehrhovey 0:439354122597 1003 /*
pehrhovey 0:439354122597 1004 int bits;
pehrhovey 0:439354122597 1005 int number = Osc_NumberMatch( indexCount, message, &bits );
pehrhovey 0:439354122597 1006 if ( number == -1 && bits == -1 )
pehrhovey 0:439354122597 1007 return Osc_SubsystemError( channel, subsystemName, "Bad index" );
pehrhovey 0:439354122597 1008 */
pehrhovey 0:439354122597 1009
pehrhovey 0:439354122597 1010 // Sometime after the address, the data tag begins - this is the description
pehrhovey 0:439354122597 1011 // of the data in the rest of the message. It starts with a comma. Return
pehrhovey 0:439354122597 1012 // where it is into 'type'. If there is no comma, this is bad.
pehrhovey 0:439354122597 1013 char* type = Osc_FindDataTag( message, length );
pehrhovey 0:439354122597 1014 if ( type == NULL )
pehrhovey 0:439354122597 1015 return Osc_SubsystemError( channel, subsystemName, "No type tag" );
pehrhovey 0:439354122597 1016
pehrhovey 0:439354122597 1017 // Debug( 1, "Osc General Type[1] = %d", type[ 1 ] );
pehrhovey 0:439354122597 1018
pehrhovey 0:439354122597 1019 // We can tell if there's data by seeing if the character after the comma
pehrhovey 0:439354122597 1020 // is a zero or not.
pehrhovey 0:439354122597 1021 if ( type[ 1 ] != 0 )
pehrhovey 0:439354122597 1022 {
pehrhovey 0:439354122597 1023 // If there was data, it was a WRITE.
pehrhovey 0:439354122597 1024 int status;
pehrhovey 0:439354122597 1025 status = (*propertySet)( propertyIndex, type, channel );
pehrhovey 0:439354122597 1026 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 1027 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 1028 }
pehrhovey 0:439354122597 1029 else
pehrhovey 0:439354122597 1030 {
pehrhovey 0:439354122597 1031 // No data, then. I guess it was a read. The XXXXOsc getters
pehrhovey 0:439354122597 1032 // take the channel number and use it to call
pehrhovey 0:439354122597 1033 // Osc_CreateMessage() which adds a new message to the outgoing
pehrhovey 0:439354122597 1034 // stack
pehrhovey 0:439354122597 1035
pehrhovey 0:439354122597 1036 (*propertyGet)( propertyIndex, channel );
pehrhovey 0:439354122597 1037 }
pehrhovey 0:439354122597 1038
pehrhovey 0:439354122597 1039 return CONTROLLER_OK;
pehrhovey 0:439354122597 1040 }
pehrhovey 0:439354122597 1041
pehrhovey 0:439354122597 1042 /**
pehrhovey 0:439354122597 1043 Receive integers for a subsystem with multiple indexes.
pehrhovey 0:439354122597 1044 An example of this kind of situation is the analog in system - you have 8 channels (indexes) and you're only
pehrhovey 0:439354122597 1045 going to be receiving integers.
pehrhovey 0:439354122597 1046
pehrhovey 0:439354122597 1047 You'll usually want to call this when the OSC system calls you with a new message.
pehrhovey 0:439354122597 1048 @param channel An index for which OSC channel is being used (usually USB or Ethernet). Usually provided for you
pehrhovey 0:439354122597 1049 by the OSC system.
pehrhovey 0:439354122597 1050 @param message The OSC message being received. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 1051 @param length The length of the incoming message. Usually provided for you by the OSC system.
pehrhovey 0:439354122597 1052 @param indexCount The number of indexes in your subsystem.
pehrhovey 0:439354122597 1053 @param subsystemName The name of your subsystem.
pehrhovey 0:439354122597 1054 @param propertySet A pointer to the function to be called in order to write a property of your subsystem.
pehrhovey 0:439354122597 1055 @param propertyGet A pointer to the function to be called in order to read a property of your subsystem.
pehrhovey 0:439354122597 1056 @param propertyNames An array of all the property names in your subsystem.
pehrhovey 0:439354122597 1057 \ingroup OSCAPI
pehrhovey 0:439354122597 1058
pehrhovey 0:439354122597 1059 \par Example
pehrhovey 0:439354122597 1060 \code
pehrhovey 0:439354122597 1061 // this is where OSC calls us when an incoming message for us has arrived
pehrhovey 0:439354122597 1062 int MySubsystemOsc_ReceiveMessage( int channel, char* message, int length )
pehrhovey 0:439354122597 1063 {
pehrhovey 0:439354122597 1064 int status = Osc_GeneralReceiverHelper( channel, message, length,
pehrhovey 0:439354122597 1065 5, // our index count
pehrhovey 0:439354122597 1066 MySubsystemOsc_Name,
pehrhovey 0:439354122597 1067 MySubsystemOsc_PropertySet, MySubsystemOsc_PropertyGet,
pehrhovey 0:439354122597 1068 MySubsystemOsc_PropertyNames );
pehrhovey 0:439354122597 1069
pehrhovey 0:439354122597 1070 if ( status != CONTROLLER_OK )
pehrhovey 0:439354122597 1071 return Osc_SendError( channel, MySubsystemOsc_Name, status );
pehrhovey 0:439354122597 1072 return CONTROLLER_OK;
pehrhovey 0:439354122597 1073 }
pehrhovey 0:439354122597 1074 \endcode
pehrhovey 0:439354122597 1075 */
pehrhovey 0:439354122597 1076
pehrhovey 0:439354122597 1077 //validIndex is a func to tell if an index is valid... some indexes between 0 and indexCount may not be valid
pehrhovey 0:439354122597 1078 int Osc_IndexIntReceiverHelper( int channel, char* message, int length,
pehrhovey 0:439354122597 1079 int indexCount, bool (*validIndex)( int index ), char* subsystemName,
pehrhovey 0:439354122597 1080 int (*propertySet)( int index, int property, int value ),
pehrhovey 0:439354122597 1081 int (*propertyGet)( int index, int property ),
pehrhovey 0:439354122597 1082 char* propertyNames[] )
pehrhovey 0:439354122597 1083 {
pehrhovey 0:439354122597 1084
pehrhovey 0:439354122597 1085 int i;
pehrhovey 0:439354122597 1086 if( *message == '\0' || *message == ' ' ) // first, try to see if it was an index "help" query
pehrhovey 0:439354122597 1087 {
pehrhovey 0:439354122597 1088 for ( i = 0; i < indexCount; i++ )
pehrhovey 0:439354122597 1089 {
pehrhovey 0:439354122597 1090 if(validIndex == NULL || (*validIndex)(i)){ //use index validator if we have one
pehrhovey 0:439354122597 1091 //list each valid index
pehrhovey 0:439354122597 1092 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s", subsystemName );
pehrhovey 0:439354122597 1093 Osc_CreateMessage( channel, Osc->scratch1, ",i", i );
pehrhovey 0:439354122597 1094 }
pehrhovey 0:439354122597 1095
pehrhovey 0:439354122597 1096 }
pehrhovey 0:439354122597 1097 return CONTROLLER_OK;
pehrhovey 0:439354122597 1098 }
pehrhovey 0:439354122597 1099 //printf("IIReHelper looking for next slash\r\n");
pehrhovey 0:439354122597 1100 // Look for the next slash - being the one that separates the index
pehrhovey 0:439354122597 1101 // from the property. Note that this won't go off on a search through the buffer
pehrhovey 0:439354122597 1102 // since there will soon be a string terminator (i.e. a 0)
pehrhovey 0:439354122597 1103 char* prop = strchr( message, '/' );
pehrhovey 0:439354122597 1104 char* propHelp = NULL;
pehrhovey 0:439354122597 1105 if ( prop == NULL ){ //index only, no property found /led/5
pehrhovey 0:439354122597 1106
pehrhovey 0:439354122597 1107 // printf("IIRhelper no property found for msg %s\r\n",message);
pehrhovey 0:439354122597 1108 propHelp = strchr(message,'\0');//try to get ptr to end of string
pehrhovey 0:439354122597 1109 //propHelp = message + strlen(message);//go to end of string this might have issues
pehrhovey 0:439354122597 1110
pehrhovey 0:439354122597 1111 }else{ //there is a '/', but is there anything after it?
pehrhovey 0:439354122597 1112
pehrhovey 0:439354122597 1113 // if( *(prop+1) =='\0'){
pehrhovey 0:439354122597 1114 // printf("IIRHelper - message ends in '/' so its malformed\r\n");
pehrhovey 0:439354122597 1115 // return CONTROLLER_ERROR_BAD_FORMAT;
pehrhovey 0:439354122597 1116 // }
pehrhovey 0:439354122597 1117 // printf("IIRhelper found potential property '%s' for msg %s\r\n",prop+1,message);
pehrhovey 0:439354122597 1118 }
pehrhovey 0:439354122597 1119
pehrhovey 0:439354122597 1120 // Here's where we try to understand what index we got. In the world of
pehrhovey 0:439354122597 1121 // OSC, this could be a pattern. So while we could get "0/speed" we could
pehrhovey 0:439354122597 1122 // also get "*/speed" or "[0-4]/speed". This is kind of a drag, but it is
pehrhovey 0:439354122597 1123 // quite nice from the user's perspective.
pehrhovey 0:439354122597 1124 // So to deal with this take a look at the text "0" or "{1,2}" or whatever
pehrhovey 0:439354122597 1125 // and produce either a nice integer in the simplest case or a set of bits
pehrhovey 0:439354122597 1126 // where each bit corresponds to one of the indicies. Clearly we don't have
pehrhovey 0:439354122597 1127 // to go crazy, since there are only a small finite number of them.
pehrhovey 0:439354122597 1128 // Osc_NumberMatch() does the work for us, producing either number = -1 and
pehrhovey 0:439354122597 1129 // bits == -1 if there was no index match, or number != -1 for there was a single
pehrhovey 0:439354122597 1130 // number, or bits != -1 if there were several.
pehrhovey 0:439354122597 1131
pehrhovey 0:439354122597 1132 // note that we tweak the string a bit here to make sure the next '/' is not
pehrhovey 0:439354122597 1133 // mixed up with this. Insert a string terminator.
pehrhovey 0:439354122597 1134 if(prop!=NULL)
pehrhovey 0:439354122597 1135 *prop = 0;
pehrhovey 0:439354122597 1136
pehrhovey 0:439354122597 1137 //printf("IIRHelper number matching %s to figure out index\r\n",message);
pehrhovey 0:439354122597 1138 int bits;
pehrhovey 0:439354122597 1139 //Need the number even to list properties (for constructing OSC addr)
pehrhovey 0:439354122597 1140 int number = Osc_NumberMatch( indexCount, message, &bits );
pehrhovey 0:439354122597 1141 if ( number == -1 && bits == -1 )
pehrhovey 0:439354122597 1142 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 1143
pehrhovey 0:439354122597 1144 //printf("IIRHelper number matching returned num=%d bits=%d for message %s \r\n",number,bits,message);
pehrhovey 0:439354122597 1145 // We tweaked the '/' before - now put it back
pehrhovey 0:439354122597 1146 if(prop!=NULL)
pehrhovey 0:439354122597 1147 *prop = '/';
pehrhovey 0:439354122597 1148
pehrhovey 0:439354122597 1149 //char* propHelp = prop + 1; //set propHelp to end of string
pehrhovey 0:439354122597 1150 // first, try to see if it was an index "help" query
pehrhovey 0:439354122597 1151 //print all properties if we do not have one
pehrhovey 0:439354122597 1152 if( *prop == '\0' || *prop == ' ' || prop==NULL )
pehrhovey 0:439354122597 1153 {
pehrhovey 0:439354122597 1154 //printf("IIRHelper listing properties for message %s \r\n",message);
pehrhovey 0:439354122597 1155 i = 0;
pehrhovey 0:439354122597 1156 while( true )
pehrhovey 0:439354122597 1157 {
pehrhovey 0:439354122597 1158 if( propertyNames[i] != 0 ) //list each valid property
pehrhovey 0:439354122597 1159 {
pehrhovey 0:439354122597 1160
pehrhovey 0:439354122597 1161 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s/%d", subsystemName, number );
pehrhovey 0:439354122597 1162 Osc_CreateMessage( channel, Osc->scratch1, ",s", propertyNames[i] );
pehrhovey 0:439354122597 1163
pehrhovey 0:439354122597 1164 i++;
pehrhovey 0:439354122597 1165 }
pehrhovey 0:439354122597 1166 else
pehrhovey 0:439354122597 1167 return CONTROLLER_OK;
pehrhovey 0:439354122597 1168 }
pehrhovey 0:439354122597 1169 }
pehrhovey 0:439354122597 1170
pehrhovey 0:439354122597 1171 // Now that we know where the property is, we can see if we can find it.
pehrhovey 0:439354122597 1172 // This is a little cheap, since we're also implying that there are no
pehrhovey 0:439354122597 1173 // more address terms after the property. That is, if testing for "speed", while
pehrhovey 0:439354122597 1174 // "speed" would match, "speed/other_stuff" would not.
pehrhovey 0:439354122597 1175 int propertyIndex = Osc_PropertyLookup( propertyNames, prop + 1 ); //do +1 to skip the '/'
pehrhovey 0:439354122597 1176 if ( propertyIndex == -1 ){
pehrhovey 0:439354122597 1177 return CONTROLLER_ERROR_UNKNOWN_PROPERTY;
pehrhovey 0:439354122597 1178 }else{
pehrhovey 0:439354122597 1179 // printf("IIRH: found prop index %d for property %s\r\n",propertyIndex,prop);
pehrhovey 0:439354122597 1180 }
pehrhovey 0:439354122597 1181
pehrhovey 0:439354122597 1182
pehrhovey 0:439354122597 1183 // Sometime after the address, the data tag begins - this is the description
pehrhovey 0:439354122597 1184 // of the data in the rest of the message. It starts with a comma. Return
pehrhovey 0:439354122597 1185 // where it is into 'type'. If there is no comma, this is bad.
pehrhovey 0:439354122597 1186 char* type = Osc_FindDataTag( message, length );
pehrhovey 0:439354122597 1187 if ( type == NULL )
pehrhovey 0:439354122597 1188 return CONTROLLER_ERROR_NO_TYPE_TAG;
pehrhovey 0:439354122597 1189 //else
pehrhovey 0:439354122597 1190 // printf("IIRHelper - found typetag %s\r\n",type);
pehrhovey 0:439354122597 1191
pehrhovey 0:439354122597 1192 // We can tell if there's data by seeing if the character after the comma
pehrhovey 0:439354122597 1193 // is a zero or not.
pehrhovey 0:439354122597 1194 if ( type[ 1 ] == 'i' || type[ 1 ] == 'f' )
pehrhovey 0:439354122597 1195 {
pehrhovey 0:439354122597 1196 // If there was int or float data, it was a WRITE.
pehrhovey 0:439354122597 1197 // So, sort of scanff-like, go get the data. Here we pass in where the data is
pehrhovey 0:439354122597 1198 // thanks to the previous routine and then specify what we expect to find there
pehrhovey 0:439354122597 1199 // in tag terms (i.e. "i", "s", "f" and others). Finally we pass in a set
pehrhovey 0:439354122597 1200 // of pointers to the data types we want to extract. Osc_ExtractData()
pehrhovey 0:439354122597 1201 // will rummage around in the message magically grabbing values for you,
pehrhovey 0:439354122597 1202 // reporting how many it got. It will convert ints and floats if necessary.
pehrhovey 0:439354122597 1203 int value;
pehrhovey 0:439354122597 1204 int count = Osc_ExtractData( type, "i", &value );
pehrhovey 0:439354122597 1205 if ( count != 1 )
pehrhovey 0:439354122597 1206 return CONTROLLER_ERROR_INCORRECT_DATA_TYPE;
pehrhovey 0:439354122597 1207
pehrhovey 0:439354122597 1208 // Now with the data we need to decide what to do with it.
pehrhovey 0:439354122597 1209 // Is there one or many here?
pehrhovey 0:439354122597 1210 if ( number != -1 )
pehrhovey 0:439354122597 1211 (*propertySet)( number, propertyIndex, value );
pehrhovey 0:439354122597 1212 else
pehrhovey 0:439354122597 1213 {
pehrhovey 0:439354122597 1214 int index = 0;
pehrhovey 0:439354122597 1215 while ( bits > 0 && index < indexCount )
pehrhovey 0:439354122597 1216 {
pehrhovey 0:439354122597 1217 if ( bits & 1 )
pehrhovey 0:439354122597 1218 (*propertySet)( index, propertyIndex, value );
pehrhovey 0:439354122597 1219 bits >>= 1;
pehrhovey 0:439354122597 1220 index++;
pehrhovey 0:439354122597 1221 }
pehrhovey 0:439354122597 1222 }
pehrhovey 0:439354122597 1223 }
pehrhovey 0:439354122597 1224 else
pehrhovey 0:439354122597 1225 {
pehrhovey 0:439354122597 1226 // No data, then. I guess it was a read. The XXXXOsc getters
pehrhovey 0:439354122597 1227 // take the channel number and use it to call
pehrhovey 0:439354122597 1228 // Osc_CreateMessage() which adds a new message to the outgoing
pehrhovey 0:439354122597 1229 // stack
pehrhovey 0:439354122597 1230 if ( number != -1 )
pehrhovey 0:439354122597 1231 {
pehrhovey 0:439354122597 1232 int value = (*propertyGet)( number, propertyIndex );
pehrhovey 0:439354122597 1233
pehrhovey 0:439354122597 1234 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s/%d/%s", subsystemName, number, propertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 1235 Osc_CreateMessage( channel, Osc->scratch1, ",i", value );
pehrhovey 0:439354122597 1236
pehrhovey 0:439354122597 1237 }
pehrhovey 0:439354122597 1238 else
pehrhovey 0:439354122597 1239 {
pehrhovey 0:439354122597 1240 int index = 0;
pehrhovey 0:439354122597 1241 while ( bits > 0 && index < indexCount )
pehrhovey 0:439354122597 1242 {
pehrhovey 0:439354122597 1243 if ( bits & 1 )
pehrhovey 0:439354122597 1244 {
pehrhovey 0:439354122597 1245 int value = (*propertyGet)( index, propertyIndex );
pehrhovey 0:439354122597 1246
pehrhovey 0:439354122597 1247 snprintf( Osc->scratch1, OSC_SCRATCH_SIZE, "/%s/%d/%s", subsystemName, index, propertyNames[ propertyIndex ] );
pehrhovey 0:439354122597 1248 Osc_CreateMessage( channel, Osc->scratch1, ",i", value );
pehrhovey 0:439354122597 1249
pehrhovey 0:439354122597 1250 }
pehrhovey 0:439354122597 1251 bits >>= 1;
pehrhovey 0:439354122597 1252 index++;
pehrhovey 0:439354122597 1253 }
pehrhovey 0:439354122597 1254 }
pehrhovey 0:439354122597 1255 }
pehrhovey 0:439354122597 1256
pehrhovey 0:439354122597 1257 return CONTROLLER_OK;
pehrhovey 0:439354122597 1258 }
pehrhovey 0:439354122597 1259
pehrhovey 0:439354122597 1260 int Osc_SendError( int channel, char* subsystemName, int error )
pehrhovey 0:439354122597 1261 {
pehrhovey 0:439354122597 1262 char* errorText;
pehrhovey 0:439354122597 1263 switch ( error )
pehrhovey 0:439354122597 1264 {
pehrhovey 0:439354122597 1265 case CONTROLLER_ERROR_UNKNOWN_PROPERTY:
pehrhovey 0:439354122597 1266 errorText = "Unknown Property";
pehrhovey 0:439354122597 1267 break;
pehrhovey 0:439354122597 1268 case CONTROLLER_ERROR_NO_PROPERTY:
pehrhovey 0:439354122597 1269 errorText = "No Property";
pehrhovey 0:439354122597 1270 break;
pehrhovey 0:439354122597 1271 case CONTROLLER_ERROR_INCORRECT_DATA_TYPE:
pehrhovey 0:439354122597 1272 errorText = "Incorrect Data Type";
pehrhovey 0:439354122597 1273 break;
pehrhovey 0:439354122597 1274 case CONTROLLER_ERROR_ILLEGAL_INDEX:
pehrhovey 0:439354122597 1275 errorText = "Bad Index";
pehrhovey 0:439354122597 1276 break;
pehrhovey 0:439354122597 1277 case CONTROLLER_ERROR_BAD_FORMAT:
pehrhovey 0:439354122597 1278 errorText = "Bad Format";
pehrhovey 0:439354122597 1279 break;
pehrhovey 0:439354122597 1280 case CONTROLLER_ERROR_NO_TYPE_TAG:
pehrhovey 0:439354122597 1281 errorText = "No Type Tag";
pehrhovey 0:439354122597 1282 break;
pehrhovey 0:439354122597 1283 case CONTROLLER_ERROR_BAD_DATA:
pehrhovey 0:439354122597 1284 errorText = "Bad Data";
pehrhovey 0:439354122597 1285 break;
pehrhovey 0:439354122597 1286 default:
pehrhovey 0:439354122597 1287 errorText = "Error";
pehrhovey 0:439354122597 1288 break;
pehrhovey 0:439354122597 1289 }
pehrhovey 0:439354122597 1290 return Osc_SubsystemError( channel, subsystemName, errorText );
pehrhovey 0:439354122597 1291 }
pehrhovey 0:439354122597 1292
pehrhovey 0:439354122597 1293 // OSC_ExtractData takes a buffer (i.e. a point in the incoming OSC message)
pehrhovey 0:439354122597 1294 // And a format e.g. "i" "bb", etc. and unpacks them to the var args
pehrhovey 0:439354122597 1295 // The var args need to be pointers to memory ready to receive the values.
pehrhovey 0:439354122597 1296 // In the case of blobs, there need to be three parameters: char** buffer,
pehrhovey 0:439354122597 1297 // and int* size on the param list. The buffer gets a pointer into the
pehrhovey 0:439354122597 1298 // right place in the incoming buffer and the size value gets assigned
pehrhovey 0:439354122597 1299 int Osc_ExtractData( char* buffer, char* format, ... )
pehrhovey 0:439354122597 1300 {
pehrhovey 0:439354122597 1301 // Set up to iterate through the arguments
pehrhovey 0:439354122597 1302 va_list args;
pehrhovey 0:439354122597 1303 va_start( args, format );
pehrhovey 0:439354122597 1304 int count = 0;
pehrhovey 0:439354122597 1305
pehrhovey 0:439354122597 1306 // figure out where the data starts
pehrhovey 0:439354122597 1307 int tagLen = strlen( buffer ) + 1;
pehrhovey 0:439354122597 1308 int pad = tagLen % 4;
pehrhovey 0:439354122597 1309 if ( pad != 0 )
pehrhovey 0:439354122597 1310 tagLen += ( 4 - pad );
pehrhovey 0:439354122597 1311 char* data = buffer + tagLen;
pehrhovey 0:439354122597 1312
pehrhovey 0:439354122597 1313 // Going to be walking the tag string, the format string and the data
pehrhovey 0:439354122597 1314 char* fp;
pehrhovey 0:439354122597 1315 char* tp = buffer + 1; // need to skip the comma ','
pehrhovey 0:439354122597 1316 bool cont = true;
pehrhovey 0:439354122597 1317 for ( fp = format; *fp && cont; fp++ )
pehrhovey 0:439354122597 1318 {
pehrhovey 0:439354122597 1319 cont = false;
pehrhovey 0:439354122597 1320 switch ( *fp )
pehrhovey 0:439354122597 1321 {
pehrhovey 0:439354122597 1322 case 'i':
pehrhovey 0:439354122597 1323 if ( *tp == 'i' )
pehrhovey 0:439354122597 1324 {
pehrhovey 0:439354122597 1325 *(va_arg( args, int* )) = Osc_ReadInt( data );
pehrhovey 0:439354122597 1326 data += 4;
pehrhovey 0:439354122597 1327 count++;
pehrhovey 0:439354122597 1328 cont = true;
pehrhovey 0:439354122597 1329 }
pehrhovey 0:439354122597 1330 if ( *tp == 'f' )
pehrhovey 0:439354122597 1331 {
pehrhovey 0:439354122597 1332 *(va_arg( args, int* )) = (int)Osc_ReadFloat( data );
pehrhovey 0:439354122597 1333 data += 4;
pehrhovey 0:439354122597 1334 count++;
pehrhovey 0:439354122597 1335 cont = true;
pehrhovey 0:439354122597 1336 }
pehrhovey 0:439354122597 1337
pehrhovey 0:439354122597 1338 break;
pehrhovey 0:439354122597 1339 case 'f':
pehrhovey 0:439354122597 1340 if ( *tp == 'f' )
pehrhovey 0:439354122597 1341 {
pehrhovey 0:439354122597 1342 *(va_arg( args, float* )) = Osc_ReadFloat( data );
pehrhovey 0:439354122597 1343 data += 4;
pehrhovey 0:439354122597 1344 count++;
pehrhovey 0:439354122597 1345 cont = true;
pehrhovey 0:439354122597 1346 }
pehrhovey 0:439354122597 1347 if ( *tp == 'i' )
pehrhovey 0:439354122597 1348 {
pehrhovey 0:439354122597 1349 *(va_arg( args, float* )) = (float)Osc_ReadInt( data );
pehrhovey 0:439354122597 1350 data += 4;
pehrhovey 0:439354122597 1351 count++;
pehrhovey 0:439354122597 1352 cont = true;
pehrhovey 0:439354122597 1353 }
pehrhovey 0:439354122597 1354 break;
pehrhovey 0:439354122597 1355 case 's':
pehrhovey 0:439354122597 1356 if ( *tp == 's' )
pehrhovey 0:439354122597 1357 {
pehrhovey 0:439354122597 1358 *(va_arg( args, char** )) = data;
pehrhovey 0:439354122597 1359 int len = strlen( data ) + 1;
pehrhovey 0:439354122597 1360 int pad = len % 4;
pehrhovey 0:439354122597 1361 if ( pad != 0 )
pehrhovey 0:439354122597 1362 len += ( 4 - pad );
pehrhovey 0:439354122597 1363 data += len;
pehrhovey 0:439354122597 1364 count++;
pehrhovey 0:439354122597 1365 cont = true;
pehrhovey 0:439354122597 1366 }
pehrhovey 0:439354122597 1367 break;
pehrhovey 0:439354122597 1368 case 'b':
pehrhovey 0:439354122597 1369 if ( *tp == 'b' )
pehrhovey 0:439354122597 1370 {
pehrhovey 0:439354122597 1371 int length = Osc_ReadInt( data );
pehrhovey 0:439354122597 1372 data += 4;
pehrhovey 0:439354122597 1373 *(va_arg( args, char** )) = data;
pehrhovey 0:439354122597 1374 *(va_arg( args, int* )) = length;
pehrhovey 0:439354122597 1375 int pad = length % 4;
pehrhovey 0:439354122597 1376 if ( pad != 0 )
pehrhovey 0:439354122597 1377 length += ( 4 - pad );
pehrhovey 0:439354122597 1378 data += length;
pehrhovey 0:439354122597 1379 count++;
pehrhovey 0:439354122597 1380 cont = true;
pehrhovey 0:439354122597 1381 }
pehrhovey 0:439354122597 1382 else
pehrhovey 0:439354122597 1383 {
pehrhovey 0:439354122597 1384 if ( *tp == 's' )
pehrhovey 0:439354122597 1385 {
pehrhovey 0:439354122597 1386 *(va_arg( args, char** )) = data;
pehrhovey 0:439354122597 1387 int len = strlen( data ) + 1;
pehrhovey 0:439354122597 1388 *(va_arg( args, int* )) = len;
pehrhovey 0:439354122597 1389 int pad = len % 4;
pehrhovey 0:439354122597 1390 if ( pad != 0 )
pehrhovey 0:439354122597 1391 len += ( 4 - pad );
pehrhovey 0:439354122597 1392 data += len;
pehrhovey 0:439354122597 1393 count++;
pehrhovey 0:439354122597 1394 cont = true;
pehrhovey 0:439354122597 1395 }
pehrhovey 0:439354122597 1396 }
pehrhovey 0:439354122597 1397 break;
pehrhovey 0:439354122597 1398 }
pehrhovey 0:439354122597 1399 tp++;
pehrhovey 0:439354122597 1400 }
pehrhovey 0:439354122597 1401
pehrhovey 0:439354122597 1402 //va_end( args );
pehrhovey 0:439354122597 1403
pehrhovey 0:439354122597 1404 return count;
pehrhovey 0:439354122597 1405 }
pehrhovey 0:439354122597 1406
pehrhovey 0:439354122597 1407 int Osc_ReadInt( char* buffer )
pehrhovey 0:439354122597 1408 {
pehrhovey 0:439354122597 1409 int v = *((int*)buffer);
pehrhovey 0:439354122597 1410 v = Osc_EndianSwap( v );
pehrhovey 0:439354122597 1411 return v;
pehrhovey 0:439354122597 1412 }
pehrhovey 0:439354122597 1413
pehrhovey 0:439354122597 1414 float Osc_ReadFloat( char* buffer )
pehrhovey 0:439354122597 1415 {
pehrhovey 0:439354122597 1416 int v = *((int*)buffer);
pehrhovey 0:439354122597 1417 v = Osc_EndianSwap( v );
pehrhovey 0:439354122597 1418 return *(float*)&v;
pehrhovey 0:439354122597 1419 }
pehrhovey 0:439354122597 1420
pehrhovey 0:439354122597 1421 /**
pehrhovey 0:439354122597 1422 Osc_CreateMessage
pehrhovey 0:439354122597 1423 Must put the "," as the first format letter
pehrhovey 0:439354122597 1424 */
pehrhovey 0:439354122597 1425 int Osc_CreateMessage( int channel, char* address, char* format, ... )
pehrhovey 0:439354122597 1426 {
pehrhovey 0:439354122597 1427 if ( address == NULL || format == NULL || *format != ',' )
pehrhovey 0:439354122597 1428 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 1429
pehrhovey 0:439354122597 1430 if ( channel < 0 || channel >= OSC_CHANNEL_COUNT )
pehrhovey 0:439354122597 1431 return CONTROLLER_ERROR_ILLEGAL_INDEX;
pehrhovey 0:439354122597 1432
pehrhovey 0:439354122597 1433 OscChannel* ch = Osc->channel[ channel ];
pehrhovey 0:439354122597 1434
pehrhovey 0:439354122597 1435 if ( !ch->running )
pehrhovey 0:439354122597 1436 return CONTROLLER_ERROR_SUBSYSTEM_INACTIVE;
pehrhovey 0:439354122597 1437
pehrhovey 0:439354122597 1438 if ( channel == OSC_CHANNEL_UDP && ch->replyAddress == 0 )
pehrhovey 0:439354122597 1439 return CONTROLLER_ERROR_NO_ADDRESS;
pehrhovey 0:439354122597 1440
pehrhovey 0:439354122597 1441 // Check for sender
pehrhovey 0:439354122597 1442 if ( ch->sendMessage == NULL )
pehrhovey 0:439354122597 1443 return CONTROLLER_ERROR_RESOURCE_MISSING;
pehrhovey 0:439354122597 1444
pehrhovey 0:439354122597 1445
pehrhovey 0:439354122597 1446
pehrhovey 0:439354122597 1447 if ( ch->bufferPointer == NULL )
pehrhovey 0:439354122597 1448 Osc_ResetChannel( ch );
pehrhovey 0:439354122597 1449
pehrhovey 0:439354122597 1450 // try to send this message - if there's a problem somewhere,
pehrhovey 0:439354122597 1451 // send the existing buffer - freeing up space, then try (once) again.
pehrhovey 0:439354122597 1452 int count = 0;
pehrhovey 0:439354122597 1453 char *bp;
pehrhovey 0:439354122597 1454 do
pehrhovey 0:439354122597 1455 {
pehrhovey 0:439354122597 1456 count++;
pehrhovey 0:439354122597 1457
pehrhovey 0:439354122597 1458 char* buffer = ch->bufferPointer;
pehrhovey 0:439354122597 1459 int length = ch->bufferRemaining;
pehrhovey 0:439354122597 1460
pehrhovey 0:439354122597 1461 bp = buffer;
pehrhovey 0:439354122597 1462
pehrhovey 0:439354122597 1463 // First message in the buffer?
pehrhovey 0:439354122597 1464 if ( bp == ch->buffer )
pehrhovey 0:439354122597 1465 {
pehrhovey 0:439354122597 1466 bp = Osc_CreateBundle( bp, &length, 0, 0 );
pehrhovey 0:439354122597 1467 if ( bp == NULL )
pehrhovey 0:439354122597 1468 return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
pehrhovey 0:439354122597 1469 }
pehrhovey 0:439354122597 1470
pehrhovey 0:439354122597 1471 // Make room for the new message
pehrhovey 0:439354122597 1472 int* lp = (int *)bp;
pehrhovey 0:439354122597 1473 bp += 4;
pehrhovey 0:439354122597 1474 length -= 4;
pehrhovey 0:439354122597 1475
pehrhovey 0:439354122597 1476 // remember the start of the message
pehrhovey 0:439354122597 1477 char* mp = bp;
pehrhovey 0:439354122597 1478
pehrhovey 0:439354122597 1479 if ( length > 0 )
pehrhovey 0:439354122597 1480 {
pehrhovey 0:439354122597 1481 // Set up to iterate through the arguments
pehrhovey 0:439354122597 1482 va_list args;
pehrhovey 0:439354122597 1483 va_start( args, format );
pehrhovey 0:439354122597 1484
pehrhovey 0:439354122597 1485 bp = Osc_CreateMessageInternal( bp, &length, address, format, args );
pehrhovey 0:439354122597 1486
pehrhovey 0:439354122597 1487 //va_end( args );
pehrhovey 0:439354122597 1488 }
pehrhovey 0:439354122597 1489 else
pehrhovey 0:439354122597 1490 bp = 0;
pehrhovey 0:439354122597 1491
pehrhovey 0:439354122597 1492 if ( bp != 0 )
pehrhovey 0:439354122597 1493 {
pehrhovey 0:439354122597 1494 // Set the size
pehrhovey 0:439354122597 1495 *lp = Osc_EndianSwap( bp - mp );
pehrhovey 0:439354122597 1496
pehrhovey 0:439354122597 1497 ch->bufferPointer = bp;
pehrhovey 0:439354122597 1498 ch->bufferRemaining = length;
pehrhovey 0:439354122597 1499 ch->messages++;
pehrhovey 0:439354122597 1500 }
pehrhovey 0:439354122597 1501 else
pehrhovey 0:439354122597 1502 {
pehrhovey 0:439354122597 1503 Osc_SendPacketInternal( ch );
pehrhovey 0:439354122597 1504 }
pehrhovey 0:439354122597 1505 } while ( bp == 0 && count == 1 );
pehrhovey 0:439354122597 1506
pehrhovey 0:439354122597 1507
pehrhovey 0:439354122597 1508 return ( bp != 0 ) ? CONTROLLER_OK : CONTROLLER_ERROR_ILLEGAL_PARAMETER_VALUE;
pehrhovey 0:439354122597 1509 }
pehrhovey 0:439354122597 1510
pehrhovey 0:439354122597 1511 int Osc_CreateMessageToBuf( char* bp, int* length, char* address, char* format, ... )
pehrhovey 0:439354122597 1512 {
pehrhovey 0:439354122597 1513 if ( address == NULL || format == NULL || *format != ',' )
pehrhovey 0:439354122597 1514 return CONTROLLER_ERROR_BAD_DATA;
pehrhovey 0:439354122597 1515
pehrhovey 0:439354122597 1516 va_list args;
pehrhovey 0:439354122597 1517 va_start( args, format );
pehrhovey 0:439354122597 1518
pehrhovey 0:439354122597 1519 Osc_CreateMessageInternal( bp, length, address, format, args );
pehrhovey 0:439354122597 1520 return CONTROLLER_OK;
pehrhovey 0:439354122597 1521 }
pehrhovey 0:439354122597 1522
pehrhovey 0:439354122597 1523 char* Osc_CreateMessageInternal( char* bp, int* length, char* address, char* format, va_list args )
pehrhovey 0:439354122597 1524 {
pehrhovey 0:439354122597 1525 // do the address
pehrhovey 0:439354122597 1526 bp = Osc_WritePaddedString( bp, length, address );
pehrhovey 0:439354122597 1527 if ( bp == NULL )
pehrhovey 0:439354122597 1528 return 0;
pehrhovey 0:439354122597 1529
pehrhovey 0:439354122597 1530 // do the type
pehrhovey 0:439354122597 1531 bp = Osc_WritePaddedString( bp, length, format );
pehrhovey 0:439354122597 1532 if ( bp == NULL )
pehrhovey 0:439354122597 1533 return 0;
pehrhovey 0:439354122597 1534
pehrhovey 0:439354122597 1535 // Going to be walking the tag string, the format string and the data
pehrhovey 0:439354122597 1536 // skip the ',' comma
pehrhovey 0:439354122597 1537 char* fp;
pehrhovey 0:439354122597 1538 bool cont = true;
pehrhovey 0:439354122597 1539 for ( fp = format + 1; *fp && cont; fp++ )
pehrhovey 0:439354122597 1540 {
pehrhovey 0:439354122597 1541 switch ( *fp )
pehrhovey 0:439354122597 1542 {
pehrhovey 0:439354122597 1543 case 'i':
pehrhovey 0:439354122597 1544 *length -= 4;
pehrhovey 0:439354122597 1545 if ( *length >= 0 )
pehrhovey 0:439354122597 1546 {
pehrhovey 0:439354122597 1547 int v = va_arg( args, int );
pehrhovey 0:439354122597 1548 v = Osc_EndianSwap( v );
pehrhovey 0:439354122597 1549 *((int*)bp) = v;
pehrhovey 0:439354122597 1550 bp += 4;
pehrhovey 0:439354122597 1551 }
pehrhovey 0:439354122597 1552 else
pehrhovey 0:439354122597 1553 cont = false;
pehrhovey 0:439354122597 1554 break;
pehrhovey 0:439354122597 1555 case 'f':
pehrhovey 0:439354122597 1556 *length -= 4;
pehrhovey 0:439354122597 1557 if ( *length >= 0 )
pehrhovey 0:439354122597 1558 {
pehrhovey 0:439354122597 1559 int v;
pehrhovey 0:439354122597 1560 *((float*)&v) = (float)( va_arg( args, double ) );
pehrhovey 0:439354122597 1561 v = Osc_EndianSwap( v );
pehrhovey 0:439354122597 1562 *((int*)bp) = v;
pehrhovey 0:439354122597 1563 bp += 4;
pehrhovey 0:439354122597 1564 }
pehrhovey 0:439354122597 1565 else
pehrhovey 0:439354122597 1566 cont = false;
pehrhovey 0:439354122597 1567 break;
pehrhovey 0:439354122597 1568 case 's':
pehrhovey 0:439354122597 1569 {
pehrhovey 0:439354122597 1570 char* s = va_arg( args, char* );
pehrhovey 0:439354122597 1571 bp = Osc_WritePaddedString( bp, length, s );
pehrhovey 0:439354122597 1572 if ( bp == NULL )
pehrhovey 0:439354122597 1573 cont = false;
pehrhovey 0:439354122597 1574 break;
pehrhovey 0:439354122597 1575 }
pehrhovey 0:439354122597 1576 case 'b':
pehrhovey 0:439354122597 1577 {
pehrhovey 0:439354122597 1578 char* b = va_arg( args, char* );
pehrhovey 0:439354122597 1579 int blen = va_arg( args, int );
pehrhovey 0:439354122597 1580 bp = Osc_WritePaddedBlob( bp, length, b, blen );
pehrhovey 0:439354122597 1581 if ( bp == NULL )
pehrhovey 0:439354122597 1582 cont = false;
pehrhovey 0:439354122597 1583 break;
pehrhovey 0:439354122597 1584 }
pehrhovey 0:439354122597 1585 default:
pehrhovey 0:439354122597 1586 cont = false;
pehrhovey 0:439354122597 1587 }
pehrhovey 0:439354122597 1588 }
pehrhovey 0:439354122597 1589
pehrhovey 0:439354122597 1590 return ( cont ) ? bp : NULL;
pehrhovey 0:439354122597 1591 }
pehrhovey 0:439354122597 1592
pehrhovey 0:439354122597 1593 char* Osc_CreateBundle( char* buffer, int* length, int a, int b )
pehrhovey 0:439354122597 1594 {
pehrhovey 0:439354122597 1595 char *bp = buffer;
pehrhovey 0:439354122597 1596
pehrhovey 0:439354122597 1597 // do the bundle bit
pehrhovey 0:439354122597 1598 bp = Osc_WritePaddedString( bp, length, "#bundle" );
pehrhovey 0:439354122597 1599 if ( bp == NULL )
pehrhovey 0:439354122597 1600 return 0;
pehrhovey 0:439354122597 1601
pehrhovey 0:439354122597 1602 // do the timetag
pehrhovey 0:439354122597 1603 bp = Osc_WriteTimetag( bp, length, a, b );
pehrhovey 0:439354122597 1604 if ( bp == NULL )
pehrhovey 0:439354122597 1605 return 0;
pehrhovey 0:439354122597 1606
pehrhovey 0:439354122597 1607 return bp;
pehrhovey 0:439354122597 1608 }
pehrhovey 0:439354122597 1609
pehrhovey 0:439354122597 1610
pehrhovey 0:439354122597 1611
pehrhovey 0:439354122597 1612 int Osc_NumberMatch( int count, char* message, int* bits )
pehrhovey 0:439354122597 1613 {
pehrhovey 0:439354122597 1614 int n = 0;
pehrhovey 0:439354122597 1615 int digits = 0;
pehrhovey 0:439354122597 1616 while ( isdigit( *message ) )
pehrhovey 0:439354122597 1617 {
pehrhovey 0:439354122597 1618 digits++;
pehrhovey 0:439354122597 1619 n = n * 10 + ( *message++ - '0' );
pehrhovey 0:439354122597 1620 }
pehrhovey 0:439354122597 1621
pehrhovey 0:439354122597 1622 *bits = -1;
pehrhovey 0:439354122597 1623 if ( n >= count )
pehrhovey 0:439354122597 1624 return -1;
pehrhovey 0:439354122597 1625
pehrhovey 0:439354122597 1626 switch ( *message )
pehrhovey 0:439354122597 1627 {
pehrhovey 0:439354122597 1628 case '*':
pehrhovey 0:439354122597 1629 case '?':
pehrhovey 0:439354122597 1630 case '[':
pehrhovey 0:439354122597 1631 case '{':
pehrhovey 0:439354122597 1632 {
pehrhovey 0:439354122597 1633 int i;
pehrhovey 0:439354122597 1634 int b = 0;
pehrhovey 0:439354122597 1635 char s[ 5 ];
pehrhovey 0:439354122597 1636 for ( i = count - 1; i >=0 ; i-- )
pehrhovey 0:439354122597 1637 {
pehrhovey 0:439354122597 1638 b <<= 1;
pehrhovey 0:439354122597 1639 sprintf( s, "%d", i );
pehrhovey 0:439354122597 1640 if ( Osc_PatternMatch( message, s ) )
pehrhovey 0:439354122597 1641 b |= 1;
pehrhovey 0:439354122597 1642 }
pehrhovey 0:439354122597 1643 *bits = b;
pehrhovey 0:439354122597 1644 return -1;
pehrhovey 0:439354122597 1645 }
pehrhovey 0:439354122597 1646 default:
pehrhovey 0:439354122597 1647 if ( digits == 0 )
pehrhovey 0:439354122597 1648 return -1;
pehrhovey 0:439354122597 1649 return n;
pehrhovey 0:439354122597 1650 }
pehrhovey 0:439354122597 1651 }
pehrhovey 0:439354122597 1652
pehrhovey 0:439354122597 1653 // Looks the named property up, returning an index
pehrhovey 0:439354122597 1654 // Note that we need to be careful - there may be other stuff there in the string
pehrhovey 0:439354122597 1655 // Probably best to eventually do something better with it.
pehrhovey 0:439354122597 1656 int Osc_PropertyLookup( char** properties, char* property )
pehrhovey 0:439354122597 1657 {
pehrhovey 0:439354122597 1658 char** p = properties;
pehrhovey 0:439354122597 1659 int index = 0;
pehrhovey 0:439354122597 1660 while (*p != NULL )
pehrhovey 0:439354122597 1661 {
pehrhovey 0:439354122597 1662 if ( strcmp( property, *p++ ) == 0 )
pehrhovey 0:439354122597 1663 return index;
pehrhovey 0:439354122597 1664 index++;
pehrhovey 0:439354122597 1665 }
pehrhovey 0:439354122597 1666 return -1;
pehrhovey 0:439354122597 1667 }
pehrhovey 0:439354122597 1668
pehrhovey 0:439354122597 1669 char *Osc_FindDataTag( char* message, int length )
pehrhovey 0:439354122597 1670 {
pehrhovey 0:439354122597 1671 while ( *message != ',' && length-- > 0 )
pehrhovey 0:439354122597 1672 message++;
pehrhovey 0:439354122597 1673 if ( length <= 0 )
pehrhovey 0:439354122597 1674 return NULL;
pehrhovey 0:439354122597 1675 else
pehrhovey 0:439354122597 1676 return message;
pehrhovey 0:439354122597 1677 }
pehrhovey 0:439354122597 1678
pehrhovey 0:439354122597 1679 char* Osc_WritePaddedString( char* buffer, int* length, char* string )
pehrhovey 0:439354122597 1680 {
pehrhovey 0:439354122597 1681 int tagLen = strlen( string ) + 1;
pehrhovey 0:439354122597 1682 int tagPadLen = tagLen;
pehrhovey 0:439354122597 1683 int pad = ( tagPadLen ) % 4;
pehrhovey 0:439354122597 1684 if ( pad != 0 )
pehrhovey 0:439354122597 1685 tagPadLen += ( 4 - pad );
pehrhovey 0:439354122597 1686
pehrhovey 0:439354122597 1687 *length -= tagPadLen;
pehrhovey 0:439354122597 1688
pehrhovey 0:439354122597 1689 if ( *length >= 0 )
pehrhovey 0:439354122597 1690 {
pehrhovey 0:439354122597 1691 strcpy( buffer, string );
pehrhovey 0:439354122597 1692 int i;
pehrhovey 0:439354122597 1693 buffer += tagLen;
pehrhovey 0:439354122597 1694 for ( i = tagLen; i < tagPadLen; i++ )
pehrhovey 0:439354122597 1695 *buffer++ = 0;
pehrhovey 0:439354122597 1696 }
pehrhovey 0:439354122597 1697 else
pehrhovey 0:439354122597 1698 return NULL;
pehrhovey 0:439354122597 1699
pehrhovey 0:439354122597 1700 return buffer;
pehrhovey 0:439354122597 1701 }
pehrhovey 0:439354122597 1702
pehrhovey 0:439354122597 1703 char* Osc_WritePaddedBlob( char* buffer, int* length, char* blob, int blen )
pehrhovey 0:439354122597 1704 {
pehrhovey 0:439354122597 1705 int i;
pehrhovey 0:439354122597 1706 int padLength = blen;
pehrhovey 0:439354122597 1707 int pad = ( padLength ) % 4;
pehrhovey 0:439354122597 1708 if ( pad != 0 )
pehrhovey 0:439354122597 1709 padLength += ( 4 - pad );
pehrhovey 0:439354122597 1710
pehrhovey 0:439354122597 1711 if ( *length < ( padLength + 4 ) )
pehrhovey 0:439354122597 1712 return 0;
pehrhovey 0:439354122597 1713
pehrhovey 0:439354122597 1714 // add the length of the blob
pehrhovey 0:439354122597 1715 int l = Osc_EndianSwap( blen );
pehrhovey 0:439354122597 1716 *((int*)buffer) = l;
pehrhovey 0:439354122597 1717 buffer += 4;
pehrhovey 0:439354122597 1718 *length -= 4;
pehrhovey 0:439354122597 1719
pehrhovey 0:439354122597 1720 memcpy( buffer, blob, blen );
pehrhovey 0:439354122597 1721 buffer += blen;
pehrhovey 0:439354122597 1722 // reduce the remaining buffer size
pehrhovey 0:439354122597 1723 *length -= padLength;
pehrhovey 0:439354122597 1724
pehrhovey 0:439354122597 1725 for ( i = blen; i < padLength; i++ )
pehrhovey 0:439354122597 1726 *buffer++ = 0;
pehrhovey 0:439354122597 1727
pehrhovey 0:439354122597 1728 return buffer;
pehrhovey 0:439354122597 1729 }
pehrhovey 0:439354122597 1730
pehrhovey 0:439354122597 1731 char* Osc_WriteTimetag( char* buffer, int* length, int a, int b )
pehrhovey 0:439354122597 1732 {
pehrhovey 0:439354122597 1733 if ( *length < 8 )
pehrhovey 0:439354122597 1734 return NULL;
pehrhovey 0:439354122597 1735
pehrhovey 0:439354122597 1736 *((int*)buffer) = Osc_EndianSwap( a );
pehrhovey 0:439354122597 1737 buffer += 4;
pehrhovey 0:439354122597 1738 *((int*)buffer) = Osc_EndianSwap( b );
pehrhovey 0:439354122597 1739 buffer += 4;
pehrhovey 0:439354122597 1740 *length -= 8;
pehrhovey 0:439354122597 1741
pehrhovey 0:439354122597 1742 return buffer;
pehrhovey 0:439354122597 1743 }
pehrhovey 0:439354122597 1744
pehrhovey 0:439354122597 1745 int Osc_EndianSwap( int a )
pehrhovey 0:439354122597 1746 {
pehrhovey 0:439354122597 1747 return ( ( a & 0x000000FF ) << 24 ) |
pehrhovey 0:439354122597 1748 ( ( a & 0x0000FF00 ) << 8 ) |
pehrhovey 0:439354122597 1749 ( ( a & 0x00FF0000 ) >> 8 ) |
pehrhovey 0:439354122597 1750 ( ( a & 0xFF000000 ) >> 24 );
pehrhovey 0:439354122597 1751
pehrhovey 0:439354122597 1752 }
pehrhovey 0:439354122597 1753
pehrhovey 0:439354122597 1754
pehrhovey 0:439354122597 1755
pehrhovey 0:439354122597 1756