Waiting for AT COMMAND correct response

Hi

I have a function, which i use to run all my AT COMMANDS.
But it currently just waits for a response, and not for the modem to connect, get ip or some other function that might require time.

I need the function to wait for the right response (somehow?).
So instead of just shooting ERROR when I run a command, I want it to check the response, and if its not "OK" or "CONNECTED" or whatever the command is supposed to return, I want it to wait for the right response.
Ive tried jugling around with a function for it, but I cant get it working.

The function I use currently, looks like this:

void ModemCommand(String command) 
{ 
  //Send command to modem
  mySerial.println(command);
  Serial.println(command);
  delay(100);
  while (!mySerial.available()) 
  { 
    Serial.println(F("No response yet"));
    delay(1000);
  }
  while (mySerial.available())
  {
    Serial.write(mySerial.read());
  }
  Serial.println("");
  delay(10);
}

But that will just return ERROR instead of waiting for the right response if I dont use any delays.
I currently have guesses as to how much delay is needed, but I'd like to make it more effecient and save battery :slight_smile:

Parts of what I currently run:

  ModemCommand(F("ATE0"));                                                       //Turn on echo
  ModemCommand(F("AT+CFUN=1"));                                                  //Turn modem functions on 
  waitSec(8,F("turning on Modem functions"));
  ModemCommand(F("AT+CGREG?"));                                                  //GSM attached?
  ModemCommand(F("AT+CSQ"));                                                     //Signal Quality
  ModemCommand(F("AT+CSTT=\"internet\""));                                       //Set APN
  ModemCommand(F("AT+CIICR"));                                                   //Connect to APN GPRS
  waitSec(8,F("connecting to APN GPRS"));
  ModemCommand(F("AT+CIFSR"));                                                   //Get IP

The waitSec is a function that calls a delay*1000 on the number with a description after. Its merely for debugging.

Is there a way to wait for the command to return OK?

Is there a way to wait for the command to return OK?

No. You could wait for a period of time OR for the command to return SOME response.

It does not make sense to make the function wait for "OK", when the command fails.

Hi

The AT command reference for my SIM800 module indicates that different commands have different maximum response times. So I initialise a timer with different wait times according to the particular AT command.

Despite the maximum response timer my SIM800 module serial read function will return early if a response has been received - regardless of whether it is the expected result or not.

Cheers

Catweazle NZ

Hi!
I'm working with the esp8266 (wifi module) and I have to wait for OK ir ERROR responses after AT commands, otherwise I need a long delay to be sure the module isn't busy in the next command.

So I wrote a function with this usage:

sendATcommand ("AT");
wait("OK,ERROR",10000);

where the function Will Block the code until it receives OK or ERROR or it timeouts by 10sec.

This function Will return -1 for timeout or an number corresponding to the index of match string (in this example 0 for OK or 1 for ERROR).

Code:

int16_t wait(char* Values, uint16_t timeout) {

  uint16_t Length = strlen(Values);

  char InputBuffer[Length + 1];
  strcpy(InputBuffer, Values);
  char CompareBuffer[Length + 1];
  memset(CompareBuffer,0,sizeof(CompareBuffer));

  uint16_t Quantity = 1;
  
  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ',')
      Quantity++;
  }

  char* InputTokens[Quantity];
  memset(InputTokens, 0, sizeof(InputTokens));
  char* CompareTokens[Quantity];
  memset(CompareTokens, 0, sizeof(CompareTokens));

  InputTokens[0] = InputBuffer;
  CompareTokens[0] = CompareBuffer;

  uint16_t TokenPosition = 1;
  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ',') {
      InputBuffer[n] = 0;
      InputTokens[TokenPosition] = &InputBuffer[n + 1];
      CompareTokens[TokenPosition] = &CompareBuffer[n + 1];
      TokenPosition++;
    }
  }

  uint64_t timer = millis();
  char c;

  while (millis() - timer < timeout) {
    while (mySerial.available()) {
      c = mySerial.read();
      Serial.print(c);

      for (int16_t n = 0; n < Quantity; n++) {
        Length = strlen(CompareTokens[n]);
        if (c == InputTokens[n][Length])
          CompareTokens[n][Length] = c;
        else
          memset(CompareTokens[n], 0, Length);

        if (!strcmp(InputTokens[n],CompareTokens[n]))
          return n;
      }
    }
  }
  return -1;
}

Note that the function May not be perfect as I'm thinking in ways to improve it. (Enable progmen strings,etc).

giova014:
Hi!
I'm working with the esp8266 (wifi module) and I have to wait for OK ir ERROR responses after AT commands, otherwise I need a long delay to be sure the module isn't busy in the next command.

So I wrote a function with this usage:

sendATcommand ("AT");

wait("OK,ERROR",10000);




where the function Will Block the code until it receives OK or ERROR or it timeouts by 10sec.

This function Will return -1 for timeout or an number corresponding to the index of match string (in this example 0 for OK or 1 for ERROR).

