Software flow control

Hi all, I’m trying to connect SIM900 module to the my Arduino Uno. All is OK, but I’m strongly need to use software or hardware flow control. In SIM900 manual I read that it supporting XON/XOFF symbols, but I don’t know how I can to use them.
For example, I have one loop(), which contain all operations including serial port reading. But execution of reading segment delayed by another segments and often I’m losing data which was sent by SIM900. And I want to allow incoming data from module only on activity of reading segment in loop(). What I need to do?
My sketch with trys to get software flow control worked, if somebody needs:

#include <SoftwareSerial.h>

#define txPin 8
#define rxPin 7

SoftwareSerial phoneSerial(rxPin, txPin);

#define pirPin 4
#define relayPin 12

String currStr = "";

unsigned long updateTime = 0;
unsigned long timeOfNextCall = 0;

unsigned char state = 0; //0 - inactive
                                                 //1 - active
						 //2 - alarm

unsigned char ringFlag = 0;
unsigned char smsFlag = 0;
unsigned char flagCalled = 0;

unsigned char needActive = 0;
unsigned char needInactive = 0;

void relayOn(void) {
	digitalWrite(relayPin, LOW);
	Serial.println("Relay turned on.");
}

void relayOff(void) {
	digitalWrite(relayPin, HIGH);
	Serial.println("Relay turned off.");
}

void callOwner(void) {
	phoneSerial.print(char(17));
	phoneSerial.println("ATD+7XXXXXXXXXX;");
	phoneSerial.print(char(19));
}

void sendSMS(String string) {
	/*
	phoneSerial.print(char(17));
	phoneSerial.print("AT+CMGF=1\r"); //text mode
    delay(100);
    phoneSerial.println("AT + CMGS = \"+7XXXXXXXXXX\"");
    delay(100);
    phoneSerial.println(string);
    delay(100);
    phoneSerial.println((char)26); //Ctrl+Z 
	phoneSerial.print(char(19));*/
	Serial.print("Outgoing SMS: ");
	Serial.println(string);
}

void touch() {
    if (millis() >= updateTime) {
		phoneSerial.print(char(17)); //XON
        phoneSerial.println("AT");
		if (updateTime >= 4294965000) { //near the end of unsigned long
			updateTime = 4294967295;
		} else {
			updateTime += 5000;
		}
		phoneSerial.print(char(19)); //XOFF
    }  
}

void setup(void) {                
	pinMode(pirPin, INPUT);
	pinMode(relayPin, OUTPUT);
	relayOff();
	delay(2000); //time to init phone
	Serial.begin(4800);
	phoneSerial.begin(4800);
	phoneSerial.print("AT+CMGF=1\r\n"); //text format instead PDU
    delay(300);
    phoneSerial.print("AT+IFC=1, 1\r\n"); //this and all next for syncronized input of incoming SMS
    delay(300);
    phoneSerial.print("AT+CPBS=\"SM\"\r\n");
    delay(300);
    phoneSerial.print("AT+CNMI=1,2,2,1,0\r\n");
    delay(500);
	phoneSerial.print("AT+IPR=1,1\r\n"); //enabling software flow control
	delay(300);
	phoneSerial.print(char(19)); //XOFF
}

