Arduino stops sending info to server after a while

Hi,

I have a problem with my Arduino uno and my 3G + GPS shield.
After I launch the arduino, the program sometimes just suddenly stops,
or after sending the data to the server a few times, it stops.

The aim of my project is to send info to a server (here Cosm) on a
regular basis and to also send SMSs.

I'm using two libraries, one to send the SMSs and one to send data to
the server. (code below)

I put in some debug prints so I could see what was going on.
sometimes it would stop here, at the beginning of the connection: (once every two connections)
AT+CGSOCKCONT=1,"IP","gprs.swisscom.ch"

Then during the process of sending data at regular intervals, the arduino stops after a random
number of times. it stops at this:
AT+TCPWRITE=287

For these problems, I'm thinking the Arduino simply doesn't respond, but I don't know why...

here is the code for the libraries:
TCP_3G.cpp

#include "Arduino.h"
#include "TCP_3G.h"

TCP_3G::TCP_3G(){
	
}

void TCP_3G::begin(int led, int onModulePin){
	_led = led;
	_onModulePin = onModulePin;
	
	x = 0;
	
    delay(2000);
    pinMode(_led, OUTPUT);
    pinMode(_onModulePin, OUTPUT);
	
	char _server[] = "api.cosm.com";
	char _port[] = "8081";
	
		// Set PDP parameters
    Serial.println("AT+CGSOCKCONT=1,\"IP\",\"gprs.swisscom.ch\"");
	//
	//Blocks here every other time
	//
	Serial.flush();
	Serial.print(Serial.read());
    while(Serial.available()==0 || Serial.read()!='K');
    
    // Set connection parameters
    Serial.print("AT+NETOPEN=\"TCP\","); Serial.println(_port);
    Serial.flush();
    x=0;
    do {
        while(Serial.available()==0);
        data[x]=Serial.read();
		//if((data[x]!='\n') && (data[x]!='\r')) Serial.print(char(data[x]));
        x++;  
    } while(!(data[x-1]=='d'&&data[x-2]=='e'));       //waits for response "Network opened"

    while(Serial.available()==0 || Serial.read()!='K');

	
    // Connect to server
    Serial.print("AT+TCPCONNECT=\""); Serial.print(_server); Serial.print("\","); Serial.println(_port);
    Serial.flush();
    while(Serial.available()==0 || Serial.read()!='K');
}

void TCP_3G::switchModule(){
    digitalWrite(_onModulePin,HIGH);
    digitalWrite(_onModulePin,LOW);
    delay(2000);
}

void TCP_3G::sendInfo(int bottleN, float waterHeight, float derivative){
	
	char COSM_API_KEY[] = "KrGtesAnlf8No0_C9_pLrVGt8biSAKhbViRKFks2eXJ1ez0g";
	char COSM_FEED[] = "*****";
	
	//Doing this for the size
	char sbottle[6];
    itoa(bottleN,sbottle, 10);
    char scm[6];
    sprintf(scm,"%.0f",waterHeight);
    char sderiv[6];
    sprintf(sderiv,"%.0f",derivative);
	
    char feedStr[] = "{\"method\":\"put\",\"resource\":\"/feeds/12345\",\"params\":{},\"headers\":{\"X-PachubeApiKey\":\"KrGtesAnlf8No0_C9_pLrVGt8biSAKhbViRKFks2eXJ1ez0g\"},\"body\":{\"datastreams\":[{\"id\":\"0\",\"current_value\":\"\"},{\"id\":\"1\",\"current_value\":\"\"},{\"id\":\"2\",\"current_value\":\"\"}]},\"token\":\"0x12345\"}";

    Serial.print("AT+TCPWRITE="); Serial.println(sizeof(sbottle) + sizeof(scm) + sizeof(sderiv) + sizeof(feedStr));//
    //
	//Blocks here after a while
	//
	Serial.flush();
	Serial.print(Serial.read());
    while(Serial.available()==0 || Serial.read()!='>');
	
    Serial.print("{\"method\":\"put\",\"resource\":\"/feeds/");
    Serial.print(COSM_FEED); 
    Serial.print("\",\"params\":{},\"headers\":{\"X-PachubeApiKey\":\"");
    Serial.print(COSM_API_KEY);
    Serial.print("\"},\"body\":{\"datastreams\":[{\"id\":\"0\",\"current_value\":\"");
    Serial.print(bottleN);  
    Serial.print("\"},{\"id\":\"1\",\"current_value\":\"");
    Serial.print(waterHeight);
    Serial.print("\"},{\"id\":\"2\",\"current_value\":\"");
    Serial.print(derivative);
    Serial.println("\"}]},\"token\":\"0x12345\"}");
	
    Serial.println("AT+NETCLOSE");
    Serial.flush();
    while(Serial.available()==0 || Serial.read()!='K');

}

