Connecting with TCPclient code, and PING issues

Hello,

We just got our 2 Spark Core boards, (Black silk screen) and doing a project that we are having some results we did not except. We currently have many regular Arduino WiFi boards, which are setup as TCP Clients and send sensor data to a server device via a REST protocol on the same network.

We have successfully coded the Core to read our sensors and via Spark variables, we can read variable data.  We can monitor our Core with the Arduino IDE serial monitor to debug and can connect to the Spark cloud.

We coded the Core with TCPclient code to communicate REST, to our server, but keep getting a “connection failed” message via serial, we coded on a connection failure.  We never  get a successful “client.connect”. We spent several days trying to understand why coding, similar to the TCPclient example, was not working on the Core talking to our other internal server.

I ran into this forum post about PING, https://community.spark.io/t/how-to-ping-or-get-mac-address-to-check-if-alive/3478/15, and thought I would try pinging our internal server.

So we setup pinging, Google, our internal server, two other ArduinoWiFi boards, the WiFi Router and a failed IP address.

The results shows the Google pings, the WiFi Router pings, but the internal server and Arduino do not Ping, on the same network!

Google: 5
Server: 0
WiredUNO: 0
SensorUNO: 0
WiFi Router: 5
Failed…: 0

So I tried to ping from my PC the same devices and Google above.  All ping correctly!

I then used Network.localIP(), to see what the network settings looked like on the Core, looks OK.

IP: 192.168.0.104
Mask: 255.255.255.0
Gateway: 192.168.0.1
SSID: DVLP_Router

So I then tried to Ping the Core @ 192.168.0.104 from the PC, and the Core did not Ping!?!

So from what I can gather, the Core cannot see another device on the same network, except the Router, and the Core does not respond to Ping either. It looks like for whatever reason, the Core will not reach the internal server on the same network with our TCPclient code.

We are unclear why the Core cannot see other devices/server on the same network and cannot be pinged itself. What are we missing?

Your help with this matter is greatly appreciated. Mark

Hi @MarkInAZ

I am sorry you are having problems.  There are a lot of variables here but one thought that came up immediately for me is that the most recent TI CC3000 patch removed the autonomous ping answer in order to fix other problems.  This means that older cores that have not been patched yet do answer ping requests, but those with the latest version do not.  They can still send pings and get responses, but they do not answer ping requests on their own. This was apparently needed to fix the ARP problems we were having before.

You can tell what version of the TI chip patch you have by running this (1.29 is the latest, I believe):

uint8_t fwver[2];
nvmem_read_sp_version(fwver);
Serial.print(fwver[0]);
Serial.println(fwver[1]);

I know that is one small mystery in your larger problem here. Maybe you could post some code for us to take a look at?

I would also try a different router or network and see if that helps.

1 Like

Hello,

Thank you for your help with this matter. The version we have is 1.29

To clarify, we are using another Arduino that Pings all our devices, especially WiFi shield Arduinos, because we have had a lot of issues with WiFi shields dropping WiFi and not reconnecting. We have tested over a dozen Arduino shields, and have one design that works, OK. Most of our units use the Arduino Ethernet hardwired board/Shield. We would love to go WiFI, but have seen soo many reliability issues! Since the Core is a WiFi device, we are concerned with seeing the same issues we have seen in the past with WiFi connects being dropped. With the WiFi drops, we have seen lost time frames of data that is not recorded in a database.

We have not tested another network, but will look at this.

OK, here is the TEST sketch we are running:

TCPClient client;
byte server[] = { 192, 168, 0, 115 }; // Server IP

void setup()
{
  Serial.begin(9600);
  delay(1000);
  Serial.println("Filename: SparkCore_REST, 6/17/2014 ");

}

