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.
osc_sys.cpp@0:439354122597, 2010-03-17 (annotated)
- Committer:
- pehrhovey
- Date:
- Wed Mar 17 03:17:38 2010 +0000
- Revision:
- 0:439354122597
Who changed what in which revision?
User | Revision | Line number | New 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 |