OSC message value always 0 after sending with SLIP

Status
Not open for further replies.

harald25

Well-known member
I have an ESP8266 breakout connected to a Teensy 3.2
The ESP is set up to receive OSC messages over UDP and then send them to the Teensy over serial with SLIP.
The teensy is set up to output the received OSC messages to the USB serial that my computer is connected to.
When I send an OSC message the Teensy receives it, and routes it to the correct function (in other words, the address is correct), but when I try to read the value of the message it always comes out as 0.

I tested what would happen if I had the ESP route and read the OSC messages, and print the values to serial (that my computer now is connected to).
In this scenario everything works great! I get the correct values printed in the serial monitor.
So I'm wondering if sending the messages from the ESP to the Teensy by SLIP destroys the packets somehow?

Heres the code I'm running on the ESP when everything works fine:
Code:
// This program converts UDP OSC messages into SLIP Serial OSC messages on the ESP8266 wifi board
// At the moment there is no OSC bundle support, not sure I need it at the moment


#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#include <OSCMessage.h>
//#include <SLIPEncodedSerial.h>


int status = WL_IDLE_STATUS;
const char* ssid = "xxxxx";  //  your network name (SSID)
const char* pass = "xxxxx";       // your network password

int localPort = 8000;
int destPort = 9000;
IPAddress outIp(10, 0, 1, 215); //default IP, will change with received udp
IPAddress espip(10, 0, 1, 14);
IPAddress gateway(10,0,1,1);
IPAddress subnet(255,255,255,0);
WiFiUDP Udp;
//SLIPEncodedSerial SLIPSerial(Serial);


void setup()
{
  //SLIPSerial.begin(115200);
  Serial.begin(115200);

  WiFi.begin(ssid, pass);
  WiFi.config(espip,gateway,subnet);

  int tries=0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    tries++;
    if (tries > 30){
      break;
    }
  }
  Udp.begin(localPort);
}

void loop(){
 OSCMsgReceive();
  
}

void OSCMsgReceive(){
  OSCMessage msgIN;
  int size;
  if((size = Udp.parsePacket())>0){
    while(size--) 
      msgIN.fill(Udp.read());
    if(!msgIN.hasError()){
      msgIN.route("/OnOff/toggle1",toggleOnOff);
      msgIN.route("/Fader/Value",funcValue);
      msgIN.route("/XY/xy",xy);
    }
  }
}

  void xy(OSCMessage &msg, int addrOffset)
{
  float xValue;
  float yValue;

  xValue = msg.getFloat(0);
  yValue = msg.getFloat(1);

  Serial.print("X: ");
  Serial.println(xValue);
  Serial.print("Y: ");
  Serial.println(yValue);
}


void toggleOnOff(OSCMessage &msg, int addrOffset)
{
  float ledState;
  ledState = msg.getFloat(0);
  //OSCMessage msgOUT("/OnOff/toggle1");
  //msgOUT.add(ledState);

  //digitalWrite(ledPin, ledState);

  
  if (ledState) {
    Serial.println("LED on");
    Serial.println(ledState);
  }
  else {
    Serial.println("LED off");
    Serial.println(ledState);
  }

  //ledState = !ledState;     // toggle the state from HIGH to LOW to HIGH to LOW ...

  //send osc message back to control object in TouchOSC
  //Local feedback is turned off in the TouchOSC interface.
  //The button is turned on in TouchOSC interface whe the conrol receives this message.
  //SLIPSerial.beginPacket();
  //msgOUT.send(SLIPSerial); // send the bytes
  //SLIPSerial.endPacket(); // mark the end of the OSC Packet
  //msgOUT.empty(); // free space occupied by message
}

void funcValue(OSCMessage &msg, int addrOffset ){

  float value = msg.getFloat(0);
  //OSCMessage msgOUT("/Fader/Value");

  Serial.print("Value = : ");
  Serial.println(value);

  //msgOUT.add(value);

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

Heres the code I'm running when I'm trying to use SLIP to send messages to the Teensy

ESP-code:
Code:
// This program converts UDP OSC messages into SLIP Serial OSC messages on the ESP8266 wifi board
// At the moment there is no OSC bundle support, not sure I need it at the moment


#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#include <OSCMessage.h>
#include <SLIPEncodedSerial.h>


int status = WL_IDLE_STATUS;
const char* ssid = "xxxxx";  //  your network name (SSID)
const char* pass = "xxxxx";       // your network password

int localPort = 8000;
int destPort = 9000;
IPAddress outIp(10, 0, 1, 215); //default IP, will change with received udp
IPAddress espip(10, 0, 1, 14);
IPAddress gateway(10,0,1,1);
IPAddress subnet(255,255,255,0);
WiFiUDP Udp;
SLIPEncodedSerial SLIPSerial(Serial);


void setup()
{
  SLIPSerial.begin(115200);

  WiFi.begin(ssid, pass);
  WiFi.config(espip,gateway,subnet);

  int tries=0;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    tries++;
    if (tries > 30){
      break;
    }
  }
  Udp.begin(localPort);
}

