Sending OSC over SLIP

Hello,
has anyone ever sent OSC over SLIP (Serial Line Internet Protocol)?I recently saw that OSC for arduino provides slip classes. It could be quite useful to have the same interface on an arduino for serial and for network connections.
Is there a way to get raw osc packed data out of an osc message/bundle, without modifying the source?
@bakercp does ofxSerial already support slip?

1 Like

ofxSerial doesn’t include SLIP encoder, but it does include a COBS (which is in the ofxIO package) … which is theoretically better :slight_smile: (https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing) encoder as the default encoder for the PacketSerial example. The PacketSerialDevice class (https://github.com/bakercp/ofxSerial/blob/master/libs/ofxSerial/include/ofx/IO/PacketSerialDevice.h#L37) takes a template parameter for and Encoder / Decoder class, which seems like one could use to implement a SLIP encoder / decoder.

I’d be very happy to include a SLIP encoder / decoder, I just haven’t had a chance to write it …

Thanks for your answer.
I will have a look once i have the time and once i really need it. There are already examples for processing and pd in the OSC for arduino repo. So i will go the slip way instead of implementing COBS on the arduino side.

The other point is still how to get the data of an osc message. Does anyone have an idea how to do this?

Sounds good. COBS that works with packet serial (ofxSerial) on the arduino side is already implemented here: https://github.com/bakercp/PacketSerial

It’s got loads of documentation too :smile:

well, this sounds even better. Thanks.

If you get stuck, let me know. I have some code from a project that used the OSC for arduino library with OpenFrameworks—pulling it out and getting it working is on my TODO list, but I haven’t actually gotten around to doing it.

It’s a long TODO list. Probably too long.

COBS does sound nice, though the OSC 1.1 spec (PDF link) does require SLIP for framing stream-oriented protocols like TCP and serial. So if interoperability a requirement, you might consider (yucky) SLIP instead or in addition to :wink:

Yeah, SLIP for sure for OSC. I just happened to have COBS implemented for other reasons already. If you use the ofxSerial, it would be trivial to take a look at the encoder base class and implement a version for SLIP (just copy the base class i.e. https://github.com/bakercp/ofxIO/blob/master/libs/ofxIO/include/ofx/IO/AbstractTypes.h#L167-L222).

ofxIO now has a SLIPEncoding class! I tried to give it a quick shot with CNMAT/OSC, but didn’t make it too far - I kept getting 0-length buffers on the receiving side, even before playing with the encoder.

I (finally) got around to writing up my code for this:

1 Like

Thanks a lot. I will give it a try.

I was experimenting with this a little and added the following two functions:

ofBuffer ofxOscSender::packOsc( ofxOscMessage& message, bool wrapInBundle )
{
    //setting this much larger as it gets trimmed down to the size its using before being sent.
    //TODO: much better if we could make this dynamic? Maybe have ofxOscMessage return its size?
    static const int OUTPUT_BUFFER_SIZE = 327680;
    char buffer[OUTPUT_BUFFER_SIZE];
    osc::OutboundPacketStream p( buffer, OUTPUT_BUFFER_SIZE );
    
    // serialise the message
    if(wrapInBundle) p << osc::BeginBundleImmediate;
    appendMessage( message, p );
    if(wrapInBundle) p << osc::EndBundle;
    
    return ofBuffer( p.Data(), p.Size() );
}

ofBuffer ofxOscSender::packOsc( ofxOscBundle& bundle )
{
    //setting this much larger as it gets trimmed down to the size its using before being sent.
    //TODO: much better if we could make this dynamic? Maybe have ofxOscBundle return its size?
    static const int OUTPUT_BUFFER_SIZE = 327680;
    char buffer[OUTPUT_BUFFER_SIZE];
    osc::OutboundPacketStream p(buffer, OUTPUT_BUFFER_SIZE );
    
    // serialise the bundle
    appendBundle( bundle, p );
    
    return ofBuffer( p.Data(), p.Size() );
}

and i was able to send the packet using ofxUDPManager

ofBuffer buffer = sender.packOsc(msg);
udpConnection.Send(buffer.getData(), buffer.size());

I tried sending it to pd using ofxTCPClient and i get the following error message in pd unpackOSC: Packet size (14) not a multiple of 4 bytes: dropping packet.

I guess I am missing something important.

Also, i am not sure if this should be in ofxOscSender or implemented in ofBuffer ofxOscMessage::getBuffer()

Any pointers?

oscTcpServer.pd.zip (304 Bytes)

I tryed ofxOscuino (https://github.com/workergnome/ofxOscuino) from @workergnome and it’s working fine here in OSX to Arduino. I am sending OSC from the OSX to Arduino using the USB serial.

I am on OF master branch 0.9 and OSX 10.10.5 with Xcode 6.4.
Now I’ll check if it’s working on Raspbian on Raspberry too.

I would like to know why @workergnome says this on the repo:

While this is certainly not the most efficient way to do so, it lets all the existing OpenFrameworks OSC stuff work out of the box.

It’s something related to the above other comments about COBS algorithm / ofxIO …etc ? Should I try another better way?

1 Like

You said the magic word and summoned me!

It’s been a bit of time since I’ve worked on that, but basically OpenFrameworks assumes that OSC is coming in over UDP, and all the libraries are built around that assumption. ofxOscuino doesn’t try and change that—it just sets up a UDP channel and bridges between UDP and SLIP.

This means that it goes ofxOsc->UDP->SLIP->Arduino, and back Arduino->SLIP->UDP->ofxOsc.

This is obviously less efficient than if you rewrote or created a version of ofxOsc that emited SLIP directly, but unless you have really high demands on OSC, you’re not going to run into problems, and it’s much simpler to use.

(And if you have that level of performance demands, you shouldn’t be using OSC over serial, but something more performant!)

2 Likes

Hey @workergnome, after playing a little more with ofxOscuino, I am having some troubles. It seems like USB port is overflood after working fine some seconds. I am using mainly your arduino code for testing. The error I am getting is something like this:

[notice ] SENDING  >> stepperCamValue '4'
[notice ] RECEIVED << address:'/response' message:'4'
[notice ] SENDING  >> stepperCamValue '-9'
[ error ] Whoops!  USB might be disconnected.
[ error ] Whoops!  USB might be disconnected.
[ error ] Whoops!  USB might be disconnected.
[notice ] SENDING  >> stepperCamValue '-13'
libc++abi.dylib: terminating with uncaught exception of type osc::MalformedPacketException: element size must be multiple of four
(lldb) 

Like you can see above, It seems that is happening when receiving… Do you have any idea of what I can check to improve this errors?

EDIT: Sometimes the arduino isn’t replaying what is sended even when OF says “connected successfully to the client” too. It’s being hard or unstable to make the usb work fine. (I am using arduino Mega 2560, 0.9.0 and OSX 10.10.5 & Xcode 6.4)

You could try replacing ofSerial with ofxSerial, which has flow control and some other nice features.

1 Like

It sounds like you might be sending more data than you have the ability to read, and you’re flooding the buffer. Remember that you’re dealing with two computers of vastly different power. Maybe check what baud rate you’re sending at?

I was using the default 9600 baud rate, but I tested with 115200 too, but the hangs still the same…

When sending just the integer keys (every seconds) like on the example it’s working almost perfect; but sometimes hangs too. The problems increase when sending back (Arduino->OF) a slider controller moved fast by hand on the OF. I suppose that could cause more overflood probability. But when limiting on OF the “sending refreshing” to 10 or 100ms sometimes I get the hang error too, but less.

I am not sure if the problem could be the data format, for example when sending a signed Int and expecting to receive a not signed or a float… Maybe I should check the data types better… Or to check in OF if the OSC message is correct before read it.

My OF receiver code is very similar to your example and looks like:

void ofApp::update(){
    // Get data from the UDP-Serial bridge if both the serial is initialized
    // and the bridge is working

    if(serial.isInitialized() && oscBridge.update()) {
        while(receiver.hasWaitingMessages()) {
            // get the next message
            ofxOscMessage m;
            receiver.getNextMessage(&m);
            
            string mAddress = m.getAddress();
            int mArg0 = m.getArgAsInt32(0); // value

            ofLog(OF_LOG_NOTICE) << "RECEIVED << '" << mAddress << "/" << mArg0 << "'";
            
            if ( (mAddress == "/tiltResponse") || (mAddress == "/panResponse")) {
                int mArg1 = m.getArgAsInt(1); // steps
                int mArg2 = m.getArgAsInt(2); // degree
                
                ofLog(OF_LOG_NOTICE) << "RECEIVED << (pasos/grados) : '" << mArg1 << "/" << mArg2 << "'";
            }
        }
    }
}

On the Arduino side its similar too:
On the loop message identifying section:

  if(!bundleIN.hasError()){
     bundleIN.dispatch("/key", keyFunction);
     bundleIN.dispatch("/tilt", tiltFunction);
     bundleIN.dispatch("/pan", panFunction);
    //...
  } 

One of the read and resend back functions:

void tiltFunction(OSCMessage &msg)
{
  ledToggle();

  int tiltVal = msg.getInt(0);
  tiltGrados = tiltVal;
  tiltPasos = tiltGrados * 10;
  
  if (bEnableMotors){
    stepperTilt.runToNewPosition(tiltPasos);
  }
    
  //-
  if (bEnableOSCback){
    OSCMessage resp("/tiltResponse");
    resp.add(tiltVal); // msg0
    resp.add(tiltPasos); // msg1
    resp.add(tiltGrados); // msg2

    SLIPSerial.beginPacket();  
    resp.send(SLIPSerial); // send the bytes to the SLIP stream
    SLIPSerial.endPacket(); // mark the end of the OSC Packet
    resp.empty(); // free space occupied by message
  }
}

Do you have other example or code to check?

Sorry for the big text, and thanks for reading and helping! :smile:

Yeah—might be helpful to catch the errors, and see what the malformed message is.

I know that I was running into issues when working with this that there were some values for baud rate that worked, and some that didn’t.

You should also check if the arduino is browning out—the “no USB connection” sounds like you might be doing something that causes the connection to be lost. It’s UDP, so you won’t retry, but if data is lost, you’d get a malformed packet.

1 Like

nice! :slightly_smiling: I have seen this new feature on the ofxSerial from @bakercp:

thanks!

1 Like