Go Down

Topic: [Solved] Send/Receive TCP/IP strings (Yùn) (Read 23509 times) previous topic - next topic

fab03

Mar 26, 2015, 12:39 am Last Edit: Apr 03, 2015, 11:58 am by fab03
Hi everybody,

I'm just getting crazy with this new bridge library. What I wish to do is to simply receive a TCP/IP string, process it, then send back another string, like I always did with the Ethernet shield together with its Ethernet library.
That was very simple:
1) I started the connection with Ethernet.begin(Mac, staticIP);
2) client.read() to read
3) client.write() to write
Simple!

But what about the Yùn platform? May I have to learn billions of different programming languages to make this Arduino do a simple task as this??
The documentation of the Yùn is very poor and there are no examples out there!
And I'm not Bill Gates... :D

Thank you

jessemonroy650

#1
Mar 26, 2015, 01:29 am Last Edit: Mar 26, 2015, 01:38 am by jessemonroy650
::::SNIP::::

But what about the Yùn platform? May I have to learn billions of different programming languages to make this Arduino do a simple task as this??
The documentation of the Yùn is very poor and there are no examples out there!
And I'm not Bill Gates... :D

Thank you
@fab03,
Many of us will agree that the documentation is lacking, but this is an Open Source project, so that means the volunteers and supports are under "social contract" to add what is "missing".

Next, if you are not aware of it, the Yun has two (2) processors. Even if you are, it would be good to watch this short video. Pay extra attention to the part with the sketches.

Getting started with Arduino Yún - tutorial (6:53)
https://www.youtube.com/watch?v=9-hPhWHWnvs

Next, to accomplish your goal, study the Bridge example. This will pass the string to the Atmel ATmega32U4. If you want to do more processing on the string, you might want to catch it on the Linux side.

If you have more questions, please ask.

Jesse

ShapeShifter

To make an outbound connection, take a look at the YunClient Class, it will do what you want to do. It is similar to the EthernetClient class, but inthinkmits easier to use: all of the work you have to do to set up the EthernetShield (setting up MAC addresses, IP addresses, etc.) is already done for you, all you need to do is call Bridge.begin() to set things up.

To accept incoming connections, look at the YunServer Class. Most of the examples using YunServer are handling incoming web requests, but it can do more than that. Both YunServer and YunClient are simple TCP streams at their heart.

I have some examples of both uses, but I'm away from my computer at the moment. I will find and post the examples when I get back to my computer in a couple hours.

fab03

First of all thank you for the replies guys.

@jesse

I saw exactly that video many times, trying to understand how the library has to be used. I understand I have to treat the Bridge library as the Serial library, since the Atmega and the Linux microprocessor are linked with a serial connection.
The received string (composed by few chars) has just to be compared, so it doesn't need to be processed in the more powerful Linux environment.

@ShapeShifter

I studied those two examples but seem to be less powerful than the Ethernet library! Here I write a couple of things I could do with the ethernet library that I think I can't do anymore with bridge:
1) easily set a static IP address  to the Yùn through a dedicated function directly in the sketch
2) set a communication port (of my choice); by the way is the default port 5555 (as specified in the Yùn guide) or 80 (as always in Http)?
3) quickly send simple TCP strings without the need of complicated and slower HTTP GET requests
Most of the examples using YunServer are handling incoming web requests, but it can do more than that. Both YunServer and YunClient are simple TCP streams at their heart.
You're right! They have TCP streams at their heart, but I need that heart! When I send a simple string (to port 80) the Yùn returns a "Bad request" as it is expecting a complete HTTP GET request. Seems like the Yùn is able to make the hardest task (handle web pages through web requests) and not the easiest one (send/receive one line strings)!!


@all of you

I tried to write a simple Processing 2 client sketch that opens a communication to the Yùn IP. I wanted to see if the string is received or not by the Yùn (I tried on both port 5555 and 80): no results... Here's the Yùn sketch:
Code: [Select]
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

YunServer server;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Starting bridge...\n");

  Bridge.begin();

  delay(2000);
  Serial.println("Done.\n");
}

void loop() {

  YunClient client = server.accept();

  if (client) {
    // read the command
    String command = client.readString();
    command.trim();        //kill whitespace
    Serial.println(command);

    // Close connection and free resources.
    client.stop();
  }
  delay(50);
}

ShapeShifter

1) easily set a static IP address  to the Yùn through a dedicated function directly in the sketch
That is done through Linux, not the sketch. It's the Linux side that manages the network. You can do it using the advanced configuration web pages of the Yun. Remember that the network is used by a lot more than just the sketch, so the sketch does not have the ability to selfishly reprogram that level of network configuration out from under Linux.

Quote
2) set a communication port (of my choice); by the way is the default port 5555 (as specified in the Yùn guide) or 80 (as always in Http)?
Actually, the default is that it is listening on port 5555 for connections from the localhost (the Linux processor.) The Linux processor is listening on port 80, handling the HTTP overhead, and then passing the payload along to the sketch on port 5555.

But you can manually configure the port. On the YunServer, the port to listen on is an optional parameter. In that case, you should use server.nolistenonlocalhost() to start the server, rather than server.listenonlocalhost(). The former says listen to incoming requests on that port from the general network, the latter says just listen for pre-digested connections from the processes on the Linux side.

