Package org.smslib.modem.athandler

Source Code of org.smslib.modem.athandler.ATHandler

// SMSLib for Java v3
// A Java API library for sending and receiving SMS via a GSM modem
// or other supported gateways.
// Web Site: http://www.smslib.org
//
// Copyright (C) 2002-2012, Thanasis Delenikas, Athens/GREECE.
// SMSLib is distributed under the terms of the Apache License version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.smslib.modem.athandler;

import java.io.IOException;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.smslib.GatewayException;
import org.smslib.Service;
import org.smslib.TimeoutException;
import org.smslib.AGateway.AsyncEvents;
import org.smslib.AGateway.Protocols;
import org.smslib.InboundMessage.MessageClasses;
import org.smslib.helper.Logger;
import org.smslib.modem.AModemDriver;
import org.smslib.modem.CNMIDetector;
import org.smslib.modem.ModemGateway;

/**
* Generic modem AT handler.
*/
public class ATHandler extends AATHandler
{
  protected AModemDriver modemDriver;

  protected CNMIDetector cnmiDetector;

  /**
   * Cell Broadcast Data Coding Scheme (CBS DCS) value of 15 indicates GSM
   * default 7-bit alphabet (high nybble 0000), language unspecified (low
   * nybble 1111)
   **/
  protected static final int DEFAULT_USSD_DCS_NUM = 0x0f;

  public AModemDriver getModemDriver()
  {
    return this.modemDriver;
  }

  public ATHandler(ModemGateway myGateway)
  {
    super(myGateway);
    this.modemDriver = myGateway.getModemDriver();
    this.cnmiDetector = null;
    this.terminators = new String[14];
    this.terminators[0] = "OK\\s";
    this.terminators[1] = "\\s*[\\p{ASCII}]*\\s+OK\\s";
    this.terminators[2] = "(ERROR|NO CARRIER|NO DIALTONE)\\s";
    this.terminators[3] = "ERROR:\\s*\\d+\\s";
    this.terminators[4] = "\\+CM[ES]\\s+ERROR:\\s*\\d+\\s";
    this.terminators[5] = "\\+CPIN:\\s*READY\\s";
    this.terminators[6] = "\\+CPIN:\\s*SIM\\s*BUSY\\s";
    this.terminators[7] = "\\+CPIN:\\s*SIM\\s*PIN\\s";
    this.terminators[8] = "\\+CPIN:\\s*SIM\\s*PIN2\\s";
    this.terminators[9] = "\\+CUSD:\\s.*\\s";
    this.terminators[10] = "\\+CMTI:\\s*\\p{Punct}[\\p{ASCII}]+\\p{Punct}\\p{Punct}\\s*\\d+\\s";
    this.terminators[11] = "\\+CDSI:\\s*\\p{Punct}[\\p{ASCII}]+\\p{Punct}\\p{Punct}\\s*\\d+\\s";
    this.terminators[12] = "RING\\s";
    this.terminators[13] = "\\+CLIP:\\s*\\p{Punct}[\\p{ASCII}]*\\p{Punct}\\p{Punct}\\s*\\d+[\\p{ASCII}]*\\s";
    this.unsolicitedResponses = new String[5];
    this.unsolicitedResponses[0] = "+CMTI";
    this.unsolicitedResponses[1] = "+CDSI";
    this.unsolicitedResponses[2] = "RING";
    this.unsolicitedResponses[3] = "+CLIP";
    this.unsolicitedResponses[4] = "+CUSD";
  }

  @Override
  public void sync() throws IOException, InterruptedException
  {
    getModemDriver().write("ATZ\r");
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
  }

