Crash in CC3000 on repeated TCP connections

For other supported Arduino products from Adafruit: Shields, accessories, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Crash in CC3000 on repeated TCP connections

Post by jouster »

I'm running this test code below, making TCP calls to ThingSpeak every 30 seconds. I've found that I get a crash/lockup inside the Adafruit_CC3000_Client::connected(void) function after this runs for about five minutes. I've been able to stop these crashes by inserting a delay(10) in the second line of the connected function. I have no clear idea why this fixes it and it's not fixing a root cause. Any thoughts/suggestions? Is the test code doing something wrong?

Code: Select all

bool Adafruit_CC3000_Client::connected(void) { 
  if (_socket < 0) return false;
  delay(10);   // THIS PREVENTS THE CRASH
  if (! available() && closed_sockets[_socket] == true) {
    //if (CC3KPrinter != 0) CC3KPrinter->println("No more data, and closed!");
    closesocket(_socket);
    closed_sockets[_socket] = false;
    _socket = -1;
    return false;
  }

  else return true;  
}

Code: Select all

/*************************************************** 
  This is an example for the Adafruit CC3000 Wifi Breakout & Shield

  Designed specifically to work with the Adafruit WiFi products:
  ----> https://www.adafruit.com/products/1469

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
 
 /*
This example does a test of the TCP client capability:
  * Initialization
  * Optional: SSID scan
  * AP connection
  * DHCP printout
  * DNS lookup
  * Optional: Ping
  * Connect to website and print out webpage contents
  * Disconnect
SmartConfig is still beta and kind of works but is not fully vetted!
It might not work on all networks!
*/
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include <Streaming.h>

#include "utility/debug.h"

// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed
#define WLAN_SSID       "myNetwork"           // cannot be longer than 32 characters!
#define WLAN_PASS       "myPassword"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define IDLE_TIMEOUT_MS  1000      // Amount of time to wait (in milliseconds) with no data 
                                   // received before closing the connection.  If you know the server
                                   // you're accessing is quick to respond, you can reduce this value.

#define MAXGAUGES 7
// What page to grab!
#define WEBSITE      "api.thingspeak.com"
//#define WEBPAGE      "/channels/4027/field/1/last.txt"
//const char* fieldFormatString = "/channels/4027/field/%d/last.txt?prepend=$&append=$";
const char* fieldFormatString = "/channels/9/field/%d/last.txt?prepend=$&append=$";

/**************************************************************************/
/*!
    @brief  Sets up the HW and the CC3000 module (called automatically
            on startup)
*/
/**************************************************************************/

uint32_t ip;
unsigned long pollTime;
const unsigned int pollDelay = 30000;

void setup(void)
{
  pollTime = millis() + pollDelay;
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n")); 


  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  
  /* Initialise the module */
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }
  
  // Optional SSID scan
  // listSSIDResults();
  
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }
   
  Serial.println(F("Connected!"));
  
  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(100); // ToDo: Insert a DHCP timeout!
  }  

  /* Display the IP address DNS, Gateway, etc. */  
  while (! displayConnectionDetails()) {
    delay(1000);
  }
}
int pollWebsite(){
  char webpage[80];
  sprintf(webpage, fieldFormatString, 0);
  Serial << "webpage = " << webpage << endl;
  ip = 0;
  // Try looking up the website's IP address
  Serial.print(WEBSITE); Serial.print(F(" -> "));
  while (ip == 0) {
    if (! cc3000.getHostByName(WEBSITE, &ip)) {
      Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }

  cc3000.printIPdotsRev(ip);
  
  // Optional: Do a ping test on the website
  /*
  Serial.print(F("\n\rPinging ")); cc3000.printIPdotsRev(ip); Serial.print("...");  
  replies = cc3000.ping(ip, 5);
  Serial.print(replies); Serial.println(F(" replies"));
  */  

  /* Try connecting to the website.
     Note: HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read.
  */
  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    www.fastrprint(F("GET "));
    www.fastrprint(webpage);
    www.fastrprint(F(" HTTP/1.1\r\n"));
    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
    www.fastrprint(F("\r\n"));
    www.println();
  } else {
    Serial.println(F("Connection failed"));    
    return 0 ;
  }

  Serial.println(F("-------------------------------------"));
  
  /* Read data until either the connection is closed, or the idle timeout is reached. */ 
  unsigned long lastRead = millis();
  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {  //CRASH HAPPENS IN HERE
    while (www.available()) {        
      Serial << "!\n";
      char c = www.read();
      Serial.print(c);
      lastRead = millis();
    }
    Serial << "$\n";
  }
  Serial << "exitted\n";
  www.close();
  Serial.println(F("----------------END----------------"));

  return 0;
  
}