void loop(){
 
  // read=udp->serial, write=serial->udp
  int rd,wr;
  OSCMessage rMsg, wMsg;
  //static unsigned int bp = 0;
  static bool packet = 0;
  static unsigned long  tr = 0, tw = 0;

  if((rd = Udp.parsePacket())>0){
    if(tr - micros() > 10000)
    {
      outIp = Udp.remoteIP();
      while (rd--)
        rMsg.fill(Udp.read());
      if(!rMsg.hasError())
      {
        SLIPSerial.beginPacket();
        rMsg.send(SLIPSerial);
        SLIPSerial.endPacket();
      }
      rMsg.empty();
     }
     else
     {
      while (rd--)
        Udp.read();
     }
    tr = micros();
  }

  while(!SLIPSerial.endofPacket()) {
    if(wr = SLIPSerial.available()>0){
      tw = micros();
      if(!packet)
        packet = 1;
      while(wr--) { //this needs a byte limit
        wMsg.fill(SLIPSerial.read());
        //if(++bp >= 512) break; //packets seem to get truncated about here anyway
      }
    }
    if((micros() - tw) > 10000) break; //Timeout for no eoP()
    //if(bp >= 512) break; //break again
  }

  if(packet) {
    if(!wMsg.hasError()) {
      Udp.beginPacket(outIp, destPort);
      wMsg.send(Udp);
      Udp.endPacket();
      packet = 0;
    }
  }
}

Teensy code
Code:
//DHCP-based OSC server test code
//#include <SPI.h>
#include <SLIPEncodedSerial.h>
#include <OSCMessage.h>

SLIPEncodedSerial SLIPSerial(Serial1);


void setup(){
  Serial.begin(9600);         //Teensy <=> Computer 
  SLIPSerial.begin(115200);   //Teensy <=> ESP
  delay(1000);
  Serial.println("Started");
}

void loop(){
  OSCMsgReceive();
} 


void xy(OSCMessage &msg, int addrOffset)
{
  float xValue;
  float yValue;

  xValue = msg.getFloat(1);
  yValue = msg.getFloat(2);

  Serial.print("X: ");
  Serial.println(xValue);
  Serial.print("Y: ");
  Serial.println(yValue);
}


void toggleOnOff(OSCMessage &msg, int addrOffset)
{
  float ledState;
  ledState = msg.getFloat(0);
  OSCMessage msgOUT("/OnOff/toggle1");
  msgOUT.add(ledState);

  //digitalWrite(ledPin, ledState);

  
  if (ledState) {
    Serial.println("LED on");
    Serial.println(ledState);
  }
  else {
    Serial.println("LED off");
    Serial.println(ledState);
  }

  //ledState = !ledState;     // toggle the state from HIGH to LOW to HIGH to LOW ...

  //send osc message back to control object in TouchOSC
  //Local feedback is turned off in the TouchOSC interface.
  //The button is turned on in TouchOSC interface whe the conrol receives this message.
  SLIPSerial.beginPacket();
  msgOUT.send(SLIPSerial); // send the bytes
  SLIPSerial.endPacket(); // mark the end of the OSC Packet
  msgOUT.empty(); // free space occupied by message
}