Code:


int16_t wait(char* Values, uint16_t timeout) {

uint16_t Length = strlen(Values);

char InputBuffer[Length + 1];
  strcpy(InputBuffer, Values);
  char CompareBuffer[Length + 1];
  memset(CompareBuffer,0,sizeof(CompareBuffer));

uint16_t Quantity = 1;
 
  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ',')
      Quantity++;
  }

char* InputTokens[Quantity];
  memset(InputTokens, 0, sizeof(InputTokens));
  char* CompareTokens[Quantity];
  memset(CompareTokens, 0, sizeof(CompareTokens));

InputTokens[0] = InputBuffer;
  CompareTokens[0] = CompareBuffer;

uint16_t TokenPosition = 1;
  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ',') {
      InputBuffer[n] = 0;
      InputTokens[TokenPosition] = &InputBuffer[n + 1];
      CompareTokens[TokenPosition] = &CompareBuffer[n + 1];
      TokenPosition++;
    }
  }

uint64_t timer = millis();
  char c;

while (millis() - timer < timeout) {
    while (mySerial.available()) {
      c = mySerial.read();
      Serial.print(c);

for (int16_t n = 0; n < Quantity; n++) {
        Length = strlen(CompareTokens[n]);
        if (c == InputTokens[n][Length])
          CompareTokens[n][Length] = c;
        else
          memset(CompareTokens[n], 0, Length);

if (!strcmp(InputTokens[n],CompareTokens[n]))
          return n;
      }
    }
  }
  return -1;
}




Note that the function May not be perfect as I'm thinking in ways to improve it. (Enable progmen strings,etc).

Could you post your code for "sendATcommand" aswell? Just so I know how you handle that aswell :slight_smile:

Hi!

The sendATcommand() is nothing special, I'm using just a print:

mySerial.print("AT+CIFSR\r\n"); //get local ip and MAC
wait("ERROR\r\n,OK\r\n", 5000);

I used sendATcommand() because some AT commands return more than ERROR or OK, they can return (in the example above) the local IP and MAC, so the function would have to handle this input, and it would be:

bool getIPandMAC(char* APIP, char* APMAC, char* STAIP, char* STAMAC) {

  esp8266.print("AT+CIFSR\r\n"); //get local ip and MAC

  if (wait("ERROR\r\n;APIP,", 5000) > 0 ) {
    copyValueToBuffer(APIP);

    if (wait("ERROR\r\n;APMAC,", 5000) > 0) {
      copyValueToBuffer(APMAC);

      if (wait("ERROR\r\n;STAIP,", 5000) > 0) {
        copyValueToBuffer(STAIP);

        if (wait("ERROR\r\n;STAMAC,", 5000) > 0) {
          copyValueToBuffer(STAMAC);

          if(wait("ERROR\r\n;OK\r\n", 5000) > 0)
            return true;
        }
      }
    }
  }

  return false;
}

In the example above, the AT command returns four values, so I will wait for the keywords and after them, copy the a buffer to handle the values. As you can see, I needed to check for ',' and it was my argument delimiter in the wait() function, so I changed it to ';' .

Here is the wait() (again):

int16_t wait(char* Values, uint16_t TimeOut) {

  if(!Values)
    return -1;
  
  uint16_t Length = strlen(Values);

  char InputBuffer[Length + 1];
  strcpy(InputBuffer, Values);
  char CompareBuffer[Length + 1];
  memset(CompareBuffer, 0, sizeof(CompareBuffer));

  uint16_t TokenQuantity = 1;

  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ';')
      TokenQuantity++;
  }

  char* InputTokens[TokenQuantity];
  memset(InputTokens, 0, sizeof(InputTokens));
  char* CompareTokens[TokenQuantity];
  memset(CompareTokens, 0, sizeof(CompareTokens));

  InputTokens[0] = InputBuffer;
  CompareTokens[0] = CompareBuffer;

  uint16_t TokenPosition = 1;
  for (int16_t n = 0; n < Length; n++) {
    if (InputBuffer[n] == ',') {
      InputBuffer[n] = 0;
      InputTokens[TokenPosition] = &InputBuffer[n + 1];
      CompareTokens[TokenPosition] = &CompareBuffer[n + 1];
      TokenPosition++;
    }
  }

  uint64_t timer = millis();
  char c;

  while (millis() - timer < TimeOut) {
    while (esp8266.available()) {
      c = esp8266.read();
      Serial.print(c);

      for (int16_t n = 0; n < TokenQuantity; n++) {
        Length = strlen(CompareTokens[n]);
        if (c == InputTokens[n][Length])
          CompareTokens[n][Length] = c;
        else if (Length > 0)
          memset(CompareTokens[n], 0, Length);

        if (!strcmp(InputTokens[n], CompareTokens[n]))
          return n;
      }
    }
  }
  return -1;
}

Thank you for a very useful wait().