SMS_3G.cpp

#include "Arduino.h"
#include "SMS_3G.h"

SMS_3G::SMS_3G()
{
   
}

void SMS_3G::begin(int led, int onModulePin)
{
	_onModulePin = onModulePin;
	_led = led;
   //Serial.begin(brate);                // UART baud rate
   delay(2000); 

   pinMode(led, OUTPUT);
   pinMode(onModulePin, OUTPUT);
   switchModule();                    // switches the module ON
	
   for (int i=0;i<5;i++){
       delay(5000);
   }

   Serial.println("AT+CMGF=1");         // sets the SMS mode to text
   delay(100);
}

void SMS_3G::switchModule(){
    digitalWrite(_onModulePin,HIGH);
    delay(2000);
    digitalWrite(_onModulePin,LOW);
}

void SMS_3G::sendSMS(char phone_number[], char msg[])
{

 delay(1500);
 Serial.print("AT+CMGS=\"");		// send the SMS number
 Serial.print(phone_number);
 Serial.println("\""); 
 delay(1500);  

 Serial.print(msg);   // the SMS body
 
 delay(500);
 Serial.write(0x1A);       //sends ++
 Serial.write(0x0D);
 Serial.write(0x0A);

 delay(5000);
}

Thanks a lot for your help!

and here is the ino file too:

#include <SMS_3G.h> //For sms, it's actually with cosm that it will be sent!
#include <TCP_3G.h>

SMS_3G sms;  //As there are no arguments, drop the brackets
TCP_3G info;
char phone_number[]="*********"; //is the number to which the SMS is going to bo sent
int once = 0; //used to send the only once an sms telling the user 22 bottles are filled

// Pin number of the sensor's output:
const int pingPin = 7;
const int iscoPin = 9;

// Time
unsigned int dtLoop = 10000;            // [ms]
double dtCstSampling = 60.0;           // [s]
double nextSampleTime = 0;             // [s]

// Sensor (height in [cm])
const int dhStormThr = 2;              // [cm/s] for Chambrone a good threasold would be 5-8 cm/jour
const double dhRecPercThr = 0.1;       // [%] recesion detcted when height 10% lower than peak height
float hBase = 0.0f;                    // The mean distance between the senseor and the water.
float cm = 0.0f, cmPeak = -10000.0f;   // The height of the water relative to 'hBase': cm = sensor value - hBase.

// Lowpass filter of the sensor data: alpha with dT_ech and dT_filtre
unsigned int dtFilter = 5000;          // [ms]
const float alpha = (dtLoop/1000.0f) / ((dtFilter/1000.0f)/(2.0f*3.14159f)+(dtLoop/1000.0f));

// Model parameters
double c = 1.0/5.0;                    // in [1/seconds]

// Sampler
unsigned const char nbBottles = 24;    // Total number of bottles in the sampler.
unsigned const char stockBottles = 2;  // Bottles that should remain after the flood.
unsigned char curBottle = 1;           // The current bottle waiting to be filled.

// State of the sensor, because we need to calibrate it (to initialize the hBase variable).
typedef enum {
  CALIGBRATING, SENSOR_READY} 
SensorState;
SensorState sensorState;

// State of river
typedef enum {
  WAIT_STORM, WAIT_RECESSION, RECESSION, SAMPLER_FULL} 
StormState;
StormState stormState;

// State of sampling
typedef enum {
  NOT_SAMPLING, CST_SAMPLING, PROG_SAMPLING} 
SamplingState;
SamplingState samplingState;

