Hard fault caused by the TCPServer example from the Spark docs and a simple Python client

AMEN! :smile:

All I need it a stable platform for a few hundred bytes of data every so often. Currently I can't get 200 bytes of data every 5 seconds to be stable longer than 10-15 mins. I don't think that is unreasonable for the Spark.

1 Like

Agreed, I want to love the spark core but for something that is such a basic feature of it, it’s failing terribly.

3 Likes

I moved 5 posts to a new topic: User code sometimes blocked by cc3000 in manual mode?

I feel the same way. Bringing some robustness to the TCP stack would be a wonderful thing, the code being opaquely locked inside the cc3000 limits our options.

But try we must! I have some free time over the holiday period to take a look at the TCP stack, in particular the ACK/NAK application handling that the new TI driver patch offers in the hope that we can fix these issues. Fingers crossed! :slight_smile:

3 Likes

@mdma Hey - I’m happy to pitch in too. Let me know how I can help. I have a JTAG shield and Segger JLink + and I’m not afraid to use it :smile:

OK - well I have it but have not yet figured out how to use it.

Thanks for your offer of help! There’s a great tutorial by Elco on how to setup JTAG debugging. Familiarize yourself with debugging first and then we can take it from there!

1 Like

@mtnscott, i tested the code and got the same SOS result for Hard fault

The pattern on the python script:

0
1
2
3
4
5
6
7
8
9


0
1
2
3
4
5
6
7

You are getting a few characters further, but basically you get thru one connection and the second one fails.

I’m so glad to hear that TCP is being worked on as I’m basing a large chunk of my project on it.

If it’s any help I can share my issues so far. I was having similar problems with the cores disconnecting when sending streams of packets. I’ve made a fix which I’m just using for testing whereby the core doesn’t send the packet until it gets a keystroke. The interesting thing is that if I send the packet just as the previous packet finishes processing it works fine and if I continue to press the key at the right time the spark will continue to work perfectly. If I wait too long between the previous packet being processed and sending another, It disconnects. If I try to send a packet while the previous packet is still being processed it disconnects.

This made just be my code of course but I thought I’d chime in as I’ve been playing around with the TCP stuff alot. (I’m communicating spark to spark if that wasn’t a given)

Code:

byte serv[] = { 127, 0, 1, 1 }; //dos
//SYSTEM_MODE(MANUAL);<
//TCPServer server = TCPServer(23);
TCPClient client;
#include <string.h>
#include <stdio.h>
void setup()
{
    Serial.begin(9600);
  // start listening for clients
    while(!Serial.available()) SPARK_WLAN_Loop();
  //  client.connect(serv,23);
    if (client.connect(serv, 80))
    {
        Serial.println("connected");
        client.println("We are all connected");
    }
    else
    {
        Serial.println("connection failed");
    }
}

String getValue(String data, char separator, int index)
{
  int found = 0;
  int strIndex[] = {0, -1};
  int maxIndex = data.length()-1;

  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i)==separator || i==maxIndex){
        found++;
        strIndex[0] = strIndex[1]+1;
        strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }

  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}

void loop()
{
    Serial.println("Yep");    
    int x = 0;
    if (client.connected())
    {   

        }*/if (Serial.available() > 0) {
    // read the incoming byte:
                x = Serial.read();

    // say what you got:
                Serial.print("I received: ");
                Serial.println(x);
                if ( x!=-1){
            client.write(x);
            delay(200);
            Serial.println("Here");
            Serial.println("Length is: ");
            int length = client.read();
            Serial.println(length);
            client.flush();
            String s4 = "";
            Serial.println(s4);


            for (int i=1; i <= length; i++){
                delay(1000);
                char be = client.read();
                s4 += be;
                Serial.println(s4);
                }
        Serial.println("Post for loop");

        s4 += "\0";
        String word1 = getValue(s4, ' ', 0);
        String word2 = getValue(s4, ' ', 1);
        String word3 = getValue(s4, ' ', 2);
        String word4 = getValue(s4, ' ', 3);
        String word5 = getValue(s4, ' ', 4);
        
        
        Serial.println("");
        Serial.println("The Unique ID of this packet is: ");
        Serial.print(word1);
        Serial.println("");
        Serial.println("The ZigBeeType of this packet is: ");
        Serial.println(word2);
        Serial.println(word3);
        Serial.println(word4);
        Serial.println(word5);
        
        int y = 2;
        client.write(y);
        delay(200);
        Serial.println("Packet Ready!");
        }else{delay(2000);}
    }else{Serial.println("Serial Error");delay(2000);}
        
    }else{Serial.println("Disconnecting");delay(2000);} 

}

More code:


#include <string.h>
TCPServer server = TCPServer(80);
TCPClient client; 