void loop(void) {
	switch (state) {
		case 0: { //inactive
			if (needActive == 1) {
				state = 1;
				needActive = 0;
				Serial.println("Changing state to active...");
				delay(60000);
				Serial.println("State is active from inactive.");
				sendSMS("State is active.");
			}
			break;
		}
		case 1: { //active
			if (digitalRead(pirPin) == HIGH) {
				state = 2;
				Serial.println("State is alarm from active.");
			}
			if (needInactive == 1) {
				state = 0;
				needInactive = 0;
				Serial.println("State is inactive from active.");
				sendSMS("State is inactive.");
			}
			break;
		}
		case 2: { //alarm
			if (flagCalled == 1 && timeOfNextCall <= millis()) {
				flagCalled = 0;
			}
			if (flagCalled == 0) {
				callOwner();
				if (timeOfNextCall >= 4294800000) {
					timeOfNextCall = 4294967295;
				} else {
					timeOfNextCall += 300000;
				} 
				flagCalled = 1;
			}
			if (needInactive == 1) {
				state = 0;
				needInactive = 0;
				flagCalled = 0;
				Serial.println("State is inactive from alarm.");
				sendSMS("State is inactive, alarm stopped.");
			}
			break;
		}
	}
	
	if (!phoneSerial.available()) return;
	phoneSerial.print(char(17));
	char currSymb = phoneSerial.read();
	if ('\r' == currSymb) {
		if (smsFlag) {
			Serial.println(currStr);
			if (!currStr.compareTo("1")) { //set active state
				needActive = 1;
			}
			else if (!currStr.compareTo("2")) { //set inactive state
				needInactive = 1;
			}
			else if (!currStr.compareTo("3")) { //set relay on
				relayOn();
				sendSMS("Relay open.");
			}
			else if (!currStr.compareTo("4")) { //set relay off
				relayOff();
				sendSMS("Relay close.");
			}
			smsFlag = 0;
		}
		else {
			if (!currStr.compareTo("RING")) { //incoming call
				ringFlag = 1;
				phoneSerial.println("AT+CHUP"); //hup call
				Serial.println("Recieved a RING signal.");
			}
			else if (currStr.startsWith("+CMT:")) { //incoming SMS
				smsFlag = 1;
				phoneSerial.println("AT+CMGD=1,4"); //deleting it from SIM
				Serial.print("Recieved a SMS: ");
			}
		}
		currStr = "";
	} else if (currSymb != '\n') currStr += String(currSymb);
	
	touch();
	phoneSerial.print(char(19));
}

What I need to do?

You need to understand how asynchronous communications work, and how to live with the asynchronous nature of the communication.

You make a request. You push that request type in a queue.

Replies are received. When the end of a reply arrives, you know that it does with the first request in the queue.

If the next request depends on the response to the previous one, you need to wait until the queue is empty to make another request.

PaulS:
You make a request.

But I don’t make a request, SIM900 sends RING or +CMT message to Arduino without my request (if only I don’t send a SMS from Arduino to somebody with request to call me (: ). I don’t know where I can get interrupt for reading begin.

But I don't make a request, SIM900 sends RING or +CMT message to Arduino without my request

This can only happen when the queue is empty. So, the information that the Arduino gets has the "request" type in it. I don't see the problem.

You need to read and store the data coming in as fast as possible. That absolutely precludes using the String class, which gets slower and slower the larger the amount of data it is manipulating gets.

kostett:
Hi all, I’m trying to connect SIM900 module to the my Arduino Uno. All is OK, but I’m strongly need to use software or hardware flow control. In SIM900 manual I read that it supporting XON/XOFF symbols, but I don’t know how I can to use them.
For example, I have one loop(), which contain all operations including serial port reading. But execution of reading segment delayed by another segments and often I’m losing data which was sent by SIM900. And I want to allow incoming data from module only on activity of reading segment in loop(). What I need to do?
My sketch with trys to get software flow control worked, if somebody needs:

to use software flow control (xon/xoff) you need to monitor how full the Serial receive buffer is, and if the buffer has less than ‘x’ characters left, send the XOFF character to the Transmitter. when the buffer falls below ‘y’ characters send XON

static bool Xoffed = false;

void check_buffer(){
if(!Xoffed)&&(Serial.available()>48){ //buffer is 3/4 full better shut it down!
  Serial.write(0x13); // xoff
  Xoffed = true;
  }
else if(Xoffed&&(Serial.available()<32)){ // more room in buffer Yea! turn it on!
  Serial.write(0x11); // Xon
  Xoffed = false;
  }
}

Now you need to place a call to this function wherever you are ignoring the Serial Buffer.

If you are sending data out on the same serial link, the Xoff/Xon character don’t jump to front of the buffer, they are send out in the order they are received, if the output buffer has 50 byte in it and you send the XOff, it is not send out for at least 50 character transmit periods, meanwhile the receive buffer might have overflowed 34+ characters, the Xoff command has no fixed guaranteed response time, the transmitter might not acknowledge the Xoff for 5 or 10 characters. So in this case, you could loose 44+ characters before the transmitter shuts off.

So either process the Serial.read() really often and/or set the Xon/Xoff thresholds low.

Chuck.

Giving up. Installed a GSMSHIELD library. Works well.