  @Override
  public void reset() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("\u001b");
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
    getModemDriver().write("+++");
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
    getModemDriver().write("ATZ\r");
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
    getModemDriver().clearBuffer();
  }

  @Override
  public void echoOff() throws IOException, InterruptedException
  {
    getModemDriver().write("ATE0\r");
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
    getModemDriver().clearBuffer();
  }

  @Override
  public void init() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CLIP=1\r");
    getModemDriver().getResponse();
    if (!Service.getInstance().getSettings().DISABLE_COPS)
    {
      getModemDriver().write("AT+COPS=0\r");
      getModemDriver().getResponse();
    }
  }

  @Override
  public void done() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    // No default behavior.
  }

  @Override
  public boolean isAlive() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT\r");
    String response = getModemDriver().getResponse();
    if (response.indexOf("AT\r") == -1) { return getModemDriver().isOk(); }
    return false;
  }

  @Override
  public String getSimStatus() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CPIN?\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public boolean enterPin(String pin) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CPIN=\"_1_\"\r".replaceAll("_1_", pin));
    getModemDriver().getResponse();
    return (getModemDriver().isOk());
  }

  @Override
  public boolean setVerboseErrors() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CMEE=1\r");
    getModemDriver().getResponse();
    return (getModemDriver().isOk());
  }

  @Override
  public boolean setPduProtocol() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CMGF=0\r");
    getModemDriver().getResponse();
    return (getModemDriver().isOk());
  }

  @Override
  public boolean setTextProtocol() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CMGF=1\r");
    getModemDriver().getResponse();
    if (getModemDriver().isOk())
    {
      getModemDriver().write("AT+CSCS=\"8859-1\"\r");
      getModemDriver().getResponse();
      return (getModemDriver().isOk());
    }
    return false;
  }

  @Override
  public boolean setIndications() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    int RETRIES = 3;
    int count = 0;
    while (count < RETRIES)
    {
      getModemDriver().write("AT+CNMI=?\r");
      try
      {
        this.cnmiDetector = new CNMIDetector(getModemDriver().getResponse());
        getModemDriver().write(this.cnmiDetector.getATCommand());
        getModemDriver().getResponse();
        return (getModemDriver().isOk());
      }
      catch (Exception e)
      {
        count++;
        Logger.getInstance().logWarn("Retrying the detection of CNMI, modem busy?", null, getGateway().getGatewayId());
        Thread.sleep(Service.getInstance().getSettings().AT_WAIT_CNMI);
      }
    }
    Logger.getInstance().logWarn("CNMI detection failed, proceeding with defaults.", null, getGateway().getGatewayId());
    return false;
  }

  @Override
  public CNMIDetector getIndications()
  {
    return this.cnmiDetector;
  }

  @Override
  public String getManufacturer() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CGMI\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getModel() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CGMM\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getSerialNo() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CGSN\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getImsi() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CIMI\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getSwVersion() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CGMR\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getBatteryLevel() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CBC\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getSignalLevel() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CSQ\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String getNetworkOperator() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+COPS?\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public boolean switchStorageLocation(String mem) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    if (mem.equalsIgnoreCase("--")) return true;
    getModemDriver().write("AT+CPMS=\"" + mem + "\"\r");
    getModemDriver().getResponse();
    return (getModemDriver().isOk());
  }

  @Override
  public void switchToCmdMode() throws IOException, InterruptedException
  {
    getModemDriver().write("+++");
    java.util.Date start = new java.util.Date();
    while (new java.util.Date().getTime() - start.getTime() <= Service.getInstance().getSettings().AT_WAIT_CMD)
      Thread.sleep(100);
  }

  @Override
  public void keepLinkOpen() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    if (!Service.getInstance().getSettings().DISABLE_CMMS)
    {
      getModemDriver().write("AT+CMMS=2\r");
      getModemDriver().getResponse();
    }
  }

  @Override
  public int sendMessage(int size, String pdu, String phone, String text) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    int responseRetries, errorRetries;
    String response;
    int refNo = -1;
    if (getGateway().getProtocol() == Protocols.PDU)
    {
      errorRetries = 0;
      while (true)
      {
        responseRetries = 0;
        getModemDriver().write("AT+CMGS=\"_1_\"\r".replaceAll("\"_1_\"", "" + size));
        Thread.sleep(Service.getInstance().getSettings().AT_WAIT_CGMS);
        while (!getModemDriver().dataAvailable())
        {
          responseRetries++;
          if (responseRetries == Service.getInstance().getSettings().OUTBOUND_RETRIES) throw new GatewayException("Gateway is not responding, max number of retries reached.");
          Logger.getInstance().logWarn("ATHandler().SendMessage(): Still waiting for response (I) (" + responseRetries + ")...", null, getGateway().getGatewayId());
          Thread.sleep(Service.getInstance().getSettings().OUTBOUND_RETRY_WAIT);
        }
        responseRetries = 0;
        getModemDriver().clearBuffer();
        getModemDriver().write(pdu);
        getModemDriver().write((char) 26);
        response = getModemDriver().getResponse();
        while (response.length() == 0)
        {
          responseRetries++;
          if (responseRetries == Service.getInstance().getSettings().OUTBOUND_RETRIES) throw new GatewayException("Gateway is not responding, max number of retries reached.");
          Logger.getInstance().logWarn("ATHandler().SendMessage(): Still waiting for response (II) (" + responseRetries + ")...", null, getGateway().getGatewayId());
          Thread.sleep(Service.getInstance().getSettings().OUTBOUND_RETRY_WAIT);
          response = getModemDriver().getResponse();
        }
        if (getModemDriver().getLastError() == 0)
        {
          Matcher m = Pattern.compile("\\s*\\+CMGS: *(\\d+)").matcher(response);
          if (m.find())
          {
            refNo = Integer.parseInt(m.group(1));
          }
          else
          {
            // Message-Reference ID not returned
            refNo = -1;
          }
          break;
        }
        else if (getModemDriver().getLastError() > 0)
        {
          // CMS or CME error could happen here
          errorRetries++;
          if (errorRetries == Service.getInstance().getSettings().OUTBOUND_RETRIES)
          {
            Logger.getInstance().logError(getModemDriver().getLastErrorText() + ": Quit retrying, message lost...", null, getGateway().getGatewayId());
            refNo = -1;
            break;
          }
          Logger.getInstance().logWarn(getModemDriver().getLastErrorText() + ": Retrying...", null, getGateway().getGatewayId());
          Thread.sleep(Service.getInstance().getSettings().OUTBOUND_RETRY_WAIT);
        }
        else refNo = -1;
      }
    }
    else if (getGateway().getProtocol() == Protocols.TEXT)
    {
      getModemDriver().write("AT+CMGS=\"_1_\"\r".replaceAll("_1_", phone));
      getModemDriver().clearBuffer();
      getModemDriver().write(text);
      Thread.sleep(Service.getInstance().getSettings().AT_WAIT_CGMS);
      getModemDriver().write((char) 26);
      response = getModemDriver().getResponse();
      if (response.indexOf("OK\r") >= 0)
      {
        int i;
        StringBuilder tmp = new StringBuilder();
        i = response.indexOf(":");
        while (!Character.isDigit(response.charAt(i)))
          i++;
        while (Character.isDigit(response.charAt(i)))
        {
          tmp.append(response.charAt(i));
          i++;
        }
        refNo = Integer.parseInt(tmp.toString());
      }
      else refNo = -1;
    }
    return refNo;
  }

  @Override
  public String listMessages(MessageClasses messageClass) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    if (getGateway().getProtocol() == Protocols.PDU)
    {
      if (messageClass == MessageClasses.ALL) getModemDriver().write("AT+CMGL=4\r");
      else if (messageClass == MessageClasses.UNREAD) getModemDriver().write("AT+CMGL=0\r");
      else if (messageClass == MessageClasses.READ) getModemDriver().write("AT+CMGL=1\r");
    }
    else if (getGateway().getProtocol() == Protocols.TEXT)
    {
      if (messageClass == MessageClasses.ALL) getModemDriver().write("AT+CMGL=\"ALL\"\r");
      else if (messageClass == MessageClasses.UNREAD) getModemDriver().write("AT+CMGL=\"REC UNREAD\"\r");
      else if (messageClass == MessageClasses.READ) getModemDriver().write("AT+CMGL=\"REC READ\"\r");
    }
    return getModemDriver().getResponse();
  }

  @Override
  public String getMessageByIndex(int msgIndex) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CMGR=" + msgIndex + "\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public boolean deleteMessage(int memIndex, String memLocation) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    if (!switchStorageLocation(memLocation)) return false;
    Thread.sleep(Service.getInstance().getSettings().AT_WAIT);
    getModemDriver().write("AT+CMGD=_1_\r".replaceAll("_1_", "" + memIndex));
    getModemDriver().getResponse();
    return (getModemDriver().isOk());
  }

  @Override
  public String getGprsStatus() throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CGATT?\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public String send(String s) throws TimeoutException, GatewayException, IOException, InterruptedException
  {
    getModemDriver().write(s);
    return (getModemDriver().getResponse());
  }

  @Override
  public String getNetworkRegistration() throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    getModemDriver().write("AT+CREG=1\r");
    getModemDriver().getResponse();
    getModemDriver().write("AT+CREG?\r");
    return (getModemDriver().getResponse());
  }

  @Override
  public void readStorageLocations() throws Exception
  {
    String response, loc;
    StringTokenizer tokens;
    getModemDriver().write("AT+CPMS=?\r");
    response = getModemDriver().getResponse();
    try
    {
      if (response.indexOf("+CPMS:") >= 0)
      {
        int i, j;
        i = response.indexOf('(');
        while (response.charAt(i) == '(')
          i++;
        j = i;
        while (response.charAt(j) != ')')
          j++;
        response = response.substring(i, j);
        tokens = new StringTokenizer(response, ",");
        while (tokens.hasMoreTokens())
        {
          loc = tokens.nextToken().replaceAll("\"", "");
          if ((!loc.equalsIgnoreCase("MT")) && ((getStorageLocations().indexOf(loc) < 0))) addStorageLocation(loc);
        }
      }
      else
      {
        addStorageLocation("SM");
        Logger.getInstance().logWarn("CPMS detection failed, proceeding with default storage 'SM'.", null, getGateway().getGatewayId());
      }
    }
    catch (Exception e)
    {
      addStorageLocation("SM");
      Logger.getInstance().logWarn("CPMS detection failed, proceeding with default storage 'SM'.", null, getGateway().getGatewayId());
    }
  }

  @Override
  public String readPhonebookLocations() throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    String response;
    getModemDriver().write("AT+CPBS=?\r");
    response = getModemDriver().getResponse();
    if (response.indexOf("+CPBS:") >= 0)
    {
      response = response.replaceAll("\\s*\\+CPBS:\\s*", "");
      response = response.replaceAll("[()]", "");
      return response;
    }
    return "";
  }

  @Override
  public String readPhonebook(String loc) throws GatewayException, TimeoutException, IOException
  {
    String response;
    int minIndex, maxIndex;
    try
    {
      getModemDriver().write("AT+CPBS=\"" + loc + "\"\r");
      getModemDriver().getResponse();
      getModemDriver().write("AT+CPBR=?\r");
      response = getModemDriver().getResponse();
      response = response.replaceAll("\\s*\\+CPBR:\\s*", "");
      response = response.replaceAll("[()]", "");
      StringTokenizer tokens1 = new StringTokenizer(response, ",");
      StringTokenizer tokens2 = new StringTokenizer(tokens1.nextToken(), "-");
      minIndex = Integer.parseInt(tokens2.nextToken());
      maxIndex = Integer.parseInt(tokens2.nextToken());
      getModemDriver().write("AT+CPBR=" + minIndex + "," + maxIndex + "\r");
      response = getModemDriver().getResponse();
      return response;
    }
    catch (Exception e)
    {
      Logger.getInstance().logWarn("Phonebook detection failed.", null, getGateway().getGatewayId());
      return "";
    }
  }

  @Override
  public String sendCustomATCommand(String atCommand) throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    getModemDriver().write(atCommand);
    return getModemDriver().getResponse();
  }

  @Override
  public String sendUSSDCommand(String ussdCommand) throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    return sendUSSDCommand(ussdCommand, false);
  }

  @Override
  public String sendUSSDCommand(String ussdCommand, boolean interactive) throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    String command = formatUSSDCommand(ussdCommand);
    // get the immediate result code
    String ussdResponse = sendCustomATCommand(command);
    if (!ussdResponse.contains("OK"))
    {
      Logger.getInstance().logError("+CUSD command returned non-OK result: " + ussdResponse, null, getGateway().getGatewayId());
      return null;
    }
    // get the unsolicted result
    ussdResponse = getModemDriver().getResponse(AsyncEvents.USSDRESPONSE);
    if (!interactive)
    {
      /*
       * This is a workaround for interactive USSD sessions which expect
       * further user input. We preemptively send an escape character which
       * will terminate such a session.
       */
      char esc = 0x1b;
      command = "" + esc + '\r';
      getModemDriver().write(command);
      getModemDriver().clearBuffer();
    }
    String response;
    String regex = "\"(.*)\"";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(ussdResponse);
    if (matcher.find())
    {
      response = formatUSSDResponse(matcher.group(1));
    }
    else
    {
      response = ussdResponse;
    }
    return response;
  }

  @Override
  public boolean sendUSSDRequest(String presentation, String content, String dcs) throws GatewayException, TimeoutException, IOException, InterruptedException
  {
    String rawRequest = formatUSSDCommand(presentation, content, dcs);
    String ussdResponse = sendCustomATCommand(rawRequest);
    if (!ussdResponse.contains("OK"))
    {
      Logger.getInstance().logError("+CUSD command returned non-OK result: " + ussdResponse, null, getGateway().getGatewayId());
      return false;
    }
    return true;
  }

  protected String formatUSSDCommand(String ussdCommand)
  {
    return formatUSSDCommand("1", ussdCommand, null);
  }

  protected String formatUSSDCommand(String presentation, String content, String dcs)
  {
    StringBuffer buf = new StringBuffer();
    buf.append("AT+CUSD=");
    buf.append(presentation);
    buf.append(",");
    buf.append("\"");
    buf.append(content);
    buf.append("\"");
    if (dcs != null && dcs.length() > 0)
    {
      buf.append(",");
      buf.append(dcs);
    }
    buf.append("\r");
    return buf.toString();
  }

  public String formatUSSDResponse(String ussdResponse)
  {
    // noop for most modems but some may require additional processing e.g. pdudecode
    return ussdResponse;
  }

  @Override
  public AsyncEvents processUnsolicitedEvents(String response) throws IOException
  {
    AsyncEvents event = AsyncEvents.NOTHING;
    if (response.indexOf(getUnsolicitedResponse(0)) >= 0) event = AsyncEvents.INBOUNDMESSAGE;
    else if (response.indexOf(getUnsolicitedResponse(1)) >= 0) event = AsyncEvents.INBOUNDSTATUSREPORTMESSAGE;
    else if (response.indexOf(getUnsolicitedResponse(2)) >= 0) event = AsyncEvents.NOTHING;
    else if (response.indexOf(getUnsolicitedResponse(3)) >= 0) event = AsyncEvents.INBOUNDCALL;
    else if (response.indexOf(getUnsolicitedResponse(4)) >= 0) event = AsyncEvents.USSDRESPONSE;
    return event;
  }
}
TOP

Related Classes of org.smslib.modem.athandler.ATHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.