SparkFun Forums 

Where electronics enthusiasts find answers.

For the discussion of Arduino related topics.
By Ray Depew
#197997
I'm trying to set up a wireless TCP server, using an Elegoo Arduino Uno (equivalent to the SparkFun RedBoard) and a SparkFun ESP8266 shield. I pieced together the code from the examples that came with the ESP8266 and some other stuff I found on the Web (danger, Will Robinson!). It mostly works, except for the really important part.

From the client, I can send characters to the server, things like "Hello" and "abcdefgh" and "X". I want the server to print the received characters to my 16x2 LCD (and, for diagnostic purposes, to the Serial Monitor), and to echo the characters back to the client. But it's not receiving, or decoding, or displaying, the characters properly.

I would settle for it printing an "X" to the LCD every time it receives something, printing the hex value(s) of the received bytes(s) to the serial monitor, and then sending a "Y" back to the client. It does the "X", it does the "Y", but the output values all wrong. Am I using the client.read() command wrong?

Here's the code:
Code: Select all
/*
 * TCP server
 * 
 * Make sure this is the Elegoo/breadboard, 
 * at 192.168.0.131 and COM4.
 * It would also be useful to have the 16x2 LCD on.
 * 
 * Procedure:
 * 1. Get this running on the COM4 Arduino first. 
 * 2. Open a serial monitor on COM4, press a key and Enter 
 *    to make sure it's working.
 * 3. Send one or more characters using a TCP client.
 * 5. Anything the client sends should appear in the server's LCD.
 * 
 */
 
#include <SoftwareSerial.h> // Include software serial library, ESP8266 library dependency
#include <SparkFunESP8266WiFi.h> // Include the ESP8266 AT library
#include <LiquidCrystal.h> // For the LCD display

const int rs = 12, en = 11, d4 = 6, d5 = 5, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
ESP8266Server server = ESP8266Server(3230);

void setup() {
  Serial.begin(9600);
  Serial.println("TCP Server");
  serialTrigger(F("Press any key to begin."));

  lcd.begin(16,2);
  lcd.clear();

  if (esp8266.begin()) // Initialize the ESP8266 and check its return status
      Serial.println("ESP8266 ready to go!"); // Communication and setup successful
  else
      Serial.println("Unable to communicate with the ESP8266 :(");
  int retVal;
  retVal = esp8266.connect("Name_of_my_WifiAP", "supersecretpassword");
  if (retVal < 0)
  {
      Serial.print(F("Error connecting: "));
      Serial.println(retVal);
  }
  else
  {
    server.begin();
    IPAddress myIP = esp8266.localIP(); // Get the ESP8266's local IP
    Serial.print(F("Server started! IP is: ")); Serial.println(myIP);
    lcd.setCursor(0,0); // First line
    lcd.print("Server started");
    lcd.setCursor(0,1); // Second line
    lcd.cursor(); // Turn on cursor
  }
}

void loop() {
  ESP8266Client client = server.available(500); // 500 ms timeout

  if (client)
  {
    Serial.println(F("Client connected"));
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        Serial.print(c, HEX);
        lcd.print("X");
        client.write("Y");
      }
    }
    // close the connection:
    client.stop();
    Serial.println(F("Client disconnected"));
  }
}

// serialTrigger prints a message, then waits for something
// to come in from the serial port.
// I swiped this from the ESP8266 demo programs. Useful for debugging.
void serialTrigger(String message)
{
  Serial.println();
  Serial.println(message);
  Serial.println();
  while (!Serial.available())
    ;
  while (Serial.available())
    Serial.read();
}
When the client sends "Hello", the server prints "XX" to the LCD, successfully responds to the client with a "Y", and prints hex DD to the serial monitor:
Code: Select all
TCP Server

Press any key to begin.

ESP8266 ready to go!
Server started! IP is: 192.168.0.131
Client connected
DD
Client disconnected
If I replace
Code: Select all
char c = client.read();
Serial.print(c, HEX);
with
Code: Select all
Serial.println(client.read());
... then my serial monitor output looks like this:
Code: Select all
TCP Server

Press any key to begin.

ESP8266 ready to go!
Server started! IP is: 192.168.0.131
Client connected
13
13
Client disconnected
... which looks more like a pair of carriage returns (Ctl-D) than hex DD.

This is probably a really simple question that's been answered a million times. I looked, and couldn't find the answer. Any ideas?
By Ray Depew
#197998
For what it's worth, here's the tcp client code. It seems to be working fine. I've tested it with another server.
Code: Select all
 * Copyright Mark Watson 1999. Open Source Software License.
 * Note: derived from NLPserver client example.
 * See www.markwatson.com/opensource/opensource.htm for all
 * of the natural language server (NLPserver) source code.
 *
 * Updated by Ray Depew, December 2017
 */

#include <stdio.h>
#include <stdlib.h> // exit()
#include <string.h> // memset()
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> // close()
#include <netdb.h>

char * host_name = "192.168.0.131"; // localhost
// char * host_name = "127.0.0.1"; // localhost
int port = 3230;