void setup()
{
  // initialize serial communication.
  Serial.begin(115200);

  // initialize ISCO command pin
  pinMode(iscoPin, OUTPUT);
  digitalWrite(iscoPin, LOW);

  // initialize the SMS and the TCP connection
  // Don't call switchmodule twice!
  sms.begin(13, 2);
  info.begin(13 ,2);

  // initialize states.
  sensorState = CALIGBRATING;
  stormState = WAIT_STORM;
  samplingState = NOT_SAMPLING;
  //Serial.println("Calbrating");
}

void loop()
{
  long duration = getDistancePulseDuration();             // get the datat from the Ultrasound sensor.
  float sensorCM = microsecondsToCentimeters(duration);   // convert the time into a distance
  if(sensorState == CALIGBRATING) { // Calibrate the sensor -> the base height is the current height.
    calibrateSensor(sensorCM);
    return;
  }

  float cmCur, cmDerivative, dhRecThr;
  cmCur = hBase - sensorCM;
  cmDerivative = cm; // store prev_val here to save the number of variables
  cm = alpha*cmCur + (1.0f-alpha)*cm;
  cmDerivative = (cm - cmDerivative) / float(dtLoop / 1000.f);

  // Storm state management
  // (WAIT_STORM -> WAIT_RECESSION (10% of height peak) -> RECESSION -> WAIT_STORM).
  switch(stormState) {

  case WAIT_STORM: // Waiting for the flood.
    if(cmDerivative > dhStormThr) { // The flood is detected when slope of height curve overcome dhStormThr.
      stormState = WAIT_RECESSION;
      samplingState = CST_SAMPLING; 
    }
    break;

  case WAIT_RECESSION: // Waiting that the height of water decrease.
    cmPeak = cm > cmPeak ? cm : cmPeak;
    dhRecThr = cmPeak * dhRecPercThr;
    if(cmPeak - cm > dhRecThr) { // Check if height of water is under dhRecPercThr [%] of the highest water height value.
      cmPeak = -10000.0f;
      stormState = RECESSION;
      samplingState = PROG_SAMPLING;
    }
    break;

  case RECESSION: // In recession, waiting that all the bottles are empty.
    if(curBottle > nbBottles-stockBottles) { // We preserve some bottles in case...
      if(once == 0){
		//-----------------------------------------------------
        // send SMS to operator
        //-----------------------------------------------------
        sms.sendSMS(phone_number, "finished sampling, two bottles left in case");
        once++;
      }
      stormState = WAIT_STORM;
      samplingState = NOT_SAMPLING;
    }
    else if(cmDerivative > dhStormThr) { // A flood is detected during the recetion -> go back to constant sampling and wait for recession.
      stormState = WAIT_RECESSION;
      samplingState = CST_SAMPLING; 
    }
    break; 
  }

  // Sampling management. 
  if(samplingState != NOT_SAMPLING) { // We are sampling.
    double remainingTime = nextSampleTime - double(millis())/1000.0;
    if(remainingTime < 0.0) { // next sample
      
      /*if(curBottle == 1) {
        // SMS sent to say the sampling has started 
        //sms.sendSMS(phone_number, "Sampling started");
        //Serial.println("first SMS sent.");
      }*/
      curBottle++;
      if(curBottle >= nbBottles) { // sampler full -> send SMS
        //-----------------------------------------------------
        // send SMS to operator
        //-----------------------------------------------------
        samplingState = NOT_SAMPLING;
        stormState = SAMPLER_FULL;
        //sms.sendSMS(phone_number, "Sampler full, the prediction might have been wrong, or the sampling's totally finished");
        //Serial.println("SMS sent.");
      }
      else {
        //-----------------------------------------------------
        // send next sample cammand to ISCO Sampler
        digitalWrite(iscoPin, HIGH);
        delay(10);
        digitalWrite(iscoPin, LOW);
        //-----------------------------------------------------
        if(samplingState == CST_SAMPLING) {
          nextSampleTime = computeNextSampleCstTime(dtCstSampling);
        }
        else {
          nextSampleTime = computeNextSampleProgTime(curBottle, nbBottles, c);
        }
      }
    }
  }
  info.sendInfo(curBottle, cm, cmDerivative); //We send info every time

    delay(dtLoop);
}



void calibrateSensor(float height) {
  int dt = 100;
  const float a = (dt/1000.0f) / ((2000.0f/1000.0f)/(2.0f*3.14159f)+(dt/1000.0f));
  hBase = a*height + (1.0f-a)*hBase;
  delay(dt);
  if(millis() > 5000) // we calibrate sensor during 2s.
    sensorState = SENSOR_READY;
}


