/*! \file osc.c \brief Open Sound Control (OSC) client functions. */ //***************************************************************************** // // File Name : 'osc.c' // Title : Open Sound Control (OSC) client functions // Author : Pascal Stang - Copyright (C) 2002 // Bjoern Hartmann 2005 // Created : 10/30/2002 // Revised : 07/07/2005 // Version : 0.2 // Target MCU : Atmel AVR series // Editor Tabs : 4 // // Description : This code implements a subset of the OSC protocol and // messages. It is meant to be used with the OSC extension for the visual // programming and data-processing package Pure-Data (or PD). Note that // this code sends OSC messages over serial RS-232, not a network. You // must use these functions with a suitable OSC SERIAL server (receiver) // on a host machine. // // // This code is distributed under the GNU Public License // which can be found at http://www.gnu.org/licenses/gpl.txt // //***************************************************************************** #include #include #include #include #include "global.h" #include "buffer.h" #include "uart.h" #include "osc.h" // added by bjoern hartmann 2005-06-13: // PRG_RDB is no longer defined in avr-libc #ifndef PRG_RDB #define PRG_RDB(addr) pgm_read_byte(addr) #endif #define OSC_RXOP_WAITFORSTART 0 #define OSC_RXOP_READSIZE 1 #define OSC_RXOP_READADDR 2 #define OSC_RXOP_READTAG 3 #define OSC_RXOP_READARG 4 #define OSC_RXOP_READCHECKSUM 5 #define OSC_RXOP_READMSG 6 #define OSC_RXOP_SKIPMSG 7 #define OSC_RXOP_READARG1BYTE1 8 #define OSC_RXOP_READARG1BYTE2 9 #define OSC_RXOP_READARG1BYTE3 10 #define OSC_RXOP_READARG1BYTE4 11 #define OSC_RXOP_READTAGBYTE1 12 #define OSC_RXOP_READTAGBYTE2 13 #define OSC_RXOP_READTAGBYTE3 14 #define OSC_RXOP_READTAGBYTE4 15 // global variables // ready flag from uart extern volatile u08 uartReadyTx; // receive buffer cBuffer oscRxBuffer; // space for buffer in RAM static char oscRxData[OSC_MAX_RX_MSG_SIZE]; static u08 oscRxNextOp = OSC_RXOP_WAITFORSTART; u08 oscRxMsgSize; u08 oscRxReadBytes; u08 *oscRxAddr; u32 oscRxIntArg1; u32 oscRxIntArg2; u08 oscRxChecksum; typedef void (*voidOscIntFuncPtr)(char *, u32); volatile static voidOscIntFuncPtr oscRxIntFunc; // functions void oscInit(void) { // initialize uart (if not already done) uartInit(); // set the default communication rate uartSetBaudRate(115200); } void oscSendMessage(char *address) { // write OSC packet header, argument length = 0bytes oscWriteHeader(address, 0); // write OSC address to packet oscWriteString(address); // apply checksum oscWriteChecksum(); // send buffer uartSendTxBuffer(); // wait for completion, transmitter to be ready while(!uartReadyTx); } void oscSendMessageInt(char *address, u32 arg) { // write OSC packet header, argument length = 4bytes oscWriteHeader(address, 4+4); //added 4 bytes for type tag string // write OSC address to packet oscWriteString(address); // (bjoern) write type tag string oscWriteTypeTag(OSC_TYPE_TAG_INT); // copy arg to buffer bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg))+3) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg))+2) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg))+1) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg))+0) ); // apply checksum oscWriteChecksum(); // send buffer uartSendTxBuffer(); // wait for completion, transmitter to be ready while(!uartReadyTx); } void oscSendMessageIntInt(char *address, u32 arg1, u32 arg2) { // write OSC packet header, argument length = 8bytes oscWriteHeader(address, 8+4); //added 4 bytes for type tag string // write OSC address to packet oscWriteString(address); // (bjoern) write type tag string oscWriteTypeTag(OSC_TYPE_TAG_INTINT); // copy arg1 to buffer bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg1))+3) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg1))+2) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg1))+1) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg1))+0) ); // copy arg2 to buffer bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg2))+3) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg2))+2) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg2))+1) ); bufferAddToEnd(uartGetTxBuffer(), *(((unsigned char*)(&arg2))+0) ); // apply checksum oscWriteChecksum(); // send buffer uartSendTxBuffer(); // wait for completion, transmitter to be ready while(!uartReadyTx); } void oscSendMessageString(char *address, char *arg) { u08 len; // calculate length of argument string for(len=0; PRG_RDB(arg+len); len++); len++; // count a minumum of one null for termination if(len&0x03) // are pad bytes necessary? len += 4-(len&0x03); // add null pad bytes to reach multiple of four // write OSC packet header, argument length = 8bytes oscWriteHeader(address, len+4); //added 4 bytes for type tag string // write OSC address to packet oscWriteString(address); // (bjoern) write type tag string oscWriteTypeTag(OSC_TYPE_TAG_STRING); // write string buffer oscWriteString(arg); // apply checksum oscWriteChecksum(); // send buffer uartSendTxBuffer(); // wait for completion, transmitter to be ready while(!uartReadyTx); } void oscWriteHeader(char *address, u08 arglen) { u08 len; // write OSC packet header bufferAddToEnd(uartGetTxBuffer(), OSC_HEADER); // determine padded length of address for(len=0; PRG_RDB(address+len); len++); len++; // count a minumum of one null for termination if(len&0x03) // are pad bytes necessary? len += 4-(len&0x03); // add null pad bytes to reach multiple of four // write length to packet header bufferAddToEnd(uartGetTxBuffer(), len+arglen); } void oscWriteString(char *string) { u08 temp=1; u08 len=0; // write OSC string to packet // copy string's null-termination intentionally while(temp) { temp = PRG_RDB(string++); bufferAddToEnd(uartGetTxBuffer(), temp); len++; } // pad the string as necessary to reach a 4-byte multiple // Note: (len&0x03) == (len%4) //for(; (len&0x03); len++) while(len&0x03) { bufferAddToEnd(uartGetTxBuffer(), 0); len++; } } void oscWriteChecksum(void) { u08 i; u08 chksum = 0; // calculate checksum for(i=2; idatalength; i++) chksum += bufferGetAtIndex(uartGetTxBuffer(), i); // write checksum to packet bufferAddToEnd(uartGetTxBuffer(), chksum); } //added bjoern 2005-07-07 void oscWriteTypeTag(u08 type) { switch(type) { case OSC_TYPE_TAG_INT : bufferAddToEnd(uartGetTxBuffer(),','); bufferAddToEnd(uartGetTxBuffer(),'i'); bufferAddToEnd(uartGetTxBuffer(),0); bufferAddToEnd(uartGetTxBuffer(),0); break; case OSC_TYPE_TAG_INTINT : bufferAddToEnd(uartGetTxBuffer(),','); bufferAddToEnd(uartGetTxBuffer(),'i'); bufferAddToEnd(uartGetTxBuffer(),'i'); bufferAddToEnd(uartGetTxBuffer(),0); break; case OSC_TYPE_TAG_STRING : bufferAddToEnd(uartGetTxBuffer(),','); bufferAddToEnd(uartGetTxBuffer(),'s'); bufferAddToEnd(uartGetTxBuffer(),0); bufferAddToEnd(uartGetTxBuffer(),0); break; default: //unknown type tag - send 'Nil' (no args) bufferAddToEnd(uartGetTxBuffer(),','); bufferAddToEnd(uartGetTxBuffer(),'N'); bufferAddToEnd(uartGetTxBuffer(),0); bufferAddToEnd(uartGetTxBuffer(),0); ; } } void oscInitRx(void) { u08 i; oscRxNextOp = OSC_RXOP_WAITFORSTART; oscRxMsgSize = 0; oscRxReadBytes = 0; oscRxAddr = 0; oscRxIntFunc = 0; oscRxChecksum = 0; // initialize the message receive buffer bufferInit(&oscRxBuffer, oscRxData, OSC_MAX_RX_MSG_SIZE); for(i=0;i fire off user function if(oscRxIntFunc) { oscRxIntFunc(oscRxData,oscRxIntArg1); } } else { // mismatch - throw this message away oscSendMessageIntInt((char *)PSTR("/error/checksum"),c,oscRxChecksum); } } // wait for next message header oscRxNextOp = OSC_RXOP_WAITFORSTART; break; //skip rest of message - called if an error was detected in the current //incoming message case OSC_RXOP_SKIPMSG: //oscSendMessage(PSTR("/skipmsg")); if(++oscRxReadBytes == (oscRxMsgSize+1)) { oscRxNextOp = OSC_RXOP_WAITFORSTART; } break; default: oscRxNextOp = OSC_RXOP_WAITFORSTART; } }