void setup()
{
    Serial.begin(9600);
  // start listening for clients
    server.begin();
    while(!Serial.available()) SPARK_WLAN_Loop();
  // Make sure your Serial Terminal app is closed before powering your Core

  // Now open your Serial Terminal, and hit any key to continue!

}

void loop()
{
   // char packet[10] = "packet";

    int y = 0;
    //Serial.println("Check");
    //char UUID[9] = "1234567 "; // int length;
    char UUID[] = {'1', '2', '3', '4', '5', '6', '7', ' '};
    char ZigBeeType[] = {'0', 'x', '0', '6', '0', '0', ' '};
    char data1[] = {'T', 'h', 'i', 's', ' '};
    char data2[] = {'i', 's', ' '};
    char data3[] = {'d', 'a', 't', 'a', '!'};
    
    char packet [28];

    memcpy(packet, UUID, 8);
    memcpy(&packet[8], ZigBeeType, 7);
    memcpy(&packet[15], data1, 5);
    memcpy(&packet[20], data2, 3);
    memcpy(&packet[23], data3, 5);

        if (client.connected()) {
            while (client.available()) {
                int x = client.read();
                Serial.println("Wales");
                Serial.println(x);
                client.flush();
                if(x==49){
                int length = arraySize(packet);
                client.write(length);
                Serial.println("England");
                client.flush();
                //delay(500);
                Serial.print("It's working, promise:  ");
                client.write(packet);
                Serial.println(packet);
                client.flush();
                delay(5000);
                int x = 0;
                }else{delay(10);}
                
            }
    } else {
    // if no client is yet connected, check for a new connection
        Serial.print(" No connection here ");
        client = server.available();
        delay(200);
    } 
    //Serial.print(c);
    delay (10);

}

As I previously said it could, quite easily be my code. Hope it helps regardless!

I am new to this Spark Core thing, but I had the TCP server, client, and all that working fine and reliably for a while. It was slow, but regardless it was reliable and consistent; if things failed I knew where.

I recently this week updated to the “deep update” or cc3000 patch because cyan flash of death became high priority to solve and only now am I experiencing all this inconsistency and unreliability. I’m either hard faulting (SOS, 1 blink, SOS) or I can’t make more than two transmissions without having consistent connection fails, which then my function times out after a while, and everything rinses and repeats.

I have time now to dig, if I can fix the connection failures from the user made HTTP client library I might go with that. It seemed to give me the fastest connections/transmissions. However I will work with my TCP code to see if I can get back to that old kind of slow reliability I once had.

I’m grateful to know this is a known issue and it wasn’t just me going bananas. I guess I’ll keep posted here if I find anything, if I can help I will!