void loop()
{

 if (client.connect(server, 50001)) //Port
 {
    Serial.println("connected ... ");
    client.println("GET /rest/vars/set/1/19/255 HTTP/1.1\n");
    Serial.println("Variable sent ... "); } // 255 is a dummy variable, value
 else
 {
    Serial.println("connection failed ... ");
 }
  
  if (client.available())
  {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected())
  {
    Serial.println();
    Serial.println("disconnecting ... ");
    client.stop();
    for(;;);
  }

delay(5000);

Serial.println("Tick ... "); // is the loop still running?

}

connection failed …, is what we get.

Any help is greatly appreciated, and Thank you. Mark

OK so I added the magic formatting markup for C++ code in your post–it is hard to type out here but it is three grave accents and cpp on one line before your code and three grave accents on a separate line below your code. If you edit your own post, you can see what I mean.

I think your problem might be that TCPClient does not have an overload for connect() with a byte array address–it expects either an IPAddress or a char* host character array.

Try this at the top of your file:

IPAddress server(192, 168, 0, 115);

Thank you for the code and comments.

No go. I cleaned the code down for simply testing and added your code line suggestion.

TCPClient client;
IPAddress server(192, 168, 0, 115);
int port = 50001;

void setup()
{
  Serial.begin(9600);
  delay(1000);
  Serial.println("connecting ... 1 ");
}

void loop()
{
Serial.println("connecting ... 2 ");

  if (client.connect(server, port))
  {
    Serial.println("connected ... ");
  }
  else
  {
    Serial.println("connection failed ... ");
  }

  Serial.println();
  Serial.println("disconnecting ... ");
  client.stop();
}

The output results are:

connecting … 2
connection failed …

disconnecting …

So I still do not think the Core can see the other server/device. What else should I look at?
Thank you.

Well, something strange is starting to happen.

We were watching the Core running the code we posted, and the serial monitor started spitting out the following:

connecting … 2
connection failed …

disconnecting …
connecting … 2
connected …
-1
disconnecting …
connecting … 2
connected …
-1
disconnecting …
connecting … 2
connected …
-1
disconnecting …
connecting … 2
connected …
-1
disconnecting …
connecting … 2
connection failed …

disconnecting …

It looks like the Core is sometimes connecting and other times NOT connecting to the server. When it connects, we get this -1, not sure why. We have been watching this for a bit, and it is random.

Hello,

OK, IPAddress server(192, 168, 0, 115); this code solved the major part of the issue. Thank you.

We can now connect and post data to our server, Alright !!

However, as I showed above, the connection currently takes many iterations of the loop before the Core connects! It is not consistent, about 1-2 minutes. We will run this over night and look for any WiFi drops or no connection messages.

I hope this does not occur, as this is the same type of issue we have struggled with, with ALL Arduino WiFi boards and shields.

Thanks, Mark

2 Likes

I have noticed it sometimes takes 3 or 4 attempts to connect with some of my app’s, i just create a loop with a 2 second delay before retry…

does slowing you loop down a bit help, putting a 1sec delay at the bottom

Ive just done some testing and if i use a “char host name” ie char servername[] = “somewhere.com” it will never connect on my slow connection, if i change to byte serverIP[] = { 000, 000, 000, 000 } where the 000’s are the ip for somewhere.com its slow but it works.

When I’m at home on 100mbit connection both ways work but here on very slow satellite link they don’t.

i can see in the spark_wiring_tcpclient.cpp that if i send the byte it goes straight to the proper connect function (which works well)

if however i send the “char host name” it goes to a different function… to get the IP address. and i think thats where my problem is. so it calls gethostbyname which is in socket.c

so once its got the IP it returns that to the proper connect function… but i dont think its getting that IP so it never connects.

How can i print the returned IP (from gethostbyname) to see if it has one and thats the problem?

Hi @Hootie81

It sounds like the satellite router’s DNS service is very slow or not working right. I assume you have tested it with other computers to make sure it is working at least slowly, right?

You can call gethostbyname() and print the results, something like this (I didn’t test this so there might be typos):