void main(int argc, char *argv[])
{
  char buf[8192];
  char message[256];
  int socket_descriptor;
  struct sockaddr_in pin;
  struct hostent *server_host_name;

  char * str = "A default test string";

  if (argc < 2) {
    printf("Usage: 'test \"Any test string\"\n");
    printf("We will send a default test string.\n");
  } else {
    str = argv[1];
  }

  if ((server_host_name = gethostbyname(host_name)) == 0) {
    perror("Error resolving local host\n");
    exit(1);
  }

  memset(&pin, 0, sizeof(pin));
  pin.sin_family = AF_INET;
  pin.sin_addr.s_addr = htonl(INADDR_ANY);
  pin.sin_addr.s_addr = ((struct in_addr *)(server_host_name->h_addr))->s_addr;
  pin.sin_port = htons(port);

  if ((socket_descriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Error opening socket\n");
    exit(1);
  }

  if (connect(socket_descriptor, (void *)&pin, sizeof(pin)) == -1) {
    perror("Error connecting to socket\n");
    exit(1);
  }

  printf("Sending message %s to server...\n", str);

  /* FIXME: Delete after debug */
  int message_len = strlen(str);
  printf("(%d bytes)\n", message_len);

  if (send(socket_descriptor, &str, strlen(str), 0) == -1) {
    perror("Error in send");
    exit(1);
  }

  printf("..sent message.. wait for response...\n");

  if (recv(socket_descriptor, buf, 8192, 0) == -1) {
    perror("Error in receiving response from server\n");
    exit(1);
  }

  printf("\nResponse from server:\n%s\n", buf);

  close(socket_descriptor);
}
By paulvha
#198003
you are getting DD because your code is using Serial.print(c, Hex) and not Serial.println(c.hex). The 2 received 0x13 are displayed next to each other.
Then the question is why do you only get 0x13 and not the complete message that is send. I have been doing a lot of work over the past 2 weeks on the AT driver. Still working on it and plan to post on Github in the coming week:
I did a number of bugfixing and included new functionality.
An aspect that turned out a challenge is working with softSerial. (specially with larger messages > 64 bytes)
I discovered however that when you get a warning about low RAM during compile (below ~500 bytes) the system works very instable. Not sure you have that.
As a result I created working versions of loopback, talkback test with my raspberryPi (the basic of that code looks like yours)

What you can try is to add an extra delay loop around client.available (like in the code below). Maybe the "\r\r" is left over from previous message received in the buffer. (one aspect I have fixed in the driver)

The last aspect is that you will receive the data with a header like: +IPD,<ID>,<len>:<data>. I have written a routine to remove the header:
Code: Select all

/* read data from remote and strip +IPD.... header
 * client = client socket
 * out = buffer to store output
 * len = length of buffer
 * loop = retry count for checking
 * 
 * if len is zero, The read data after the header 
 * will be displayed
 * 
 * return: 
 * number of bytes received and stored in optional buffer
 * 
 */
int readData(ESP8266Client client, char *out, int len, int loop)
{
   bool wait = 1;
   char c;
   int i = 0; 

  // Try at least loop times
  while (loop > 0)
  {
     loop--;
     delay(5);    // wait 5ms
     
    // available() will return the number of characters
    // currently in the receive buffer.
    while (client.available() )
    {
      // get character from buffer
      c = client.read();
  
      // skip +IPD ....  header
      if (wait)
      {
        if (c == ':')  wait = 0;
        continue;
      }

      if (len == 0) Serial.write(c);
      else
      { //output to provided buffer
        out[i++] = c;
        if (i == len) return len;
      }
    }
  }
  
  // return count in buffer  
  return i;
}
By gregdwilson
#198064
I’ve had the same issue with a red board and the esp8266 shield. If I use the code Serial.write(client.read()); all is fine and dandy. As soon as I try char c = client.read() then my char is always two carriage returns. I’m excited to try your suggestion with a buffer. I was having the same issue on output. client.println() seems to send a packet for every character so I had make a buffer and use client.write(). I would love to take a look at your updates though. I feel the current sparkfun library is lacking.
By Ray Depew
#198107
Thanks, @paulvha. That gave me a few clues. But it looks like I'm going to have to go digging deeper into the library as well.

For both @paulvha and @gregdwilson: I noticed on the Web that there's another library out there, called ESP8266WiFi. I assume that SparkfunESP8266Wifi is an adaptation of it, but I haven't checked the source code to see the differences. More information on it is available at https://arduino-esp8266.readthedocs.io/. I've just started reading that site.

There's another library at https://github.com/bportaluri/WiFiEsp . I've only dipped my toes in the water there.
By paulvha
#198110
I have spend considerable amount of time on the Sparkfun ESP8266 AT library as my shield would not work as I was expecting. Next to the library is very basic, which I have extended with a number features and bug fixes.
As a result I have now relative stable working version of server implementations (server and SoftAP) with loopback (echo what was send), talkback (basic chat between client and serial monitor) and handling GPIO (setting, blinking, reading digital and analog input) from a remote client. The remote client is written in C, tested with RaspberryPI and is made available are as well.
I am in final process of testing and documenting. That takes MUCH more time than expected.. but I hope today or tomorrow.
By paulvha
#198188
finally got it ready and posted the updated and enhanced library based on the original work done by SparkFun. It is posted on https://github.com/paulvha/PVH_ESP8266_ ... no_Library. It contains new sketches to set as server, SoftAp or Client to perform loopback, talkback (basic chat) and controlling GPIO pin on both Arduino and ESP8266 from remote client. In order to test, code in 'C' is included to perform the client functions and a program to act as server to the Arduino client sketch. This has been tested on both Raspberry PI-3 and Ubuntu LTS 16.4. The library has workbooks and documentation to explain.