double computeNextSampleCstTime(double dtCstSampling) {
  return dtCstSampling + double(millis())/1000.0;
}


double computeNextSampleProgTime(unsigned char a, unsigned char RS, float c) {
  // The time between samples is computed such that each sampling interval correspond
  // to an equal volume of flow under the predicated hydrograph recession curve.
  double t_sample = (exp( 2.996*double(a) / double(RS)) - 1.0f) / double(c);
  t_sample += double(millis())/1000.0;
  return t_sample;
}


long getDistancePulseDuration()
{
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH pulse whose duration is the
  // time (in microseconds) from the sending of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  return pulseIn(pingPin, HIGH);
}


float microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 343.2 m/s or 29.1375 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the object we take half of the distance travelled.
  return microseconds / 2.0f / 29.1375f;
}

Chinese government hackers are interfering with your device.

You seem to have very many strings, likely to fill the Uno's RAM which is only 2K. Unfortunately, each debug statement you add can only worsen the situation. One solution is to use the F() macro for messages that never change. For example, instead of

Serial.println("AT+NETCLOSE");

you may write

Serial.println(F("AT+NETCLOSE"));

The F() macro stores the string in program memory, not ram. You cannot use it for string that change during the execution of the sketch.

I cannot say whether this will solve your problems, but there are other potential issues. If you get an error on AT+CGSOCKCONT=1,"IP","gprs.swisscom.ch", it's a connection error with your APN and you shouldn't ignore it. It may happen sometimes and your program should be able to manage it (e.g., by retrying after a certain time). I also notice that you never check for the value of return messages from the modem: you assume they are OK (check for Serial.read()!='K'), but what if you got an ERROR response?

Are you sure that the arduino is the problem ?

If it cannot communicate to the 3G device, perhaps the 3G device is "hanging up" ( in one or other meaning of the expression ) ?.

Thanks for your responses,

I put in the F() macro, and it already works much better!
I already thought of Strings filling the memory, that's why I put in char arrays
instead of Strings.

I've checked for errors, but I can't seem to find a good way to debug...
it just seems to get worse! :~

michinyon: I haven't thought of that, but yeah, the 3G device could be hanging up!
well, the led on the 3G module isn't flashing, it just goes off.
Would you have any ideas why this might be happening?

when I insert code to see if it receives ERROR, the program blocks at various parts of the code.
When I receive an error, what could it mean?
I get errors for these:
AT+CGSOCKCONT=1,"IP","gprs.swisscom.ch"

AT+NETOPEN="TCP",8081

and AT+TCPCONNECT="api.cosm.com",8081

Then I have to reset the arduino

Would someone have any idea why I get errors?
Thanks

There will better sources, but you can start from this: http://www.reyax.com/Module/3G/SIM5320/SIM5320_ATC_EN_V1.24.pdf.

If CGSOCKCONT fails it means you cannot access the network. It's the message you send to activate the wireless packet (IP) network through an APN. It is usually due to transient conditions such as poor signal quality or too much traffic. It may also be due to authentication issues with your provider (swisscom.ch), insufficient credit and so on. If in doubt, check with your mobile operator whether your SIM is authorized to use that APN.

Once CGSOCKCONT fails you have no wireless network connection (SMS may work), so you'll not be able to open a TCP connection (NETOPEN, TCPCONNECT) to the cosm server. The connection to cosm may fail even if CGSOCKCONT was successful, again because of transient errors such as too much traffic on the network (same as when a server does not respond to a browser request, but when if you refresh the page the error disappears).

This is why it'so important to check for the return code from the modem, which is tricky because the modem will send you various messages before the OK or ERROR message (followed by one or two further characters - carriage return and/or line feed). If you keep trying sending message as if everything was OK, then you may send something that the modem does not interpret correctly. In these cases the modem just echoes back the messages you send, filling the communication buffer, and may also stop accepting new messages unless you reset it (the modem, e.g. by sending a +++ sequence). This is one of the possible causes of problems you are experiencing.

Thanks a lot for the link and the response!

It's probably one of the problems I'm having,
before as I was checking the return code from the modem I directly tried
sending the command again, repeatidly. Thanks for the info!