void setup() {
  Serial.begin(9600);
}
void loop() {
  uint32_t ip_addr = 0;
  char hostname[] = "www.google.com";  //you host name here!
  gethostbyname(hostname, strlen(hostname), &ip_addr);
  IPAddress resolvedIP(BYTE_N(ip_addr, 3), BYTE_N(ip_addr, 2), BYTE_N(ip_addr, 1), BYTE_N(ip_addr, 0));
  Serial.println(resolvedIP);
  delay(5000);
}

Just for completeness, it would be good to know the wall time that gethostbyname() took to get a response, and also its return value.

2 Likes

Something more like this:

void setup() {
  Serial.begin(9600);
}
void loop() {
  uint32_t ip_addr = 0;
  char hostname[] = "www.google.com";  //you host name here!
  unsigned long tic = millis();
  int16_t retval = gethostbyname(hostname, strlen(hostname), &ip_addr);
  unsigned long toc = millis();
  IPAddress resolvedIP(BYTE_N(ip_addr, 3), BYTE_N(ip_addr, 2), BYTE_N(ip_addr, 1), BYTE_N(ip_addr, 0));
  Serial.println(resolvedIP);
  Serial.println(retval);
  Serial.println(toc-tic);
  delay(5000);
}

Thanks @bko,

that worked a treat! always returns 0.0.0.0 and takes about 900ms (900 - 902)

there is no way that i could resolve an IP in that time… on a pc i can do nslookup and count to 3 before i get the IP…

So… how to extend that time??

A quick scan of the TI CC3000 forums, and the recesses of my memory don’t identify a mechanism to tweak the DNS timeout. I’l dig a little deeper to see if we can find a setting to modify.

1 Like

Ive just spent 2hrs trying different things to make it work… but i wont give up because its useless without it… unless i make my own version of a DNS resolver using TCP and a static ip… hmm maybe another few years of learning programming first

DNS lookups generally use UDP. Check out the Protocol details section of the Wikipedia article. However, it's not a very complex protocol, so it may not be too terrible to roll your own DNS resolver client.

As i wrote the post i started looking into it a bit more… im now trying to port the arduino DNS library, im pretty sure there is only a few lines to change around the send UDP request, but ill see what errors the compiler throws at me :stuck_out_tongue:

Watch out for the different behavior of the UDP class between :spark: and arduino. Please post your code when you have it, because we will need it for the wired :spark: proof of concept some of us are kicking around.

Funny you should say that… i was just reading that post! after i got my head around the send part i thought i would do a quick search and see… and there is issues with the write buffering or something and end packet doing nothing…

So this wouldnt work??

iRequestId = millis(); // generate a random ID
    uint16_t twoByteBuffer;
                

    iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId));

    twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG);
    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));

    twoByteBuffer = htons(1);  // One question record
    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));

    twoByteBuffer = 0;  // Zero answer records
    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));

Whats the best way to change it? the code is a straight snippet from the arduino DNS.cpp library

then ill have to get onto the receive part… ill need to work out how it works and what it does first…

I must say i have learned so much in the last couple of months, and still i don’t know much! But I’m enjoying every minute of it

Hi @Hootie81

Each one of the UDP.write() functions will generate a packet, which is not what you want. Most DNS requests are under 128 bytes, so if you make a 128-byte buffer, copy all the bytes you want to send into it, and then do just one write with the entire buffer, you will get the desired behavior.

Another user made a class to layer on top of the built-in UDP class that does just that

//----- UDP + overloading the inappropriate UDP functions of the Spark Core (REQUIRED !)
class myUDP : public UDP {
private :
	uint8_t myBuffer[128];
	int offset = 0;
public :
	virtual int beginPacket(IPAddress ip, uint16_t port){
		offset = 0;
		return UDP::beginPacket(ip, port);
	};
	virtual int endPacket(){
		return UDP::write(myBuffer, offset);
	};
	virtual size_t write(uint8_t buffer) {
		write(&buffer, 1);
		return 1;
	}
	virtual size_t write(const uint8_t *buffer, size_t size) {
		memcpy(&myBuffer[offset], buffer, size);
		offset += size;
		return size;
	}
};

myUDP Udp;