792 lines
22 KiB
C++
792 lines
22 KiB
C++
/*
|
|
Written by Yotam Mann, The Center for New Music and Audio Technologies,
|
|
University of California, Berkeley. Copyright (c) 2012, The Regents of
|
|
the University of California (Regents).
|
|
|
|
Permission to use, copy, modify, distribute, and distribute modified versions
|
|
of this software and its documentation without fee and without a signed
|
|
licensing agreement, is hereby granted, provided that the above copyright
|
|
notice, this paragraph and the following two paragraphs appear in all copies,
|
|
modifications, and distributions.
|
|
|
|
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
|
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
|
|
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
|
|
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
|
|
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
|
|
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
|
|
*/
|
|
|
|
#include "OSCMessage.h"
|
|
#include "OSCMatch.h"
|
|
#include "OSCTiming.h"
|
|
|
|
extern osctime_t zerotime;
|
|
/*=============================================================================
|
|
CONSTRUCTORS / DESTRUCTOR
|
|
=============================================================================*/
|
|
|
|
//constructor with address
|
|
OSCMessage::OSCMessage(const char * _address){
|
|
setupMessage();
|
|
setAddress(_address);
|
|
}
|
|
|
|
//constructor with nothing
|
|
//just a placeholder since the message is invalid
|
|
OSCMessage::OSCMessage(){
|
|
setupMessage();
|
|
error = INVALID_OSC;
|
|
}
|
|
|
|
//variable length constructor
|
|
//for example OSCMessage msg("/address", "isf", 1, "two", 3.0);
|
|
/*
|
|
OSCMessage::OSCMessage(const char * _address, char * types, ... ){
|
|
setupMessage(_address);
|
|
}
|
|
*/
|
|
|
|
//sets up a new message
|
|
void OSCMessage::setupMessage(){
|
|
address = NULL;
|
|
//setup the attributes
|
|
dataCount = 0;
|
|
error = OSC_OK;
|
|
//setup the space for data
|
|
data = NULL;
|
|
//setup for filling the message
|
|
incomingBuffer = NULL;
|
|
incomingBufferSize = 0;
|
|
incomingBufferFree = 0;
|
|
clearIncomingBuffer();
|
|
//set the decode state
|
|
decodeState = STANDBY;
|
|
}
|
|
|
|
//DESTRUCTOR
|
|
OSCMessage::~OSCMessage(){
|
|
//free everything that needs to be freed
|
|
//free the address
|
|
free(address);
|
|
//free the data
|
|
empty();
|
|
//free the filling buffer
|
|
free(incomingBuffer);
|
|
}
|
|
|
|
OSCMessage& OSCMessage::empty(){
|
|
error = OSC_OK;
|
|
//free each of the data in the array
|
|
for (int i = 0; i < dataCount; i++){
|
|
const auto datum = getOSCData(i);
|
|
//explicitly destruct the data
|
|
//datum->~OSCData();
|
|
delete datum;
|
|
}
|
|
//and free the array
|
|
free(data);
|
|
data = NULL;
|
|
dataCount = 0;
|
|
decodeState = STANDBY;
|
|
clearIncomingBuffer();
|
|
return *this;
|
|
}
|
|
|
|
//COPY
|
|
OSCMessage::OSCMessage(OSCMessage * msg){
|
|
//start with a message with the same address
|
|
setupMessage();
|
|
setAddress(msg->address);
|
|
//add each of the data to the other message
|
|
for (int i = 0; i < msg->dataCount; i++){
|
|
add(msg->data[i]);
|
|
}
|
|
}
|
|
|
|
/*=============================================================================
|
|
GETTING DATA
|
|
=============================================================================*/
|
|
|
|
OSCData * OSCMessage::getOSCData(int position){
|
|
if (position < dataCount){
|
|
const auto datum = data[position];
|
|
return datum;
|
|
} else {
|
|
error = INDEX_OUT_OF_BOUNDS;
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
int32_t OSCMessage::getInt(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getInt();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
osctime_t OSCMessage::getTime(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getTime();
|
|
} else {
|
|
return zerotime;
|
|
}
|
|
}
|
|
float OSCMessage::getFloat(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getFloat();
|
|
} else {
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
double OSCMessage::getDouble(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getDouble();
|
|
} else {
|
|
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
bool OSCMessage::getBoolean(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getBoolean();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
int OSCMessage::getString(int position, char * buffer){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getString(buffer, datum->bytes);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int OSCMessage::getString(int position, char * buffer, int bufferSize){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
//the number of bytes to copy is the smaller between the buffer size and the datum's byte length
|
|
int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
|
|
return datum->getString(buffer, copyBytes);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int OSCMessage::getString(int position, char * buffer, int bufferSize, int offset, int size){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
//the number of bytes to copy is the smaller between the buffer size and the datum's byte length
|
|
int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
|
|
return datum->getString(buffer, copyBytes, offset, size);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
int OSCMessage::getBlob(int position, uint8_t * buffer){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getBlob(buffer);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int OSCMessage::getBlob(int position, uint8_t * buffer, int bufferSize){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getBlob(buffer, bufferSize);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int OSCMessage::getBlob(int position, uint8_t * buffer, int bufferSize, int offset, int size){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getBlob(buffer, bufferSize, offset, size);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
const uint8_t* OSCMessage::getBlob(int position) {
|
|
const auto datum = getOSCData(position);
|
|
if(!hasError()) {
|
|
return datum->getBlob();
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
uint32_t OSCMessage::getBlobLength(int position)
|
|
{
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->getBlobLength();
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
char OSCMessage::getType(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->type;
|
|
} else {
|
|
return '\0';
|
|
}
|
|
}
|
|
|
|
int OSCMessage::getDataLength(int position){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->bytes;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*=============================================================================
|
|
TESTING DATA
|
|
=============================================================================*/
|
|
|
|
bool OSCMessage::testType(int position, char type){
|
|
const auto datum = getOSCData(position);
|
|
if (!hasError()){
|
|
return datum->type == type;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool OSCMessage::isInt(int position){
|
|
return testType(position, 'i');
|
|
}
|
|
|
|
bool OSCMessage::isTime(int position){
|
|
return testType(position, 't');
|
|
}
|
|
|
|
|
|
bool OSCMessage::isFloat(int position){
|
|
return testType(position, 'f');
|
|
}
|
|
|
|
bool OSCMessage::isBlob(int position){
|
|
return testType(position, 'b');
|
|
}
|
|
|
|
bool OSCMessage::isChar(int position){
|
|
return testType(position, 'c');
|
|
}
|
|
|
|
bool OSCMessage::isString(int position){
|
|
return testType(position, 's');
|
|
}
|
|
|
|
bool OSCMessage::isDouble(int position){
|
|
return testType(position, 'd');
|
|
}
|
|
bool OSCMessage::isBoolean(int position){
|
|
return testType(position, 'T') || testType(position, 'F');
|
|
}
|
|
|
|
|
|
/*=============================================================================
|
|
PATTERN MATCHING
|
|
=============================================================================*/
|
|
|
|
int OSCMessage::match(const char * pattern, int addr_offset){
|
|
int pattern_offset;
|
|
int address_offset;
|
|
int ret = osc_match(address + addr_offset, pattern, &pattern_offset, &address_offset);
|
|
char * next = (char *) (address + addr_offset + pattern_offset);
|
|
if (ret==3){
|
|
return pattern_offset;
|
|
} else if (pattern_offset > 0 && *next == '/'){
|
|
return pattern_offset;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool OSCMessage::fullMatch( const char * pattern, int addr_offset){
|
|
int pattern_offset;
|
|
int address_offset;
|
|
int ret = osc_match(address + addr_offset, pattern, &pattern_offset, &address_offset );
|
|
return (ret==3);
|
|
}
|
|
|
|
bool OSCMessage::dispatch(const char * pattern, void (*callback)(OSCMessage &), int addr_offset){
|
|
if (fullMatch(pattern, addr_offset)){
|
|
callback(*this);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool OSCMessage::route(const char * pattern, void (*callback)(OSCMessage &, int), int initial_offset){
|
|
int match_offset = match(pattern, initial_offset);
|
|
if (match_offset>0){
|
|
callback(*this, match_offset + initial_offset);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*=============================================================================
|
|
ADDRESS
|
|
=============================================================================*/
|
|
|
|
int OSCMessage::getAddress(char * buffer, int offset){
|
|
int result = strlen(address);
|
|
if (result > offset)
|
|
strcpy(buffer, address+offset);
|
|
else
|
|
*buffer = 0;
|
|
return result - offset; // could be negative!
|
|
}
|
|
|
|
int OSCMessage::getAddress(char * buffer, int offset, int len){
|
|
int result = strlen(address);
|
|
|
|
if (result > offset)
|
|
{
|
|
strncpy(buffer, address+offset, len); // N.B. NOT guaranteed to null-terminate! So...
|
|
buffer[len-1] = 0; // ...prevent strlen() blowing up
|
|
}
|
|
else
|
|
*buffer = 0;
|
|
return strlen(buffer);
|
|
}
|
|
|
|
const char* OSCMessage::getAddress(){
|
|
return address;
|
|
}
|
|
|
|
int OSCMessage::getAddressLength(int offset)
|
|
{
|
|
int result = (int) strlen(address) - offset;
|
|
if (result < 0) // offset past end!
|
|
result = 0; // do the best we can
|
|
return result;
|
|
}
|
|
|
|
OSCMessage& OSCMessage::setAddress(const char * _address){
|
|
//free the previous address
|
|
free(address); // are we sure address was allocated?
|
|
//copy the address
|
|
char * addressMemory = (char *) malloc( (strlen(_address) + 1) * sizeof(char) );
|
|
if (addressMemory == NULL){
|
|
error = ALLOCFAILED;
|
|
address = NULL;
|
|
} else {
|
|
strcpy(addressMemory, _address);
|
|
address = addressMemory;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*=============================================================================
|
|
SIZE
|
|
=============================================================================*/
|
|
|
|
#ifdef SLOWpadcalculation
|
|
int OSCMessage::padSize(int _bytes){
|
|
int space = (_bytes + 3) / 4;
|
|
space *= 4;
|
|
return space - _bytes;
|
|
}
|
|
#else
|
|
static inline int padSize(int bytes) { return (4- (bytes&03))&3; }
|
|
#endif
|
|
//returns the number of OSCData in the OSCMessage
|
|
int OSCMessage::size(){
|
|
return dataCount;
|
|
}
|
|
|
|
int OSCMessage::bytes(){
|
|
int messageSize = 0;
|
|
//send the address
|
|
int addrLen = strlen(address) + 1;
|
|
messageSize += addrLen;
|
|
//padding amount
|
|
int addrPad = padSize(addrLen);
|
|
messageSize += addrPad;
|
|
//add the comma separator
|
|
messageSize += 1;
|
|
//add the types
|
|
messageSize += dataCount;
|
|
//pad the types
|
|
int typePad = padSize(dataCount + 1); //for the comma
|
|
if (typePad == 0){
|
|
typePad = 4; // to make sure the type string is null terminated
|
|
}
|
|
messageSize+=typePad;
|
|
//then the data
|
|
for (int i = 0; i < dataCount; i++){
|
|
const auto datum = getOSCData(i);
|
|
messageSize+=datum->bytes;
|
|
messageSize += padSize(datum->bytes);
|
|
}
|
|
return messageSize;
|
|
}
|
|
|
|
/*=============================================================================
|
|
ERROR HANDLING
|
|
=============================================================================*/
|
|
|
|
bool OSCMessage::hasError(){
|
|
if(error != OSC_OK) return true;
|
|
//test each of the data
|
|
for (int i = 0; i < dataCount; i++){
|
|
if(getOSCData(i)->error) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
OSCErrorCode OSCMessage::getError(){
|
|
return error;
|
|
}
|
|
|
|
/*=============================================================================
|
|
SENDING
|
|
=============================================================================*/
|
|
|
|
OSCMessage& OSCMessage::send(Print &p){
|
|
//don't send a message with errors
|
|
if (hasError()){
|
|
return *this;
|
|
}
|
|
uint8_t nullChar = '\0';
|
|
//send the address
|
|
int addrLen = strlen(address) + 1;
|
|
//padding amount
|
|
int addrPad = padSize(addrLen);
|
|
//write it to the stream
|
|
p.write((uint8_t *) address, addrLen);
|
|
//add the padding
|
|
while(addrPad--){
|
|
p.write(nullChar);
|
|
}
|
|
//add the comma separator
|
|
p.write((uint8_t) ',');
|
|
//add the types
|
|
#ifdef PAULSSUGGESTION
|
|
// Paul suggested buffering on the stack
|
|
// to improve performance. The problem is this could exhaust the stack
|
|
// for long complex messages
|
|
{
|
|
uint8_t typstr[dataCount];
|
|
|
|
for (int i = 0; i < dataCount; i++){
|
|
typstr[i] = getType(i);
|
|
}
|
|
p.write(typstr,dataCount);
|
|
}
|
|
#else
|
|
for (int i = 0; i < dataCount; i++){
|
|
p.write((uint8_t) getType(i));
|
|
}
|
|
#endif
|
|
//pad the types
|
|
int typePad = padSize(dataCount + 1); // 1 is for the comma
|
|
if (typePad == 0){
|
|
typePad = 4; // This is because the type string has to be null terminated
|
|
}
|
|
while(typePad--){
|
|
p.write(nullChar);
|
|
}
|
|
//write the data
|
|
for (int i = 0; i < dataCount; i++){
|
|
const auto datum = getOSCData(i);
|
|
if ((datum->type == 's') || (datum->type == 'b')){
|
|
p.write(datum->data.b, datum->bytes);
|
|
int dataPad = padSize(datum->bytes);
|
|
while(dataPad--){
|
|
p.write(nullChar);
|
|
}
|
|
} else if (datum->type == 'd'){
|
|
double d = BigEndian(datum->data.d);
|
|
uint8_t * ptr = (uint8_t *) &d;
|
|
p.write(ptr, 8);
|
|
} else if (datum->type == 't'){
|
|
osctime_t time = datum->data.time;
|
|
uint32_t d = BigEndian(time.seconds);
|
|
uint8_t * ptr = (uint8_t *) &d;
|
|
p.write(ptr, 4);
|
|
d = BigEndian(time.fractionofseconds);
|
|
ptr = (uint8_t *) &d;
|
|
p.write(ptr, 4);
|
|
|
|
} else if (datum->type == 'T' || datum->type == 'F')
|
|
{ }
|
|
else { // float or int
|
|
uint32_t i = BigEndian(datum->data.i);
|
|
uint8_t * ptr = (uint8_t *) &i;
|
|
p.write(ptr, datum->bytes);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*=============================================================================
|
|
FILLING
|
|
=============================================================================*/
|
|
|
|
OSCMessage& OSCMessage::fill(uint8_t incomingByte){
|
|
decode(incomingByte);
|
|
return *this;
|
|
}
|
|
|
|
OSCMessage& OSCMessage::fill(uint8_t * incomingBytes, int length){
|
|
while (length--){
|
|
decode(*incomingBytes++);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*=============================================================================
|
|
DECODING
|
|
=============================================================================*/
|
|
|
|
void OSCMessage::decodeAddress(){
|
|
setAddress((char *) incomingBuffer);
|
|
//change the error from invalid message
|
|
error = OSC_OK;
|
|
clearIncomingBuffer();
|
|
}
|
|
|
|
void OSCMessage::decodeType(uint8_t incomingByte){
|
|
char type = incomingByte;
|
|
add(type);
|
|
}
|
|
|
|
void OSCMessage::decodeData(uint8_t incomingByte){
|
|
//get the first OSCData to re-set
|
|
for (int i = 0; i < dataCount; i++){
|
|
const auto datum = getOSCData(i);
|
|
if (datum->error == INVALID_OSC){
|
|
//set the contents of datum with the data received
|
|
switch (datum->type){
|
|
case 'i':
|
|
if (incomingBufferSize == 4){
|
|
//parse the buffer as an int
|
|
union {
|
|
int32_t i;
|
|
uint8_t b[4];
|
|
} u;
|
|
memcpy(u.b, incomingBuffer, 4);
|
|
int32_t dataVal = BigEndian(u.i);
|
|
set(i, dataVal);
|
|
clearIncomingBuffer();
|
|
}
|
|
break;
|
|
case 'f':
|
|
if (incomingBufferSize == 4){
|
|
//parse the buffer as a float
|
|
union {
|
|
float f;
|
|
uint8_t b[4];
|
|
} u;
|
|
memcpy(u.b, incomingBuffer, 4);
|
|
float dataVal = BigEndian(u.f);
|
|
set(i, dataVal);
|
|
clearIncomingBuffer();
|
|
}
|
|
break;
|
|
case 'd':
|
|
if (incomingBufferSize == 8){
|
|
//parse the buffer as a double
|
|
union {
|
|
double d;
|
|
uint8_t b[8];
|
|
} u;
|
|
memcpy(u.b, incomingBuffer, 8);
|
|
double dataVal = BigEndian(u.d);
|
|
set(i, dataVal);
|
|
clearIncomingBuffer();
|
|
}
|
|
break;
|
|
case 't':
|
|
if (incomingBufferSize == 8){
|
|
//parse the buffer as a timetag
|
|
union {
|
|
osctime_t t;
|
|
uint8_t b[8];
|
|
} u;
|
|
memcpy(u.b, incomingBuffer, 8);
|
|
|
|
u.t.seconds = BigEndian(u.t.seconds);
|
|
u.t.fractionofseconds = BigEndian(u.t.fractionofseconds);
|
|
set(i, u.t);
|
|
clearIncomingBuffer();
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
if (incomingByte == 0){
|
|
char * str = (char *) incomingBuffer;
|
|
set(i, str);
|
|
clearIncomingBuffer();
|
|
decodeState = DATA_PADDING;
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (incomingBufferSize > 4){
|
|
//compute the expected blob size
|
|
union {
|
|
uint32_t i;
|
|
uint8_t b[4];
|
|
} u;
|
|
memcpy(u.b, incomingBuffer, 4);
|
|
uint32_t blobLength = BigEndian(u.i);
|
|
if (incomingBufferSize == (int)(blobLength + 4)){
|
|
set(i, incomingBuffer + 4, blobLength);
|
|
clearIncomingBuffer();
|
|
decodeState = DATA_PADDING;
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
//break out of the for loop once we've selected the first invalid message
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//does not validate the incoming OSC for correctness
|
|
void OSCMessage::decode(uint8_t incomingByte){
|
|
addToIncomingBuffer(incomingByte);
|
|
switch (decodeState){
|
|
case STANDBY:
|
|
if (incomingByte == '/'){
|
|
decodeState = ADDRESS;
|
|
}
|
|
break;
|
|
case ADDRESS:
|
|
if (incomingByte == 0){
|
|
//end of the address
|
|
//decode the address
|
|
decodeAddress();
|
|
//next state
|
|
decodeState = ADDRESS_PADDING;
|
|
}
|
|
break;
|
|
case ADDRESS_PADDING:
|
|
//it does not count the padding
|
|
if (incomingByte==','){
|
|
//next state
|
|
decodeState = TYPES;
|
|
clearIncomingBuffer();
|
|
}
|
|
break;
|
|
case TYPES:
|
|
if (incomingByte != 0){
|
|
//next state
|
|
decodeType(incomingByte);
|
|
} else {
|
|
decodeState = TYPES_PADDING;
|
|
}
|
|
//FALL THROUGH to test if it should go to the data state
|
|
case TYPES_PADDING: {
|
|
//compute the padding size for the types
|
|
//to determine the start of the data section
|
|
int typePad = padSize(dataCount + 1); // 1 is the comma
|
|
if (typePad == 0){
|
|
typePad = 4; // to make sure it will be null terminated
|
|
}
|
|
if (incomingBufferSize == (typePad + dataCount)){
|
|
clearIncomingBuffer();
|
|
decodeState = DATA;
|
|
}
|
|
}
|
|
break;
|
|
case DATA:
|
|
decodeData(incomingByte);
|
|
break;
|
|
case DATA_PADDING:{
|
|
//get the last valid data
|
|
for (int i = dataCount - 1; i >= 0; i--){
|
|
const auto datum = getOSCData(i);
|
|
if (datum->error == OSC_OK){
|
|
//compute the padding size for the data
|
|
int dataPad = padSize(datum->bytes);
|
|
// if there is no padding required, switch back to DATA, and don't clear the incomingBuffer because it holds next data
|
|
if (dataPad == 0){
|
|
decodeState = DATA;
|
|
}
|
|
else if (incomingBufferSize == dataPad){
|
|
clearIncomingBuffer();
|
|
decodeState = DATA;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case DONE:
|
|
break; // TODO: is this correct? - was missing from original code, it did this by default
|
|
}
|
|
}
|
|
|
|
|
|
/*=============================================================================
|
|
INCOMING BUFFER MANAGEMENT
|
|
=============================================================================*/
|
|
#define OSCPREALLOCATEIZE 16
|
|
void OSCMessage::addToIncomingBuffer(uint8_t incomingByte){
|
|
//realloc some space for the new byte and stick it on the end
|
|
if(incomingBufferFree>0)
|
|
{
|
|
incomingBuffer[incomingBufferSize++] = incomingByte;
|
|
incomingBufferFree--;
|
|
}
|
|
else
|
|
{
|
|
|
|
incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1 + OSCPREALLOCATEIZE);
|
|
if (incomingBuffer != NULL){
|
|
incomingBuffer[incomingBufferSize++] = incomingByte;
|
|
incomingBufferFree = OSCPREALLOCATEIZE;
|
|
} else {
|
|
error = ALLOCFAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
void OSCMessage::clearIncomingBuffer(){
|
|
incomingBuffer = (uint8_t *) realloc ( incomingBuffer, OSCPREALLOCATEIZE);
|
|
if (incomingBuffer != NULL){
|
|
incomingBufferFree = OSCPREALLOCATEIZE;
|
|
} else {
|
|
error = ALLOCFAILED;
|
|
incomingBuffer = NULL;
|
|
|
|
}
|
|
incomingBufferSize = 0;
|
|
}
|