To manually configure the port on an outgoing connection, the YunClient constructor has IP address and port number parameters.

Quote
3) quickly send simple TCP strings without the need of complicated and slower HTTP GET requests
All of the formal examples use the extra overhead of using port 80 and going through the Linux processor because using port 80 and HTTP protocols make it easy to access the data using a web browser and JavaScript. But there are alternatives.

A simple example I wrote of listening for basic incoming TCP stream connections is HERE. That example listens for raw TCP connections coming in on port 255 (an arbitrary choice on my part.) You could just as easily use other ports. For example, you could use port 23, so you can connect to it with any Telnet client, but then you will get a bit of garbage at the beginning as the Telnet client tries in vain to negotiate settings. (If you do want to implement a true Telnet server, you will need to handle this negotiation yourself.)

Now, for outgoing connections. The idea is to create a YunClient object, and then use the connect() method to open an outbound connection. The function takes arguments to specify the server and the port number. The server could be a server name, or it could be an IP address in one of three forms: four discrete bytes, an array of four bytes, or a single 32 bit unsigned number.

Here's a simple example. It opens an outbound connection, sends something, and echos everything received to the serial port.
Code: [Select]
#include <Bridge.h>
#include <YunClient.h>

#define PORT 255

// Define our client object
YunClient client;

void setup()
{
  // Bridge startup
  Bridge.begin();
 
  Serial.begin(9600);

  while (!Serial); // wait for a serial connection
}

void loop()
{
  // Make the client connect to the desired server and port
  IPAddress addr(192, 168, 42, 185);
 
  // Or define it using a single unsigned 32 bit value
  // IPAddress addr(0xc0a8sab9); // same as 192.168.42.185
 
  // Or define it using a byte array
  // const uint8 addrBytes = {192, 168, 42, 185};
  // IPAddress addr(addrBytes);

  client.connect(addr, PORT);
 
  // Or connect by a server name and port.
  // Note that the Yun doesn't support mDNS by default, so "Yun.local" won't work
  // client.connect("ServerName.com", PORT);

  if (client.connected())
  {
    Serial.println("Connected to the server.");
   
    // Send something to the client
    client.println("Something...");

    // Cheap way to give the server time to respond.
    // A real application (as opposed to this simple example) will want to be more intelligent about this.
    delay (250);
 
    // Read all incoming bytes available from the server and print them
    while (client.available())
    {
      char c = client.read();
      Serial.print(c);
    }
    Serial.flush();

    // Close the connection
    client.stop();
  }
  else
    Serial.println("Could not connect to the server."); 
   
  // Give some time before trying again
  delay (10000);
}


So, I loaded my server example code on one Yun (IP address 192.168.42.185) and loaded the above client code on another. When I run them, I get this from the server:

Code: [Select]
New client connection.
From client: "Something...
"
Client disconnected.


And I get this from the client:

Code: [Select]
Connected to the server.
Hello Client!
Hello Client!
Hello Client!
Hello Client!
Hello Client!
Hello Client!
Hello Client!
Hello Client!
Hello Client!




Voila! Incoming and outgoing raw TCP connections.  8)

Any questions?

fab03

Incredible...  :o it works!
ShapeShifter maybe you are Bill Gates, that is exactly what I was looking for  ;)

But now I'm wondering why my sketches weren't working... I tried also to set a custom server port with
Code: [Select]
YunServer server(port)
as you did, but I could not get any response: I think the Yùn was expecting again an HTTP request.
After comparing my sketch and yours I'm still not able to see where the Yùn realize that the data it will receive are not HTTP headers but raw strings.
If you want (as I stressed you enough  :D ) you or anybody else can tell me where I was wrong in my sketch.

So what could I say more...? Thank you ShapeShifter
And of course thank you Jesse!

Hope these informations could help many Yùn users.

fab

ShapeShifter

as you did, but I could not get any response: I think the Yùn was expecting again an HTTP request.
After comparing my sketch and yours I'm still not able to see where the Yùn realize that the data it will receive are not HTTP headers but raw strings.
This is the key bit of code:

Code: [Select]
  server.noListenOnLocalhost();
  server.begin();
  client = server.accept();


If you look closely at the HttpClient example code, it calls server.listenOnLocalHost() where I call server.noListenOnLocalHost(). It's an important distinction. I'm betting you're calling the first one, not the one I'm calling.

server.listenOnlocalHost() tells the YunClient to look for connections coming from localHost (the Linux processor.) These are the connections that are the pre-digested HTTP calls that the Linux side fields on port 80, and which it passes to the YunServer on port 5555 if the first token of the url is /arduino/

server.noListenOnlocalHost() tells the YunClient NOT to look for connections coming from localHost (the Linux processor) so instead it will look for connections coming in from the network directly.

fab03

#7
Mar 26, 2015, 07:44 pm Last Edit: Mar 26, 2015, 07:46 pm by fab03
Yeah, you're betting right... I looked at that specific example and I copied it including server.listenOnlocalHost(). Then I totally deleted the function like the sketch I posted in this thread, hoping that it worked , but as I saw it wasn't enough.
Alright you won! But I was close to the solution  :D
Thank you, take care!

novski

This examples are verry verry useful! At High Quality explaination. Thank you!

Go Up