void funcValue(OSCMessage &msg, int addrOffset ){

  float value = msg.getFloat(0);
  OSCMessage msgOUT("/Fader/Value");

  Serial.print("Value = : ");
  Serial.println(value);

  msgOUT.add(value);

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

void OSCMsgReceive()
{
  OSCMessage msgIN;
  int size;
  
  
  while(!SLIPSerial.endofPacket())
  {
    
    if((size = SLIPSerial.available()) > 0)
    {
      while(size--)
      {
        msgIN.fill(SLIPSerial.read());
      }
      if(!msgIN.hasError())
      {
        msgIN.route("/OnOff/toggle1",toggleOnOff);
        msgIN.route("/Fader/Value",funcValue);
        msgIN.route("/XY/xy",xy);
      }
    }
  }
}
 
Hi

I just skimmed your code ... it uses libraries I'm not familiar with (but I sure am interested) ... Can I just ask a kind of 'highlevel' question?

You say you are getting good data to the esp, and that you can print out the data received at the esp correctly .... transmitting it to the teensy is the problem ... but why do you need to use slip to transmit to the teensy? If you can print out the data from the esp, then you can transmit it to the teensy as 'normal' serial. {maybe I am not understanding OSC structure too much) ... At the point of getting 'ordinary' serial to the teensy I assume you can 're-packetise' it into OSC and transmit over usb? I don't quite get how you would transmit OSC over usb... I assume it is just as serial usb, and not in a udp format ... so why does it neet to be SLIP encoded between the esp and the teensy?

I'll have a look at the libraries I am not familiar with and try and help out (and learn stuff tooo!) Certainly appears to be a problem with SLIP encoding ...
 
Seeing ESP8266 and UDP / WiFi messages I just had to look.

I found https://github.com/CNMAT/OSC - not sure if that is your source { based on this I assume it is: http://cnmat.berkeley.edu/oscuino } - but the thought that comes to mind is sometime ESP swaps byte ordering? But that wouldn't explain a ZERO field unless something oddly wrong or a problem elsewhere in the cross platform chatter?

And for ESP I found this for <WiFiUDP.h>: http://esp8266.github.io/Arduino/versions/2.1.0/doc/libraries.html

Also I saw this KUDO worthy of sharing from the CNMAT/OSC:
Best Supported Board: The Teensy 3.0 and 3.1 and LC have the performance and memory that afford rich OSC implementations. Our primary test platform for new development is the Teensy 3.1 which currently offers the best performance of any of the Arduinos and variants. We greatly appreciate Paul Stoffregen's ongoing work with "best practice" engineering of high performance microcontrollers.

Cool - stuff - good luck.
 
Hi

I just skimmed your code ... it uses libraries I'm not familiar with (but I sure am interested) ... Can I just ask a kind of 'highlevel' question?

You say you are getting good data to the esp, and that you can print out the data received at the esp correctly .... transmitting it to the teensy is the problem ... but why do you need to use slip to transmit to the teensy? If you can print out the data from the esp, then you can transmit it to the teensy as 'normal' serial. {maybe I am not understanding OSC structure too much) ... At the point of getting 'ordinary' serial to the teensy I assume you can 're-packetise' it into OSC and transmit over usb? I don't quite get how you would transmit OSC over usb... I assume it is just as serial usb, and not in a udp format ... so why does it neet to be SLIP encoded between the esp and the teensy?

I'll have a look at the libraries I am not familiar with and try and help out (and learn stuff tooo!) Certainly appears to be a problem with SLIP encoding ...

I'm really not an expert on protocols and packets, so I'm not 100% sure why SLIP is needed to send packets from the ESP to the Teensy. But I think it's because OSC is an application layer level protocol, and therefore is not made to be sent 'as-is' over a transport medium. SLIP on the other hand would be a transport layer level protocol, specifically made to send packets over a serial connection.
When I say that I'm able to output good data when only using the ESP I'm not 'directly' sending the OSCmessage out on the serial connected to my computer.
'msgIN.route();' will read the address of the OSC packet, and if the address matches what I tell the function to look for, a function I specify is run. This function in turn outputs a line of text to the serial monitor followed by the value of the OSC message which is read by the function 'msg.getFloat(0);' (0 is the index of the value to get as a OSC message can have several values in addition to its address).

Example from the code that's working (I made some comments in the code):
Code:
void OSCMsgReceive(){
  //An empty OSCmessage is created
  OSCMessage msgIN;
  int size;
  if((size = Udp.parsePacket())>0){
    while(size--) 
      //As long as there is data in the UDP packet (size != 0) the data is filled in to the OSCmessage
      msgIN.fill(Udp.read());
    if(!msgIN.hasError()){
      //If the OSCmessage contains no errors the message is routed to a specified function if the address matches what I fill in
      msgIN.route("/OnOff/toggle1",toggleOnOff);  
      msgIN.route("/Fader/Value",funcValue); // "/Fader/Value" is the address, 'funcValue' is the function that will be invoked if the address matches the OSCmessage
                                                                 //'msgIN.route()' sends a pointer to the OSCmessage as an argument for the function it invokes
      msgIN.route("/XY/xy",xy);
    }
  }
}


void funcValue(OSCMessage &msg, int addrOffset ){
  //'msg.getFloat(0);' gets the value at index 0 from the OSCmessage
  float value = msg.getFloat(0);

  //A line of text and the value is printed to the serial monitor so I can read the value
  Serial.print("Value = : ");
  Serial.println(value);
}

Did this make it a little more understandable? Please ask if something is still unclear =)



