Go Down

Topic: DTMF tone detection in GSM call (Read 5444 times) previous topic - next topic

XseTioN

Hello,

I've search for ways to detect DTMF tones while in active call with the GSM arduino standard library.
I look into google for help and I've found few possible ways:
1. To get a DTMF decoder module to mount on top of the GSM sheild.
2. To buy a GSM shield that already comes with this type of module built in.
3. Using a costume library for GSM. This library I found is made for a costume GSM shield but also can be used for standard one, although it is not working well for mine... (https://github.com/MarcoMartines/GSM-GPRS-GPS-Shield)
4. If the costume library can detect DTMF without any special hardware so there must be a way to do it with the standard library. I guess this method include working with the AT command, but I can't be sure as I did not find the way to do it.

Could any one please help me with the code to detect a DTMF tone while in active call with a standard GSM shield and the standard library for GSM.

Thanks,

v0rtex77

#1
Mar 29, 2020, 08:38 pm Last Edit: Mar 29, 2020, 08:41 pm by v0rtex77
Thought I post this here, it might help someone in the future.
I'm using the gsm shield 2 and with this code i use pin+command (e.g. 1234+1) to "arm" my alarm.
command 2 (12342) disarms and 3 (12343) returns status.

Code: [Select]

#include <GSM.h>
 
// PIN Number
#define PINNUMBER ""
#define ARM_COMMAND 1
#define DISARM_COMMAND 2
#define STATUS_COMMAND 3
 
// initialize the library instance
GSM gsmAccess; // include a 'true' parameter for debug enabled
GSMVoiceCall vcs;
uint8_t keyBufferPnt = 0;
const uint8_t passLen = 4;
const uint8_t keyBufferLen = 5;
const uint8_t passCode[] = {1,2,3,4};
uint8_t keyBuffer[5];
char numtel[20];           // buffer for the incoming call
uint16_t codeTimeOutInMillis = 2000;
unsigned long lastCodeMillis = 0;
bool codeTimeOutStarted = false;
 
bool isArmed = false;
 
 
void setup()
{
  // initialize serial communications
  Serial.begin(9600);
  Serial.println("Receive Voice Call");
 
  // connection state
  boolean notConnected = true;
 
  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes
  while(notConnected)
  {
    if(gsmAccess.begin(PINNUMBER)==GSM_READY)
      notConnected = false;
    else
    {
      Serial.println("Not connected");
      delay(1000);
    }
  }
 
  //Enable dtmf 
  theGSM3ShieldV1ModemCore.genericCommand_rqc("AT+QTONEDET=1", true); // Send command
  bool resp;
  delay(1000); // Wait for response
  theGSM3ShieldV1ModemCore.genericParse_rsp(resp);
  if(resp)Serial.println("DTMF Enabled");else Serial.println("DTMF NOT Enabled"); //Enable tone only
 
  //Select MIC1 channel to send DTMF to remote peer.
  theGSM3ShieldV1ModemCore.genericCommand_rqc("AT+QAUDCH=0", true); // Send command
  delay(1000); // Wait for response
  theGSM3ShieldV1ModemCore.genericParse_rsp(resp);
  if(resp)Serial.println("QAUDCH Enabled");
  else Serial.println("QAUDCH NOT Enabled");
 
  theGSM3ShieldV1ModemCore.genericCommand_rqc("AT+QSFR=7", true); // Send command
  delay(1000); // Wait for response
  theGSM3ShieldV1ModemCore.genericParse_rsp(resp);
  if(resp)Serial.println("QSFR Enabled");
  else Serial.println("QSFR NOT Enabled");
 
  theGSM3ShieldV1ModemCore.genericCommand_rqc("AT+QULDLSPH=0,0", true); // Send command
  delay(1000); // Wait for response
  theGSM3ShieldV1ModemCore.genericParse_rsp(resp);
  if(resp)Serial.println("ToneOnly Enabled");
  else Serial.println("ToneOnly NOT Enabled");
 
  // This makes sure the modem notifies correctly incoming events
  vcs.hangCall();
 
  Serial.println("Waiting Call");
}
 
void loop()
{
  // Check the status of the voice call
  switch (vcs.getvoiceCallStatus())
  {
    case IDLE_CALL: // Nothing is happening
 
      break;
 
    case CALLING: // This should never happen, as we are not placing a call
 
      Serial.println("CALLING");
      break;
 
    case RECEIVINGCALL: // Yes! Someone is calling us
 
      Serial.println("RECEIVING CALL");
 
      // Retrieve the calling number
      vcs.retrieveCallingNumber(numtel, 20);
 
      // Print the calling number
      Serial.print("Number:");
      Serial.println(numtel);
 
      // Answer the call, establish the call
      vcs.answerCall();       
      break;
 
    case TALKING:  // In this case the call would be established
 
      Serial.println("TALKING. Enter line to interrupt.");
      uint8_t charToneSum = 0;
      const char* strToneSearch = "QTONEDET: ";
      uint8_t len = strlen(strToneSearch);
     
      while(Serial.read()!='\n'){
        int toneNum = detectTone(&charToneSum , len, strToneSearch);
        if (isCodeTimedout()) keyTimeout();
        else{
          if(toneNum != -1){
            resetCodeTimeout();
            Serial.print("Tone detected:");Serial.println(toneNum); 
            if(keyBufferPnt < keyBufferLen){     
              keyBuffer[keyBufferPnt] = toneNum;
              keyBufferPnt++;
            }
            if(keyBufferPnt>= keyBufferLen){
              if(checkPass())correctPass();
              else badPass();             
            }             
          }
        }     
      }
                   
      vcs.hangCall();
      Serial.println("HANG. Waiting Call.");     
      break;
  }
  delay(1000);
}
 
int detectTone(uint8_t* sum , uint8_t len, const char* strSearch){
  char c = theGSM3ShieldV1ModemCore.theBuffer().read();
  *sum = (c==strSearch[*sum]) ? *sum+1 : 0;           
  if(*sum == len){
    char cc[2];
    cc[0] = (char)theGSM3ShieldV1ModemCore.theBuffer().read();
    cc[1] = (char)theGSM3ShieldV1ModemCore.theBuffer().read();
    int n;
    n = atoi(cc);
    *sum = 0;
    return n - 48;
  }
  return -1;
}
 
bool isCodeTimedout(){
  if(codeTimeOutStarted){
    if( (unsigned long) millis() - lastCodeMillis > codeTimeOutInMillis){
      codeTimeOutStarted = false;
      return true;
    }
  }
  return false;
}
 
void resetCodeTimeout(){
  lastCodeMillis = millis();
  codeTimeOutStarted = true;
}
 
bool checkPass(){
  codeTimeOutStarted = false;
  for(int i = 0; i < passLen; i++){
    if(passCode[i] != keyBuffer[i]) return false;
  }
  return true;
}
 
void keyTimeout(){
  Serial.println("Key timeout");
  keyBufferPnt = 0;
  const char* str = "AT+QWDTMF=5,0,\"GGG,300,300\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
}
 
void correctPass(){
  Serial.println("Correct pass");
  keyBufferPnt = 0;
  const char* str = "AT+QWDTMF=5,0,\"G,700,700\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
  runCommand(keyBuffer[4]);
}
 
void badPass(){
  Serial.println("Wrong pass");
  keyBufferPnt = 0;
  const char* str = "AT+QWDTMF=5,0,\"GGG,300,300\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true); 
}
 
void runCommand(int commandCode){
  switch (commandCode) {
    case ARM_COMMAND:
      armCom();
      break;
    case DISARM_COMMAND:
      disarmCom();
      break;
    case STATUS_COMMAND:
      statusCom();
      break;
    default:
      Serial.println("Uknown command");
      break;
  }
}
 
void armCom(){
  isArmed = true;
  Serial.println("Armed");
  const char* str = "AT+QWDTMF=5,0,\"1,300,300\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
}
 
void disarmCom(){
  const char* str = "AT+QWDTMF=5,0,\"12,300,300\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
  isArmed = false;
  Serial.println("Disarmed");
}
 
void statusCom(){
   const char* str = "AT+QWDTMF=5,0,\"123,300,300\"";
  theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
  if(isArmed) {
    Serial.println("Is armed");
    const char* str = "AT+QWDTMF=5,0,\"1,300,300\"";
    theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
  }
  else {
    Serial.println("Is disarmed");
    const char* str = "AT+QWDTMF=5,0,\"12,300,300\"";
    theGSM3ShieldV1ModemCore.genericCommand_rqc(str, true);
  }
}

Go Up