void loop(void)
{
  int newValue;

  if (millis() > pollTime){   
    pollTime = millis() + pollDelay;
  
    newValue = pollWebsite();
    Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
    Serial << "Time (secs) = " << millis()/1000 << endl;
  }
}


/**************************************************************************/
/*!
    @brief  Begins an SSID scan and prints out all the visible networks
*/
/**************************************************************************/

void listSSIDResults(void)
{
  uint8_t valid, rssi, sec, index;
  char ssidname[33]; 

  index = cc3000.startSSIDscan();

  Serial.print(F("Networks found: ")); Serial.println(index);
  Serial.println(F("================================================"));

  while (index) {
    index--;

    valid = cc3000.getNextSSID(&rssi, &sec, ssidname);
    
    Serial.print(F("SSID Name    : ")); Serial.print(ssidname);
    Serial.println();
    Serial.print(F("RSSI         : "));
    Serial.println(rssi);
    Serial.print(F("Security Mode: "));
    Serial.println(sec);
    Serial.println();
  }
  Serial.println(F("================================================"));

  cc3000.stopSSIDscan();
}

/**************************************************************************/
/*!
    @brief  Tries to read the IP address and other connection details
*/
/**************************************************************************/
bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
  
  if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
  {
    Serial.println(F("Unable to retrieve the IP Address!\r\n"));
    return false;
  }
  else
  {
    Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
    Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
    Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Crash in CC3000 on repeated TCP connections

Post by adafruit_support_mike »

Let me forward this one to the folks who manage the CC3000 library. It sounds like some kind of timing issue, but they may be able to trace it to something specific.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

Thanks. I'm finding this crash is more frequent as I strip out the serial debug statements as well.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

Hello,

I'm still seeing this, even on the most basic sketches. I've taken the WebClient example and put it into a loop with a CC3000 disconnect at the end. It connects to the www.adafruit.com/testwifi/index.html website every 15-20 seconds and prints it out. I've attached the minimally modified example below. It usually hangs about 5-30 minutes in (YMMV).

As far as I can tell, it's crashing somewhere in the socket.cpp::select function.

I know this is a work-in-progress, but it seems like a fundamental flaw as most applications using this device will do something like this over and over.

Let me know how I can help. I am stuck.

Thanks.

Code: Select all

/*************************************************** 
  This is an example for the Adafruit CC3000 Wifi Breakout & Shield

  Designed specifically to work with the Adafruit WiFi products:
  ----> https://www.adafruit.com/products/1469

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/
 
 /*
This example does a test of the TCP client capability:
  * Initialization
  * Optional: SSID scan
  * AP connection
  * DHCP printout
  * DNS lookup
  * Optional: Ping
  * Connect to website and print out webpage contents
  * Disconnect
SmartConfig is still beta and kind of works but is not fully vetted!
It might not work on all networks!
*/
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"

// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed

#define WLAN_SSID       "myNetwork"           // cannot be longer than 32 characters!
#define WLAN_PASS       "myPassword"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define IDLE_TIMEOUT_MS  3000      // Amount of time to wait (in milliseconds) with no data 
                                   // received before closing the connection.  If you know the server
                                   // you're accessing is quick to respond, you can reduce this value.

// What page to grab!
#define WEBSITE      "www.adafruit.com"
#define WEBPAGE      "/testwifi/index.html"


/**************************************************************************/
/*!
    @brief  Sets up the HW and the CC3000 module (called automatically
            on startup)
*/
/**************************************************************************/

uint32_t ip;

void setup(void)
{
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n")); 
}

void connectTCPIP(){
  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  
  /* Initialise the module */
  Serial.println(F("\nInitializing..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }
  
  // Optional SSID scan
  // listSSIDResults();
  
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }
   
  Serial.println(F("Connected!"));
  
  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  unsigned long timeout = millis() + 10000;
  while (!cc3000.checkDHCP() && millis() < timeout)
  {
    delay(100); // ToDo: Insert a DHCP timeout!
  }  
  if (millis() >= timeout){
    Serial.println(F(" DHCP request timed out"));
    cc3000.disconnect();
    return;
  }

  /* Display the IP address DNS, Gateway, etc. */  
  while (! displayConnectionDetails()) {
    delay(1000);
  }

  ip = 0;
  // Try looking up the website's IP address
  Serial.print(WEBSITE); Serial.print(F(" -> "));
  while (ip == 0) {
    if (! cc3000.getHostByName(WEBSITE, &ip)) {
      Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }

  cc3000.printIPdotsRev(ip);
  
  // Optional: Do a ping test on the website
  /*
  Serial.print(F("\n\rPinging ")); cc3000.printIPdotsRev(ip); Serial.print("...");  
  replies = cc3000.ping(ip, 5);
  Serial.print(replies); Serial.println(F(" replies"));
  */  

  /* Try connecting to the website.
     Note: HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read.
  */
  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    www.fastrprint(F("GET "));
    www.fastrprint(WEBPAGE);
    www.fastrprint(F(" HTTP/1.1\r\n"));
    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
    www.fastrprint(F("\r\n"));
    www.println();
  } else {
    Serial.println(F("Connection failed"));    
    return;
  }

  Serial.println(F("-------------------------------------"));
  
  /* Read data until either the connection is closed, or the idle timeout is reached. */ 
  unsigned long lastRead = millis();
  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    while (www.available()) {
      char c = www.read();
      Serial.print(c);
      lastRead = millis();
    }
  }
  www.close();
  Serial.println(F("-------------------------------------"));
  
  /* You need to make sure to clean up after yourself or the CC3000 can freak out */
  /* the next time your try to connect ... */
  Serial.println(F("\n\nDisconnecting"));
  cc3000.disconnect();
  
}

void loop(void)
{
 connectTCPIP();
 delay(10000);
}

/**************************************************************************/
/*!
    @brief  Begins an SSID scan and prints out all the visible networks
*/
/**************************************************************************/

void listSSIDResults(void)
{
  uint8_t valid, rssi, sec, index;
  char ssidname[33]; 

  index = cc3000.startSSIDscan();

  Serial.print(F("Networks found: ")); Serial.println(index);
  Serial.println(F("================================================"));

  while (index) {
    index--;

    valid = cc3000.getNextSSID(&rssi, &sec, ssidname);
    
    Serial.print(F("SSID Name    : ")); Serial.print(ssidname);
    Serial.println();
    Serial.print(F("RSSI         : "));
    Serial.println(rssi);
    Serial.print(F("Security Mode: "));
    Serial.println(sec);
    Serial.println();
  }
  Serial.println(F("================================================"));

  cc3000.stopSSIDscan();
}

/**************************************************************************/
/*!
    @brief  Tries to read the IP address and other connection details
*/
/**************************************************************************/
bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;
  
  if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
  {
    Serial.println(F("Unable to retrieve the IP Address!\r\n"));
    return false;
  }
  else
  {
    Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
    Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
    Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm

Re: Crash in CC3000 on repeated TCP connections

Post by adafruit »

Thanks, we have speeded up the library a bunch since release which may mean we have to reinsert some delays, testing in progress!

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: Crash in CC3000 on repeated TCP connections

Post by tdicola »

Thanks for providing the full sketch. I also reproduced a random freeze after it runs for a few minutes, and the interesting thing is it always seems to freeze with the same output:

-------------------------------------
HTTP/1.1 200 OK
Date: Sat, 01 Feb 2014 19:57:15 GMT
Server: Apache
Access-Control-Allow-Origin: http://learn.adafruit.com
Ac

Do you see it freezing at that output too?

The interesting thing is that it's exactly 128 characters long, which means the CC3000 single character read function is about to call recv on the socket to pull in more data (its buffer is 64 bytes long). Unfortunately when I add more debug output to see where it's freezing, the problem doesn't repro. My suspicion is the connection is being closed by the server and either the select or recv call isn't handling it well, perhaps the call is completely blocking or getting stuck in an odd state. Adding a delay, either explicitly or with more debug output, is probably making the connection close happen at a different time which is less likely to cause problems. I'll see if I can dig further into the library to see where exactly it's getting stuck--I've tried checking the loops for waiting on events in TI's driver code and oddly they don't seem to be where it's freezing.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

tdicola wrote:Thanks for providing the full sketch. I also reproduced a random freeze after it runs for a few minutes, and the interesting thing is it always seems to freeze with the same output:

-------------------------------------
HTTP/1.1 200 OK
Date: Sat, 01 Feb 2014 19:57:15 GMT
Server: Apache
Access-Control-Allow-Origin: http://learn.adafruit.com
Ac

Do you see it freezing at that output too?
Perhaps. Here is where it's freezing reading ThingSpeak:

HTTP/1.1 200 OK
Server: nginx/1.5.7
Date: Sat, 01 Feb 2014 15:25:31 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Enc

Which I count as 124 bytes. Pretty close. I think you're on to something.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

Actually I just counted your output as 124 bytes as well (cut & paste into an editor). Mine is exactly the same.

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: Crash in CC3000 on repeated TCP connections

Post by tdicola »

Yeah for every line break actually count 2 characters since there's a \r and \n that isn't printed to the console, that should get you to 128 characters. Interesting that you see the same thing too, at least that confirms we're dealing with likely the same issue.

One weird thing to try, comment out the www.println() at the end of the section that sends the web request. It's actually not part of the HTTP protocol and probably a small bug with the example. However the weird thing is with that commented out, it's been running for a few hours without lockups for me. Here's the code specifically:

Code: Select all

Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    www.fastrprint(F("GET "));
    www.fastrprint(WEBPAGE);
    www.fastrprint(F(" HTTP/1.1\r\n"));
    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
    www.fastrprint(F("\r\n"));
    // Comment out the \r\n below because it's not technically part of the HTTP request.
    // www.println();
  } else {
    Serial.println(F("Connection failed"));    
    return;
  }
Can't explain why it seems to be working yet, but can you give it a shot to see if that runs stable for you too?

User avatar
tdicola
 
Posts: 1074
Joined: Thu Oct 17, 2013 9:11 pm

Re: Crash in CC3000 on repeated TCP connections

Post by tdicola »

Actually I think I tracked it down, it looks like a recent change dropped the default SPI clock speed to a slower value which causes problems with intermittent SPI communication. Here's the github issue I raised if you're curious: https://github.com/adafruit/Adafruit_CC ... /issues/54

As a fix until the change is in the library, can you change this line:

Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIVIDER); // you can change this clock speed

To be this value (notice the last parameter is changed from SPI_CLOCK_DIVIDER, to SPI_CLOCK_DIV2):

Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIV2); // you can change this clock speed

Let me know how that works--it should hopefully clear up the intermittent lockups.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

Almost two hours and no lockups. Looking good so far! Thanks!

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

Shortly after I wrote the last note above, the checkDHCP started timing out and the cc3000.disconnect()/cc3000.begin() couldn't recover. Only a hardware reset could. This was after several hundred cycles.

I'm going to switch the test code back to connecting the the WLAN only in setup and seeing how things run.

User avatar
jouster
 
Posts: 62
Joined: Fri Dec 23, 2011 12:46 pm

Re: Crash in CC3000 on repeated TCP connections

Post by jouster »

OK, keeping the TCP calls all within a single cc3000.disconnect()/cc3000.begin() works (~2.5 hours, every 30 seconds). You might want to check the DHCP fail on the repeated cc3000.disconnect()/cc3000.begin() loop. Low priority for me, but low power apps might see this problem.

Thanks again!

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Arduino products from Adafruit”