Seeing ESP8266 and UDP / WiFi messages I just had to look.

I found https://github.com/CNMAT/OSC - not sure if that is your source { based on this I assume it is: http://cnmat.berkeley.edu/oscuino } - but the thought that comes to mind is sometime ESP swaps byte ordering? But that wouldn't explain a ZERO field unless something oddly wrong or a problem elsewhere in the cross platform chatter?

And for ESP I found this for <WiFiUDP.h>: http://esp8266.github.io/Arduino/versions/2.1.0/doc/libraries.html

Also I saw this KUDO worthy of sharing from the CNMAT/OSC:


Cool - stuff - good luck.

Yes, https://github.com/CNMAT/OSC is the source I'm using.
If the ESP swapped the byte order I would imagine the entire OSCmessage got 'fucked up' and not only the value of the message?

This, by the way, is where I've gotten the code for taking UDP packets that come in to the ESP and send them to the Teensy as SLIP
http://www.esp8266.com/viewtopic.php?f=29&t=4533
I've made a reply to this thread to ask for help also.


Edit:
I tried another thing just now.
Instead of receiving UDP packets and resending them as SLIP I programmed the ESP to generate new OSCmessages and send them as SLIP:

Code:
OSCMessage test("/Fader/Value");
  test.add(42.0);
  SLIPSerial.beginPacket();
  test.send(SLIPSerial);
  SLIPSerial.endPacket();
  test.empty();

And still the value is always 0 after receiving the SLIP packet and filling it in to a new OSCMessage on the Teensy :(
 
Last edited:
Alright!! I figured it out! :D

The problem was in the receiving end of the SLIP packets, on the Teensy.
I had 'if(!msgIN.hasError())' inside the loop: 'while(!SLIPSerial.endofPacket())'

What happened was that the OSC message was being filled up, and when the address of the message was filled in msgIN.hasError() no longer gave an error.
Therefore msgIN.route() invoked the function matching the OSC message address before any value was filled in to the message.
The solution was to move 'if(!msgIN.hasError())' outside of the while loop, and everything worked like a charm! :D

Code:
void OSCMsgReceive()
{
  OSCMessage msgIN;
  int size;
  
  static unsigned long microsTime = 0;
  while (!SLIPSerial.endofPacket())
  {
    if ((size = SLIPSerial.available()) > 0)
    {
      microsTime = micros();
      while (size--)  //this needs a byte limit
      {
        msgIN.fill(SLIPSerial.read());
      }
    }
    if ((micros() - microsTime) > 10000) break; //Timeout for no eoP()
  }
 
 
  if(!msgIN.hasError())
  {
    //msgIN.route("/OnOff/toggle1",toggleOnOff);
    msgIN.route("/Fader/Value",funcValue);
    //msgIN.route("/XY/xy",xy);
  }
}
 
Whew! great news

Can I ask how you are transmitting from the teensy to your computer... and processing it on your computer?
 
I'm not actually using my computer for anything except debugging.
This: "Serial.begin(9600); //Teensy <=> Computer " is only for sending a line of text to the serial monitor of my computer so I could see what is going on.

What I'm using is an app called Touch OSC. It's an app for iPhone/iPad that lets you customize a touch control panel.
Through a program for your computer you design the control panel. You can make buttons, sliders, xy-sliders ++. The name of the objects become the address for the OSC message that is sent out, and for a slider, for example, you specify the min and max value of the slider which is added to the OSC message before being sent.
I've set up the ESP to listen for UDP packets originating from the IP address of my phone, and the port I've specified in the Touch OSC app.
The app can also receive OSC messages, for example displaying the current value of some parameter you are adjusting.

It's all very cool and super responsive. I've now set it up to control a strip of leds in my roof.
I can switch between two modes, and adjust some parameters in each mode. Brightness is one such parameter, and when I start adjusting it the response is immediate.
 
Status
Not open for further replies.
Back
Top