Intermittent TCP/IP messages

Hi I hope the forum can help. I have been working on skit for some time now and all works except for one bit. My code reads temperature, controllers relays, sends messages about the two and can receives some commands over TCP/IP.

The problem is in the TCP/IP. It reliably receives the command messages but is very unreliable in its responses. It only works about 50% of the time.

The code is supposed to:

  1. Start-up the comms and the sensors
  2. Do things with temperatures and relays
  3. Build a message string about what it has done
  4. Send the string to Serial and UDP/IP
  5. Look for a TCP/IP command, if one exists, read it, and do it
  6. If a command is received then echo the command and send the message to TCP/IP
    It does 1 to 5 OK and but only does 6 some times

I am using a UNO v3 with Arduino Ethernet 2 Wiznet W5500

The code below is a test programme made from the bits of the application that I have the issue with. It exhibits the same behaviour so its a good proxy from the full skit.

Any help or suggest are gratefully received as I know nothing about ethernet comms and have only been baffled by what I have found.

#include <Ethernet.h>
#include <EthernetUdp.h>
#include <avr/wdt.h>

/************************ IP SETTINGS **********************/
//THESE VALUES MY BE ALTERED
#define MAC_ADDRESS \
  { 0xA8, 0x61, 0x0A, 0xAF, 0x1A, 0xAA }

#define IP_ME 192, 168, 6, 177
#define IP_DEST 192, 168, 6, 155
#define IP_DNS 192, 168, 6, 1
#define IP_GATEWAY 192, 168, 6, 1
#define IP_SUBNET 255, 255, 0, 0

// Commenting out the UDP_PORT definition removes UDP function from the code
#define UDP_PORT 8888
#define TCP_PORT 80

#define COMMAND_ENDS '\n', '\r', ' ', '\0'  //Symbols that could end a command string
char _list[5] = { COMMAND_ENDS };

/*********************** Global Veriables ********************/
//THESE VALUES MUST NOT BE ALTERED
bool _SerialSt = true;  //True = stream the messagge to Serial
bool _TCPSt = true;     //True = stream the messagge to TCP
bool _sOK = false;      //True = the serial comms have been established
bool _ipOK = false;     //True = IP comms have been established
char _msgTxt[1200];     //The current message to send

//User Set Network & IP Settings
byte mac[] = MAC_ADDRESS;  //The mac adderess of the Ethernet shield
IPAddress ip1(IP_ME);      //The static IP address of this EPCS unit
IPAddress ip2(IP_DEST);    //The Network IP Address of the device to recive the UDP
IPAddress myDns(IP_DNS);
IPAddress gateway(IP_GATEWAY);
IPAddress subnet(IP_SUBNET);
EthernetServer server(TCP_PORT);  //The Ethernet port to use
bool _alreadyConnected = false;   // whether or not the client was connected previously

//If a port has been declared then use UDP output
#ifdef UDP_PORT
bool _UDPSt = true;                 //True = stream the messagge to UDP
unsigned int localPort = UDP_PORT;  //The UDP port to use
EthernetUDP Udp;                    //The Udp instance
#endif

/*********************** Start of Code **********************/

//Send the message to the verious outputs
void Snd() {
  //Send the Serial text
  if (_sOK && _SerialSt) Serial.println(_msgTxt);
  //Deal with TCP I/O
  SendIP();
#ifdef UDP_PORT
  //Write a line of UDP
  if (_ipOK && _UDPSt) {
    Udp.beginPacket(ip2, localPort);
    Udp.write(_msgTxt);
    Udp.endPacket();
    Udp.flush();
  }
#endif
  strcpy(_msgTxt[0], "");  //clear the message text
}

//Sends and recieves TCP messages
void SendIP() {
  int i;
  bool gotit = false;
  char incomming[20], a;
  EthernetClient client = server.available();  //The Ethernet client object

  //Looks for a client and then sends what it has stored in rolling buffer
  if (_ipOK && client) {
    i = 0;
    if (client.available() > 0) {
      while (client.connected() && gotit == false) {
        a = client.read();  //Get input character by character
        incomming[i] = a;
        i++;
        if (strchr(_list, a) || (i > 20 - 2)) gotit = true;
      }
      incomming[i] = '\0';  //Terminate the new string
      Serial.println(incomming);
      Serial.println(client.connected());
      client.println(incomming);
      Serial.println(client.connected());
      client.println(_msgTxt);
      Serial.println(client.connected());
    }
  }
}

//Start the verious comms options
bool StartComms() {
  unsigned long Timeout = millis();

  //Enables the serial port for information output, if its connected
  if (!_sOK) {
    Serial.begin(9600);
    while (!Serial) {  //Wait for the serial to start.  if it does not then disable the serial
      if (millis() - Timeout > 1000) break;
    }
    if (Serial) _sOK = true;
  }

  //Enables the ethernet if its connected and cabled
  if (!_ipOK) {
    //Start the common Ethernet elements
    Ethernet.init(10);                                 // Most Arduino shields
    Ethernet.begin(mac, ip1, myDns, gateway, subnet);  // start the Ethernet connection and the server:
    _ipOK = true;
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      strcpy(_msgTxt, "Error, Ethernet shield not found \r");
      _ipOK = false;
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      strcpy(_msgTxt, "Error, Ethernet cable is not connected \r");
      _ipOK = false;
    }
    if (_ipOK) {
      server.begin();  //Start TCP server
#ifdef UDP_PORT
      Udp.begin(localPort);  //Start UDP
#endif
    }
  }
  if (strlen(_msgTxt) > 1) Snd();
  return _ipOK;
}

void setup() {
  //Start the communications
  StartComms();
}

void loop() {

  unsigned long now = millis();

  strcpy(_msgTxt, "\0");
  for (int i = 0; i < 10; i++) {
    strcat(_msgTxt, "0123456789");
  }
  Snd();  //Send the output and get any command inputs

  while (millis() - now < 1000) {};  //wait for the next cycle delay
}`Use code tags to format code for the forum`

The way its set up at the end of void loop(), that is not the way to use millis(). That will block for the timeout duration and you may as well have just used delay(1000);

Thanks for this. I did start off with delay() but that produces loops that are always longer than the timestep I want. In the real programme the loop actually takes somewhere between 120 and 200 ms to complete. I am always open to suggested improvements.

Ok, so you used millis() for better timing accuracy, however, you can use millis() to trigger an action WHEN it has reached a certain timeout, in the meantime allowing the loop run and do other things, rather than having the CPU tied up in a loop and being prevented from doing other things UNTIL timeout.

I am not sure why the Arduino is sending only 50% of responses, but have a suspicion it might be related to the processor is tied up in that loop. This video helped my to understand how millis() can be used without having CPU cycles being tied up:

^https://www.youtube.com/watch?v=dCku8BabPx4

The example demostrates this with LEDs, but you gives a good idea of the principle.

Thanks for this. I have watched the video and amended the main loop to look like this:

void loop() {

  unsigned long now;

  //simualtes doing somthing
  strcpy(_msgTxt, "\0");
  for (int i = 0; i < 10; i++) strcat(_msgTxt, "0123456789");

  now = millis();
  //send the output and get any input
  if ((now - _laststep) > DELAY) {
    _laststep = now;
    Snd();
  }

It is better code, thanks, but it unfortunately does not change the issue with the TCP/IP.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.