EDIT: Im using the user made HTTP library successfully for a few days now. Im not experiencing the hard fault anymore. I have moved away from strictly using the TCP client, although I know the HTTP library uses TCP it seems to be working and I haven`t seen hard faults in a long time. fingers crossed

2 Likes

Any other updates on this issue?

Hey guys,

Any updates towards a solution for this? Thread’s pretty old so perhaps this has been fixed by now?

I’m asking since I’ve been playing with TCPServer the last couple of days and today I got the same hard fault error immediately after the first connection or two and it was definitely related to the speed my client (photon 1) was sending data to my server (photon 2). Putting a delay would make it crash later where a delay higher than 200ms would not make it crash for 30 minutes straight. However, when I forced the client to wait for a server response before sending data again, the issue disappeared for me and I was able to send data at a pretty decent speed (estimating about 100ms, perhaps less). Note that I do turn off cloud connection to get this speed.

If you have test code, please share so we can peer review that and investigate if it looks like a system firmware issue.

I’m running some tests now. I’m blasting a Photon (0.4.9) and TCPServer with data as fast as it will take it and hasn’t faulted or experienced any data corruption yet. 40 MB received at a rate of about 124 Kbytes/sec so far. Apparently the Photon is much better at sending data (over 900 Kbytes/sec) than receiving it, or there’s a bug in my test. More info, including the source, to come after some more testing.

1 Like

Here’s my quick test. I have a Photon (0.4.9) and it’s running a TCPServer in the program below. It accepts a connection and receives 10 MB of data as fast as it can. It takes about 83 seconds or around 123 Kbytes/sec. Then it closes the connection and the process immediately repeats on a new connection. I let this go 30 times, for a total of 300 MB of data received by the Photon. No problems so far. I’m going to try a few other things to see if I can cause trouble.

#include "Particle.h"

const int MAX_CLIENTS = 5;
const int LISTEN_PORT = 7123;
const int CLIENT_BUF_SIZE = 1024;
const unsigned long INACTIVITY_TIMEOUT_MS = 30000;
const int CLOSE_AFTER_SIZE = 1024 * 1024 * 10; // 10 MB, set to -1 for unlimited

class ClientConnection {
public:
	ClientConnection();
	virtual ~ClientConnection();

	void loop();
	bool accept();

protected:
	void clear();
	void readRequest();
	void writeData();

private:
	unsigned char clientBuf[CLIENT_BUF_SIZE];
	bool inUse;
	int clientId;
	TCPClient client;
	int readOffset;
	int writeOffset;
	unsigned long lastUse;
	unsigned char expectedChar;
	unsigned long bytesRead;
	time_t startTime;
};


String localIP;
TCPServer server(LISTEN_PORT);
ClientConnection clients[MAX_CLIENTS];
int nextClientId = 1;

void setup() {
	Serial.begin(9600);

	// From CLI, use something like:
	// particle get test5 localip
	// to get the IP address of the Photon (replace "test5" with your device name)
	localIP = WiFi.localIP(); // localIP must be a global variable
	Particle.variable("localip", localIP);
	Serial.printlnf("server=%s:%d", localIP.c_str(), LISTEN_PORT);

	server.begin();
}

void loop() {
	// Handle any existing connections
	for(int ii = 0; ii < MAX_CLIENTS; ii++) {
		clients[ii].loop();
	}

	// Accept a new one if there is one waiting (and we have a free client)
	for(int ii = 0; ii < MAX_CLIENTS; ii++) {
		if (clients[ii].accept()) {
			break;
		}
	}
}


ClientConnection::ClientConnection() : inUse(false) {
	clear();
}

ClientConnection::~ClientConnection() {
}

void ClientConnection::loop() {
	if (!inUse) {
		return;
	}

	if (client.connected()) {
		readRequest();

		if (millis() - lastUse > INACTIVITY_TIMEOUT_MS) {
			Serial.printlnf("%d: inactivity timeout", clientId);
			client.stop();
			clear();
		}
	}
	else {
		Serial.printlnf("%d: client disconnected", clientId);
		client.stop();
		clear();
	}
}

bool ClientConnection::accept() {
	if (inUse) {
		return false;
	}

	client = server.available();
	if (client.connected()) {
		lastUse = millis();
		inUse = true;
		clientId = nextClientId++;
		startTime = Time.now();
		Serial.printlnf("%d: connection accepted", clientId);
	}
	return true;
}

void ClientConnection::clear() {
	lastUse = 0;
	readOffset = 0;
	writeOffset = 0;
	inUse = false;
	expectedChar = 0;
	bytesRead = 0;
}

void ClientConnection::readRequest() {
	// Note: client.read returns -1 if there is no data; there is no need to call available(),
	// which basically does the same check as the one inside read().

	int count = client.read(clientBuf, CLIENT_BUF_SIZE);
	if (count > 0) {
		for(int ii = 0; ii < count; ii++) {
			if (clientBuf[ii] != expectedChar) {
				Serial.printlnf("%d: mismatch expected %02x got %02x index %d bytesRead %d, closing",
						clientId, expectedChar, ii, bytesRead + ii);
				client.stop();
				clear();
				break;
			}
			expectedChar++;
			bytesRead++;

			if (CLOSE_AFTER_SIZE > 0 && bytesRead >= CLOSE_AFTER_SIZE) {
				time_t now = Time.now();

				Serial.printlnf("%d: received %d bytes in %d sec, closing connection",
						clientId, bytesRead, now - startTime);
				client.stop();
				clear();
				break;
			}
		}
		lastUse = millis();
	}
}

2 Likes

My client sends a variable looping from 0-254 and back again. This is converted to char’s that are then sent over to the server which puts them into an emptied char array which is then converted back to integers so I can use it to analogWrite an LED. This is working pretty well, speed is below 100ms definitely. Sometimes however, I get a value of 0 for some reason when the wifi seems to hiccup a bit, can’t explain why yet.

TCPServer code:

//adapted from @Hootie81 & @jon1977 & others in community.particle.io
#include "Particle.h"
SYSTEM_MODE(MANUAL);
int serverPort = 6123;
uint32_t lastTime;
TCPServer server = TCPServer(serverPort);
TCPClient client;

const char replymsg[60] = "TheInMsg and then a whole lot more characters than before";
String myInStr;
char myIpString[24];
char outmsg[50];
int LED = D7;
int ledPin1 = D3;
int val;

void out(const char *s) {server.write( (const uint8_t*)s, strlen(s) );  client.stop();}

void in(char *ptr, uint8_t timeout) {
  int pos = 0;
  unsigned long lastdata = millis();
  while ( client.available()  || (millis()-lastdata < timeout)) {
    if (client.available()) {
      char c = client.read();
      lastdata = millis();
      ptr[pos] = c;
      pos++;
    }
  }
  client.read();
  client.flush();
}

void setup()
{
    Serial.begin(9600);
    WiFi.connect();
    while (!WiFi.ready()) {Particle.process();}
    server.begin(); // begin listening for TCP connections
    pinMode(LED, OUTPUT);
    pinMode(ledPin1, OUTPUT);
}

void loop() {
    delay(1);
    if (!WiFi.ready()) {
        Particle.process();
        WiFi.connect();
        while(WiFi.connecting()) {Particle.process();}
    }else{
        if (client.connected()){
            char inmsg[512]; //Quite important to empty the array every time, had a problem earlier where if I received "154" and then "12" it would say "124" instead of "12" due to inmsg[2] still being assigned to "4"
            in(inmsg,10); //40 pure trial and error and longer than in client
            val = atoi(inmsg);
            Serial.println(val);
            myInStr = inmsg;
            analogWrite(D3, val);
            if (strlen(myInStr) >= 0) {
                lastTime = millis();
                while( millis()-lastTime < 5){}
                out(replymsg);
            }
        }else{
            client = server.available();
        }
    }
}

TCPClient code:

//adapted from @Hootie81 & @jon1977 in community.particle.io
#include "Particle.h"
SYSTEM_MODE(MANUAL);
int serverPort = 6123;
uint32_t lastTime;
const char replymsg[60] = "TheInMsg and then a whole lot more characters than before";
char clientmsg[4] ="255";
char inmsg[512];
String myInStr;
char myIpString[24];
byte server[] = {192, 168, 0, 160};//server's ip address
bool complete;
TCPClient client;
int val;

char outmsg[50];

void in(char *ptr, uint8_t timeout) {
  int pos = 0;
  unsigned long lastdata = millis();
  while ( client.available() || (millis()-lastdata < timeout)) {
    if (client.available()) {
      char c = client.read();
      lastdata = millis();
      ptr[pos] = c;
      pos++;
      //Serial.println("I received and read the response");
    }
  }
  client.read();
}

void out(const char *s) {
    client.write( (const uint8_t*)s, strlen(s) );
}

void setup()
{
  Serial.begin(9600);
  pinMode(D6,OUTPUT);
  pinMode(D7,OUTPUT);
  pinMode(D3,INPUT);
  while (!WiFi.ready()) {
    Particle.process();
    WiFi.connect();
    while(WiFi.connecting()) {Particle.process();}
  }
}

void loop() {
    
    val = (val + 1) % 255;
    sprintf(clientmsg,"%d",val); 
    Serial.println(val);
    
    
    complete = false;
    lastTime = millis();
   while ((!complete) &&  (millis() - lastTime < 100)) {
      if (client.connect( server, serverPort)) {
        if (client.connected()) {
            out(clientmsg);
            Serial.println(clientmsg);
            Serial.println("I'm connected and sending a message");
            lastTime = millis();
            while ((!client.available()) && (millis() - lastTime < 500)) {
                Particle.process();
                //Serial.println("Waiting for a response");
            }//wait for response
            in(inmsg,10);//5-10 pure trial and error
            myInStr =inmsg;
            if (myInStr.indexOf(replymsg)  >= 0) {
                complete = true;
            }
        }
        client.stop();
        Serial.println("Stopping client");
      }
    client.stop();
    Serial.println("Stopping client second check");
    }
  delay(1);
}

Most credits to @Hootie81 & @jon1977 for creating this code for the main part and putting it on GitHub, I only really troubleshooted and adapted it to my likings and fix the array bug that I mention in the Server code.

Okay, that’s a completely different test, opening and closing the connections after sending a very small amount of data. I’ll test that next after I finish the analysis of my last test. By the way, that’s a inefficient way to handle that; it would be much better to send multiple values over a single TCP connection, but it should still work without a fault so I’ll construct something to test that.

By the way, that’s a inefficient way to handle that; it would be much better to send multiple values over a single TCP connection

It would be awesome if you could show me how that's done ^^ I'm a bit of a rookie on TCP or WiFi communication in general.

Edit: This code of mine is a WIP btw, eventually the client needs to send 5 integer variables to the server so the server can interpret those and convert them to values to drive certain actuators. If you guys have some advice on how to properly do this, that would be really appreciated as well. Should I make a new thread for this (since this thread's topic is the hard fault)?

I ran my test above, sending a 1 MB per connection to a Photon overnight. There were no faults or reboots, though some of the connections closed early. That will require some more testing to get to the bottom of, but from a practical standpoint, who sends that much data to a Photon? Acquiring data I can certainly see it sending lots of data, but receiving it? The Photon successfully received 1.4 GB of data in the test. Up next: A test more like the Falxhor’s. And musing about maybe making a library to make it easier to send data between two Photons over TCP or UDP.

1 Like

In other projects, I use an abstraction called a conduit - a bidirectional pipe. You can then plug in UDP, TCP, Serial, even go so far as SPI, I2C where that makes sense.

Doing RPC between two photons or sending packetized data over a stream would be a cool libraries to have!

When AP mode is released, the TCP/UDP connection will be between both photons directly.

3 Likes