vshymanskyy / TinyGSM

A small Arduino library for GSM modules, that just works
GNU Lesser General Public License v3.0
1.93k stars 715 forks source link

HTTPS Support for SIM7600 #535

Open biswaKL opened 3 years ago

biswaKL commented 3 years ago

Any support for SIM7600 HTTPS?

SRGDamia1 commented 3 years ago

Not at present.

ashwanisihag commented 3 years ago

Here is support for HTTPS

See below code.

ashwanisihag commented 3 years ago

/* @file TinyGsmClientSIM7600.h @author Volodymyr Shymanskyy @license LGPL-3.0 @copyright Copyright (c) 2016 Volodymyr Shymanskyy @date Nov 2016 /

ifndef SRC_TINYGSMCLIENTSIM7600H

define SRC_TINYGSMCLIENTSIM7600H

// #define TINY_GSM_DEBUG Serial // #define TINY_GSM_USE_HEX

define TINY_GSM_MUX_COUNT 10

define TINY_GSM_BUFFER_READ_AND_CHECK_SIZE

include "TinyGsmBattery.tpp"

include "TinyGsmGPRS.tpp"

include "TinyGsmGPS.tpp"

include "TinyGsmGSMLocation.tpp"

include "TinyGsmModem.tpp"

include "TinyGsmSMS.tpp"

include "TinyGsmTCP.tpp"

include "TinyGsmTemperature.tpp"

include "TinyGsmTime.tpp"

define GSM_NL "\r\n"

static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;

if defined TINY_GSM_DEBUG

static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; static const char GSM_CMS_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CMS ERROR:";

endif

enum RegStatus { REG_NO_RESULT = -1, REG_UNREGISTERED = 0, REG_SEARCHING = 2, REG_DENIED = 3, REG_OK_HOME = 1, REG_OK_ROAMING = 5, REG_UNKNOWN = 4, };

class TinyGsmSim7600 : public TinyGsmModem, public TinyGsmGPRS, public TinyGsmTCP<TinyGsmSim7600, TINY_GSM_MUX_COUNT>, public TinyGsmSMS, public TinyGsmGSMLocation, public TinyGsmGPS, public TinyGsmTime, public TinyGsmBattery, public TinyGsmTemperature { friend class TinyGsmModem; friend class TinyGsmGPRS; friend class TinyGsmTCP<TinyGsmSim7600, TINY_GSM_MUX_COUNT>; friend class TinyGsmSMS; friend class TinyGsmGPS; friend class TinyGsmGSMLocation; friend class TinyGsmTime; friend class TinyGsmBattery; friend class TinyGsmTemperature;

/*
   Inner Client
*/

public: class GsmClientSim7600 : public GsmClient { friend class TinyGsmSim7600;

  public:
    GsmClientSim7600() {}

    explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) {
      init(&modem, mux);
    }

    bool init(TinyGsmSim7600* modem, uint8_t mux = 0) {
      this->at       = modem;
      sock_available = 0;
      prev_check     = 0;
      sock_connected = false;
      got_data       = false;

      if (mux < TINY_GSM_MUX_COUNT) {
        this->mux = mux;
      } else {
        this->mux = (mux % TINY_GSM_MUX_COUNT);
      }
      at->sockets[this->mux] = this;

      return true;
    }

  public:
    virtual int connect(const char* host, uint16_t port, int timeout_s) {
      DBG("connect called");
      stop();
      TINY_GSM_YIELD();
      rx.clear();
      sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
      return sock_connected;
    }
    TINY_GSM_CLIENT_CONNECT_OVERRIDES

    void stop(uint32_t maxWaitMs) {
        DBG("stop called");
      dumpModemBuffer(maxWaitMs);
      // at->sendAT(GF("+CIPCLOSE="), mux);
      at->sendAT(GF("+CCHCLOSE=0"));//todo
      // at->sendAT(GF("+CCHSTOP=0"));//todo
      sock_connected = false;
      DBG("stop waitResponse called");
      at->waitResponse();
    }
    void stop() override {
      stop(15000L);
    }

    /*
       Extended API
    */

    String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};

public: explicit TinyGsmSim7600(Stream& stream) : stream(stream) { memset(sockets, 0, sizeof(sockets)); }

/*
   Basic functions
*/

protected: bool initImpl(const char* pin = NULL) { DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); DBG(GF("### TinyGSM Compiled Module: TinyGsmClientSIM7600"));

  if (!testAT()) {
    return false;
  }

  sendAT(GF("E0"));  // Echo Off
  if (waitResponse() != 1) {
    return false;
  }

ifdef TINY_GSM_DEBUG

  sendAT(GF("+CMEE=2"));  // turn on verbose error codes

else

  sendAT(GF("+CMEE=0"));  // turn off error codes

endif

  waitResponse();

  DBG(GF("### Modem:"), getModemName());

  // Disable time and time zone URC's
  sendAT(GF("+CTZR=0"));
  if (waitResponse(10000L) != 1) {
    return false;
  }

  // Enable automatic time zome update
  sendAT(GF("+CTZU=1"));
  if (waitResponse(10000L) != 1) {
    return false;
  }

  SimStatus ret = getSimStatus();
  // if the sim isn't ready and a pin has been provided, try to unlock the sim
  if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
    simUnlock(pin);
    return (getSimStatus() == SIM_READY);
  } else {
    // if the sim is ready, or it's locked but no pin has been provided,
    // return true
    return (ret == SIM_READY || ret == SIM_LOCKED);
  }
}

String getModemNameImpl() {
  String name = "SIMCom SIM7600";

  sendAT(GF("+CGMM"));
  String res2;
  if (waitResponse(1000L, res2) != 1) {
    return name;
  }
  res2.replace(GSM_NL "OK" GSM_NL, "");
  res2.replace("_", " ");
  res2.trim();

  name = res2;
  DBG("### Modem:", name);
  return name;
}

bool factoryDefaultImpl() {  // these commands aren't supported
  return false;
}

/*
   Power functions
*/

protected: bool restartImpl(const char* pin = NULL) { if (!testAT()) { return false; } sendAT(GF("+CRESET")); if (waitResponse(10000L) != 1) { return false; } delay(5000L); // TODO(?): Test this delay! return init(pin); }

bool powerOffImpl() {
  sendAT(GF("+CPOF"));
  return waitResponse() == 1;
}

bool radioOffImpl() {
  if (!setPhoneFunctionality(4)) {
    return false;
  }
  delay(5000L);
  return true;
}

bool sleepEnableImpl(bool enable = true) {
  sendAT(GF("+CSCLK="), enable);
  return waitResponse() == 1;
}

bool setPhoneFunctionalityImpl(uint8_t fun, bool reset = false) {
  sendAT(GF("+CFUN="), fun, reset ? ",1" : "");
  return waitResponse(10000L) == 1;
}

/*
   Generic network functions
*/

public: RegStatus getRegistrationStatus() { return (RegStatus)getRegistrationStatusXREG("CGREG"); }

protected: bool isNetworkConnectedImpl() { RegStatus s = getRegistrationStatus(); return (s == REG_OK_HOME || s == REG_OK_ROAMING); }

public: String getNetworkModes() { sendAT(GF("+CNMP=?")); if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); return res; }

String setNetworkMode(uint8_t mode) {
  sendAT(GF("+CNMP="), mode);
  if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) {
    return "OK";
  }
  String res = stream.readStringUntil('\n');
  waitResponse();
  return res;
}

String getLocalIPImpl() {
  sendAT(GF("+IPADDR"));  // Inquire Socket PDP address
  // sendAT(GF("+CGPADDR=1"));  // Show PDP address
  String res;
  if (waitResponse(10000L, res) != 1) {
    return "";
  }
  res.replace(GSM_NL "OK" GSM_NL, "");
  res.replace(GSM_NL, "");
  res.trim();
  return res;
}

/*
   GPRS functions
*/

protected: bool gprsConnectImpl(const char apn, const char user = NULL, const char* pwd = NULL) { gprsDisconnect(); // Make sure we're not connected first

  sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
  waitResponse();

  sendAT(GF("+CGPADDR"));
  waitResponse();

  sendAT(GF("+CIPMODE=0"));
  waitResponse();

  sendAT(GF("+CIPSENDMODE=0"));
  waitResponse();

  sendAT(GF("+CIPCCFG=10,0,0,0,1,0,30000"));
  waitResponse();

  sendAT(GF("+CIPTIMEOUT="), 30000, ',', 30000, ',', 30000);
  waitResponse();

  sendAT(GF("+NETOPEN"));
  if (waitResponse(75000L,GF(GSM_NL "+NETOPEN: 0")) != 1)
  {
      DBG("+NETOPEN: 0 not found");
    sendAT(GF("+NETOPEN"));
    if (waitResponse(75000L,GF("+IP ERROR: Network is already opened")) != 1)
    {
          DBG("+IP ERROR: Network is already opened not found");
      sendAT(GF(GSM_NL "+NETOPEN"));
      if (waitResponse(75000L,GF("+IP ERROR: 4")) == 1)
      {
          DBG("+IP ERROR: 4 not found");
        DBG("NET DEACTIVATED");
        return false;
      }
    }
  }
  DBG("NET ACTIVATED");
  delay(1000);

  /*sendAT(GF("+IPADDR"));  // Inquire Socket PDP address
     if (waitResponse(120000L,GF(GSM_NL "+IP ERROR:")) == 1) {
    DBG("IPADDRESS NOT FOUND");
    return false;
    }
    DBG("IPADDRESS FOUND"); */
  return true;
}

bool isGprsConnectedImpl() {
  //AT+NETOPEN?
  sendAT(GF("+NETOPEN?"));

  if (waitResponse((GSM_NL "+NETOPEN: 1")) != 1) {
    DBG("CHECK NET FAIL");
    return false;
  }
  DBG("CHECK NET SUCCESS");
  return true;
}

bool gprsDisconnectImpl() {

  sendAT(GF("+NETCLOSE"));
  if (waitResponse(GF(GSM_NL "+NETCLOSE: 0")) != 1) {
    DBG("GPRS CLOSED");
    return false;
  }
  DBG("GPRS OPENED");
  return true;
}

/*
   SIM card functions
*/

protected: // Gets the CCID of a sim card via AT+CCID String getSimCCIDImpl() { sendAT(GF("+CICCID")); if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; } String res = stream.readStringUntil('\n'); waitResponse(); res.trim(); return res; }

/*
   Phone Call functions
*/

protected: bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; bool dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED;

/*
   Messaging functions
*/

protected: // Follows all messaging functions per template

/*
   GSM Location functions
*/

protected: // Can return a GSM-based location from CLBS as per the template

/*
   GPS/GNSS/GLONASS location functions
*/

protected: // enable GPS bool enableGPSImpl() { sendAT(GF("+CGPS=1")); if (waitResponse() != 1) { return false; } return true; }

bool disableGPSImpl() {
  sendAT(GF("+CGPS=0"));
  if (waitResponse() != 1) {
    return false;
  }
  return true;
}

// get the RAW GPS output
String getGPSrawImpl() {
  sendAT(GF("+CGNSSINFO"));
  if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) {
    return "";
  }
  String res = stream.readStringUntil('\n');
  waitResponse();
  res.trim();
  return res;
}

// get GPS informations
bool getGPSImpl(float* lat, float* lon, float* speed = 0, float* alt = 0,
                int* vsat = 0, int* usat = 0, float* accuracy = 0,
                int* year = 0, int* month = 0, int* day = 0, int* hour = 0,
                int* minute = 0, int* second = 0) {
  sendAT(GF("+CGNSSINFO"));
  if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) {
    return false;
  }

  uint8_t fixMode = streamGetIntBefore(',');  // mode 2=2D Fix or 3=3DFix
  // TODO(?) Can 1 be returned
  if (fixMode == 1 || fixMode == 2 || fixMode == 3) {
    // init variables
    float ilat = 0;
    char  north;
    float ilon = 0;
    char  east;
    float ispeed       = 0;
    float ialt         = 0;
    int   ivsat        = 0;
    int   iusat        = 0;
    float iaccuracy    = 0;
    int   iyear        = 0;
    int   imonth       = 0;
    int   iday         = 0;
    int   ihour        = 0;
    int   imin         = 0;
    float secondWithSS = 0;

    streamSkipUntil(',');               // GPS satellite valid numbers
    streamSkipUntil(',');               // GLONASS satellite valid numbers
    streamSkipUntil(',');               // BEIDOU satellite valid numbers
    ilat  = streamGetFloatBefore(',');  // Latitude in ddmm.mmmmmm
    north = stream.read();              // N/S Indicator, N=north or S=south
    streamSkipUntil(',');
    ilon = streamGetFloatBefore(',');  // Longitude in ddmm.mmmmmm
    east = stream.read();              // E/W Indicator, E=east or W=west
    streamSkipUntil(',');

    // Date. Output format is ddmmyy
    iday   = streamGetIntLength(2);    // Two digit day
    imonth = streamGetIntLength(2);    // Two digit month
    iyear  = streamGetIntBefore(',');  // Two digit year

    // UTC Time. Output format is hhmmss.s
    ihour = streamGetIntLength(2);  // Two digit hour
    imin  = streamGetIntLength(2);  // Two digit minute
    secondWithSS =
      streamGetFloatBefore(',');  // 4 digit second with subseconds

    ialt   = streamGetFloatBefore(',');  // MSL Altitude. Unit is meters
    ispeed = streamGetFloatBefore(',');  // Speed Over Ground. Unit is knots.
    streamSkipUntil(',');                // Course Over Ground. Degrees.
    streamSkipUntil(',');  // After set, will report GPS every x seconds
    iaccuracy = streamGetFloatBefore(',');  // Position Dilution Of Precision
    streamSkipUntil(',');   // Horizontal Dilution Of Precision
    streamSkipUntil(',');   // Vertical Dilution Of Precision
    streamSkipUntil('\n');  // TODO(?) is one more field reported??

    // Set pointers
    if (lat != NULL)
      *lat = (floor(ilat / 100) + fmod(ilat, 100.) / 60) *
             (north == 'N' ? 1 : -1);
    if (lon != NULL)
      *lon = (floor(ilon / 100) + fmod(ilon, 100.) / 60) *
             (east == 'E' ? 1 : -1);
    if (speed != NULL) *speed = ispeed;
    if (alt != NULL) *alt = ialt;
    if (vsat != NULL) *vsat = ivsat;
    if (usat != NULL) *usat = iusat;
    if (accuracy != NULL) *accuracy = iaccuracy;
    if (iyear < 2000) iyear += 2000;
    if (year != NULL) *year = iyear;
    if (month != NULL) *month = imonth;
    if (day != NULL) *day = iday;
    if (hour != NULL) *hour = ihour;
    if (minute != NULL) *minute = imin;
    if (second != NULL) *second = static_cast<int>(secondWithSS);

DBG("getGPSImpl waitResponse called true"); waitResponse(); return true; } DBG("getGPSImpl waitResponse called false"); waitResponse(); return false; }

/**
    CGNSSMODE: <gnss_mode>,<dpo_mode>
    This command is used to configure GPS, GLONASS, BEIDOU and QZSS support
   mode. 0 : GLONASS 1 : BEIDOU 2 : GALILEO 3 : QZSS dpo_mode: 1 enable , 0
   disable
*/
String setGNSSModeImpl(uint8_t mode, bool dpo) {
  String res;
  sendAT(GF("+CGNSSMODE="), mode, ",", dpo);
  if (waitResponse(10000L, res) != 1) {
    return "";
  }
  res.replace(GSM_NL, "");
  res.trim();
  return res;
}

uint8_t getGNSSModeImpl() {
  sendAT(GF("+CGNSSMODE?"));
  if (waitResponse(GF(GSM_NL "+CGNSSMODE:")) != 1) {
    return 0;
  }
  return stream.readStringUntil(',').toInt();
}

/*
   Time functions
*/

protected: // Can follow the standard CCLK function in the template

/*
   Battery functions
*/

protected: // returns volts, multiply by 1000 to get mV uint16_t getBattVoltageImpl() { sendAT(GF("+CBC")); if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }

  // get voltage in VOLTS
  float voltage = streamGetFloatBefore('\n');
  // Wait for final OK
  waitResponse();
  // Return millivolts
  uint16_t res = voltage * 1000;
  return res;
}

int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;

uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;

bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
                      uint16_t& milliVolts) {
  chargeState = 0;
  percent     = 0;
  milliVolts  = getBattVoltage();
  return true;
}

/*
   Temperature functions
*/

protected: // get temperature in degree celsius uint16_t getTemperatureImpl() { sendAT(GF("+CPMUTEMP")); if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { return 0; } // return temperature in C uint16_t res = streamGetIntBefore('\n'); // Wait for final OK waitResponse(); return res; }

/*
   Client related functions
*/
/*  byte NTPServerSync(String server = "pool.ntp.org", byte TimeZone = 3) {
  // Set GPRS bearer profile to associate with NTP sync
  // sendAT(GF("+CNTPCID=1"));
  // if (waitResponse(10000L) != 1) { return -1; }

  // Set NTP server and timezone
  sendAT(GF("+CNTP="), server, ',', String(TimeZone));
  if (waitResponse(10000L) != 1) { return -1; }

  // Request network synchronization
  sendAT(GF("+CNTP"));
  if (waitResponse(10000L, GF(GSM_NL "+CNTP:"))) {
    String result = stream.readStringUntil('\n');
    result.trim();
    if (isValidNumber(result)) { return result.toInt(); }
  } else {
    return -1;
  }
  return -1;
  } */

protected: bool _ssl = true; bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = true, int timeout_s = 15) {

  if (_ssl) {
    sendAT(GF("+CSSLCFG=\"sslversion\",0,4"));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"authmode\",0,2"));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"ignorelocaltime\",0,1"));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"negotiatetime\",0,25"));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"cacert\",0,\"ca_cert.pem\""));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"clientcert\",0,\"cert.pem\""));
    waitResponse();
    sendAT(GF("+CSSLCFG=\"clientkey\",0,\"key_cert.pem\""));
    waitResponse();
    sendAT(GF("+CCHSET=1,1"));
    waitResponse();
    sendAT(GF("+CCHSTART"));
    waitResponse();
    sendAT(GF("+CCHSSLCFG=0,0"));
    waitResponse();
  }
  // Make sure we'll be getting data manually on this connection

  // waitResponse();
  // Establish a connection in multi-socket mode
  uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
  if (!_ssl) {
       sendAT(GF("+CIPRXGET=1"));
  if (waitResponse() != 1) { return false; }
    sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
  }
  else { 
    sendAT(GF("+CCHOPEN=0,"), GF("\""), host, GF("\","), port, GF(",2"));
  }
  // The reply is OK followed by +CIPOPEN: <link_num>,<err> where <link_num>
  // is the mux number and <err> should be 0 if there's no error

  if (!_ssl) {
    if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) {
      return false;
    }
  }
  else {
    if (waitResponse(timeout_ms,GF(GSM_NL "+CCHOPEN: 0,0")) != 1) {
      return false;
    }
    else{
         return true;
    }
  }

/*   uint8_t opened_mux    = streamGetIntBefore(',');
  uint8_t opened_result = streamGetIntBefore('\n');
  if (opened_mux != mux || opened_result != 0)
  {
      DBG("return false;");
    return false;
  }
  else
  {
        DBG("return TRUE;");
    return true;
  } */
}

int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
     DBG("modemSend called ");
  if (!_ssl) {
    sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
  }
  else {
    sendAT(GF("+CCHSEND="), mux, ',', (uint16_t)len);
  }

DBG("modemSend waitResponse> called "); if (waitResponse(GF(">")) != 1) { return 0; } SerialMon.print((const int )buff); stream.write(reinterpret_cast<const uint8_t*>(buff), len); stream.flush(); if (!_ssl) { if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; } } else { DBG("modemSend waitResponse CCHSEND called "); if (waitResponse(GF(GSM_NL "+CCHSEND:")) != 1) { return 0; } }

  streamSkipUntil(',');  // Skip mux
  streamSkipUntil(',');  // Skip requested bytes to send
  // TODO(?):  make sure requested and confirmed bytes match
  return streamGetIntBefore('\n');
}

size_t modemRead(size_t size, uint8_t mux) {
    DBG("modemRead  called ");
  int16_t len_requested = 0;
  int16_t len_confirmed = 0;
  if (!sockets[mux]) return 0;
  if (!_ssl)
  {

ifdef TINY_GSM_USE_HEX

    sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
    if (waitResponse(GF("+CIPRXGET:")) != 1) {
      return 0;
    }

else

    sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
    if (waitResponse(GF("+CIPRXGET:")) != 1) {
      return 0;
    }

endif

    //+CIPRXGET: 2,1,5,11
    streamSkipUntil(',');  // Skip Rx mode 2/normal or 3/HEX 2,
    streamSkipUntil(',');  // Skip mux/cid (1,)
    len_requested = streamGetIntBefore(',');//5,
    //  ^^ Requested number of data bytes (1-1460 bytes)to be read
    len_confirmed = streamGetIntBefore('\n');//,11
  }
  else {
    sendAT(GF("+CCHRECV="), mux, ',', (uint16_t)size);
    DBG("modemRead  CCHRECV called ");
    if (waitResponse(GF("+CCHRECV:")) != 1) {
      return 0;
    }
    // DATA,0,4
    streamSkipUntil(',');  //DATA,
    streamSkipUntil(',');  // Skip mux/cid (0,)
    len_requested = streamGetIntBefore('\n');
    // DBG("###len_requested", len_requested);

    len_confirmed = len_requested;
  }

  // ^^ The data length which not read in the buffer
  for (int i = 0; i < len_requested; i++) {
    uint32_t startMillis = millis();

ifdef TINY_GSM_USE_HEX

    while (stream.available() < 2 &&
           (millis() - startMillis < sockets[mux]->_timeout)) {
      TINY_GSM_YIELD();
    }
    char buf[4] = {
      0,
    };
    buf[0] = stream.read();
    buf[1] = stream.read();
    char c = strtol(buf, NULL, 16);

else

    while (!stream.available() &&
           (millis() - startMillis < sockets[mux]->_timeout)) {
      TINY_GSM_YIELD();
    }
    char c = stream.read();
    SerialMon.print(c);

endif

    sockets[mux]->rx.put(c);
  }
  // DBG("### READ:", len_requested, "from", mux);
  sockets[mux]->sock_available = modemGetAvailable(mux);
  // sockets[mux]->sock_available = len_confirmed;
  if (!_ssl)
  {
    waitResponse();
  }
  return len_requested;
}

size_t modemGetAvailable(uint8_t mux) {
    DBG("modemGetAvailable   called ");
  if (!sockets[mux]) return 0;
  size_t result = 0;
  if (!_ssl)
  {
    sendAT(GF("+CIPRXGET=4,"), mux);

    if (waitResponse(GF("+CIPRXGET:")) == 1) {
      streamSkipUntil(',');  // Skip mode 4
      streamSkipUntil(',');  // Skip mux
      result = streamGetIntBefore('\n');
      waitResponse();
    }
  }
  else
  {
    // AT+CCHRECV? +CCHRECV: LEN,<cache_len_0>,<cache_len_1>
    sendAT(GF("+CCHRECV?"));
    DBG("modemGetAvailable  +CCHRECV? called ");
    if (waitResponse(GF("+CCHRECV:")) == 1) {
      streamSkipUntil(',');  // Skip mode 4
      result = streamGetIntBefore(',');
      DBG("modemGetAvailable  +CCHRECV?2 called ");
      waitResponse();
    }
  }
   DBG("### Available:", result, "on", mux);
  if (!result) {
    sockets[mux]->sock_connected = modemGetConnected(mux);
  }
  return result;
}

bool modemGetConnected(uint8_t mux) {
    DBG("modemGetConnected called ");
  // Read the status of all sockets at once
  if (!_ssl)
  {
    sendAT(GF("+CIPCLOSE?"));
    if (waitResponse(GF("+CIPCLOSE:")) != 1) {
      return false;  // TODO:  Why does this not read correctly?
    }
    for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
      // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state>
      bool muxState = stream.parseInt();
      if (sockets[muxNo]) {
        sockets[muxNo]->sock_connected = muxState;
      }
    }
    waitResponse();  // Should be an OK at the end
    if (!sockets[mux])
      return false;
    return sockets[mux]->sock_connected;
  }
  else {
    sendAT(GF("+CCHOPEN?"));
    DBG("modemGetConnected +CCHOPEN? waitResponsecalled ");
    if (waitResponse(GF("+CCHOPEN:")) != 1) {
        DBG("Modem not connectedXXXXXXXXXXXXXXXXX CCHOPEN Not Found");
        return false;
        }
      //+CCHOPEN: 0,"",,,
      streamSkipUntil(',');
      String res = stream.readStringUntil(',');
      if (res == "\"\"")
      {
            DBG("Modem not connectedXXXXXXXXXXXXXXXXX empty +CCHOPEN: 0,"",,, Found");
        return false;
      }
      else {
          DBG("************Modem is connected Found in sim7600 Library****************");
          DBG("Dats is",res);
           sockets[mux]->sock_connected = true;
            waitResponse();  // Should be an OK at the end
           sockets[mux]->sock_connected;
        return true;
      }
    }

  return false;
}

/*
   Utilities
*/

public: // TODO(vshymanskyy): Optimize this! int8_t waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),

if defined TINY_GSM_DEBUG

                    GsmConstStr r3 = GFP(GSM_CME_ERROR),
                    GsmConstStr r4 = GFP(GSM_CMS_ERROR),

else

                    GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,

endif

                    GsmConstStr r5 = NULL) {
   /*   String r1s(r1); r1s.trim();
     String r2s(r2); r2s.trim();
     String r3s(r3); r3s.trim();
     String r4s(r4); r4s.trim();
     String r5s(r5); r5s.trim();
     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s); */
  data.reserve(64);
  uint8_t  index       = 0;
  uint32_t startMillis = millis();
  do {
    TINY_GSM_YIELD();
    while (stream.available() > 0) {
      TINY_GSM_YIELD();
      int8_t a = stream.read();
      if (a <= 0) continue;  // Skip 0x00 bytes, just in case
      data += static_cast<char>(a);

      if (r1 && data.endsWith(r1)) {
        index = 1;
        goto finish;
      } else if (r2 && data.endsWith(r2)) {
        index = 2;
        goto finish;
      } else if (r3 && data.endsWith(r3)) {

if defined TINY_GSM_DEBUG

        if (r3 == GFP(GSM_CME_ERROR)) {
          streamSkipUntil('\n');  // Read out the error
        }

endif

        index = 3;
        goto finish;
      } else if (r4 && data.endsWith(r4)) {
        index = 4;
        goto finish;
      } else if (r5 && data.endsWith(r5)) {
        index = 5;
        goto finish;
      } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) {
        int8_t mode = streamGetIntBefore(',');
        if (mode == 1) {
          int8_t mux = streamGetIntBefore('\n');
          if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
            sockets[mux]->got_data = true;
          }
          data = "";
          // DBG("### Got Data:", mux);
        } else {
          // DBG("data += mode");
          data += mode;
        }
      } else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) {
        int8_t  mux = streamGetIntBefore(',');
        int16_t len = streamGetIntBefore('\n');
        if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
          sockets[mux]->got_data = true;
          if (len >= 0 && len <= 1024) {
            sockets[mux]->sock_available = len;
          }
        }
        data = "";
        // DBG("### Got Data:", len, "on", mux);
      }
      else if (data.endsWith(GF(GSM_NL "+CCHRECV:"))) //+CCHRECV: DATA,0,4
      {
        DBG("*************data start**************");
        //+CCHRECV: DATA, <session_id>,<len>
        streamSkipUntil(',');  // Skip DATA,
        int8_t  mux = streamGetIntBefore(',');//Skip 0,
        int16_t len = streamGetIntBefore('\n');//Skip ,4
        if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
        DBG("### Got_data = true");
          sockets[mux]->got_data = true;
          if (len >= 0 && len <= 1024) {
            sockets[mux]->sock_available = len;
          }
        }
        data = "";
        DBG("### Got Data:", len, "on", mux);
        DBG("**************data end*************");
      }
      else if (data.endsWith(GF("+IPCLOSE:"))) {
        int8_t mux = streamGetIntBefore(',');
        streamSkipUntil('\n');  // Skip the reason code
        if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
          sockets[mux]->sock_connected = false;
        }
        data = "";
        // DBG("### Closed: ", mux);
      } else if (data.endsWith(GF("+CIPEVENT:"))) {
        // Need to close all open sockets and release the network library.
        // User will then need to reconnect.
        // DBG("### Network error!");
        if (!isGprsConnected()) {
          gprsDisconnect();
        }
        data = "";
      }
    }
  } while (millis() - startMillis < timeout_ms);

finish: if (!index) { data.trim(); if (data.length()) { DBG("*Unhandled**"); DBG(data); DBG("*Unhandled end**"); } } // DBG("###############data start2#################"); ////data.replace(GSM_NL, "/"); // DBG('<', index, '>', data); // data = ""; // DBG("##############data end2####################"); return index; }

int8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
                    GsmConstStr r2 = GFP(GSM_ERROR),

if defined TINY_GSM_DEBUG

                    GsmConstStr r3 = GFP(GSM_CME_ERROR),
                    GsmConstStr r4 = GFP(GSM_CMS_ERROR),

else

                    GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,

endif

                    GsmConstStr r5 = NULL) {
  String data;
  return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}

int8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
                    GsmConstStr r2 = GFP(GSM_ERROR),

if defined TINY_GSM_DEBUG

                    GsmConstStr r3 = GFP(GSM_CME_ERROR),
                    GsmConstStr r4 = GFP(GSM_CMS_ERROR),

else

                    GsmConstStr r3 = NULL, GsmConstStr r4 = NULL,

endif

                    GsmConstStr r5 = NULL) {
  return waitResponse(1000, r1, r2, r3, r4, r5);
}

public: Stream& stream;

protected: GsmClientSim7600 sockets[TINY_GSM_MUX_COUNT]; const char gsmNL = GSM_NL; };

endif // SRC_TINYGSMCLIENTSIM7600H

ashwanisihag commented 3 years ago

I got success in sending data to both aws and azure TLS 1.2...its going good.

erlo commented 3 years ago

Hello @ashwanisihag,

Would you accept to provide your TinyGsmClientSIM7600.h in raw format ? I'm trying to find something to support HTTPS on SIM7600, and I have difficulties to work with your file.

Do you implement the class TinyGsmClientSecure ?

Thanks

EmanueleFeola commented 3 years ago

hi @ashwanisihag I'm trying to use your code but I can't make it work, could you please provide your raw file?

EmanueleFeola commented 3 years ago

@ashwanisihag @erlo I made a fork of tinygsm and modified two files: TinyGsmClientSIM7600.h and TinyGsmClient.h, please check it out. I looked through code above and I got it working, so thank you a lot @ashwanisihag !! I'm using the sim7600 module to connect to a mosquitto broker using the secure port 8883. I tested it and it's working correctly, the esp32 connects to mosquitto broker successfully. In my case I do not use certificates on the esp32 so I commented the lines in the code. In the arduino script I declare the client as TinyGsmClientSecure client(modem);

ashwanisihag commented 3 years ago

I am glad that it worked.:-)

kiddtang commented 3 years ago

I found a relative easy way to make it support HTTPS. Check out this tutorial!

tradexsrl commented 2 years ago

Hi @EmanueleFeola , i have the same problem you had with the same mqtt server configuration, i download from your repository the two files modified by you but when i compile i get exit status 1 error if i revert to the original files and set TinyGsmClient client(modem) i'm able to compile....i don't know what could be. please let me know

tradexsrl commented 2 years ago

i activated the verbose level and it says: \Documents\Arduino\libraries\TinyGSM\src/TinyGsmClient.h:46:25: error: 'GsmClientSecureSIM7600' in 'class TinyGsmSim7600' does not name a type typedef TinyGsmSim7600::GsmClientSecureSIM7600 TinyGsmClientSecure;

tradexsrl commented 2 years ago

ok found where is the problem: there is a SerialMon.print(c); left in the TinyGsmClientSIM7600.h downloaded from @EmanueleFeola tinygsm fork

EmanueleFeola commented 2 years ago

@tradexsrl ok, so is the code working or you need some help?

tradexsrl commented 2 years ago

At least I was able to compile the program , in the comeing days I'll test the program on lilygo board with MQTT on port 8883 If I have problems I will post a comment here Thanks

georeb commented 1 year ago

Hi @EmanueleFeola and @ashwanisihag Thank you for this patch - it works nicely on an ESP32 :) but I have a question: When making an HTTPS GET request, the request reliably works, but there is a strange delay.

Please see the output below:

Performing HTTPS GET request... [1063451] modemSend called 
[1063462] modemSend waitResponse> called 
[1063477] modemSend waitResponse CCHSEND called 
[1065489] modemSend called 
[1065490] modemSend waitResponse> called 
[1065498] modemSend waitResponse CCHSEND called 
[1067507] modemSend called 
[1067508] modemSend waitResponse> called 
[1067522] modemSend waitResponse CCHSEND called 
[1069534] modemSend called 
[1069535] modemSend waitResponse> called 
[1069549] modemSend waitResponse CCHSEND called 
[1071562] modemSend called 
[1071563] modemSend waitResponse> called 
[1071574] modemSend waitResponse CCHSEND called 
[1073583] modemSend called 
[1073584] modemSend waitResponse> called 
[1073594] modemSend waitResponse CCHSEND called 
[1075603] modemSend called 
[1075604] modemSend waitResponse> called 
[1075619] modemSend waitResponse CCHSEND called 
[1077633] modemSend called 
[1077634] modemSend waitResponse> called 
[1077645] modemSend waitResponse CCHSEND called 
[1079656] modemSend called 
[1079657] modemSend waitResponse> called 
[1079670] modemSend waitResponse CCHSEND called 
[1081682] modemSend called 
[1081683] modemSend waitResponse> called 
[1081697] modemSend waitResponse CCHSEND called 
[1083707] modemSend called 
[1083708] modemSend waitResponse> called 
[1083722] modemSend waitResponse CCHSEND called 
[1085735] modemSend called 
[1085736] modemSend waitResponse> called 
[1085749] modemSend waitResponse CCHSEND called 
[1087761] modemSend called 
[1087762] modemSend waitResponse> called 
[1087773] modemSend waitResponse CCHSEND called 
[1089783] modemSend called 
[1089784] modemSend waitResponse> called 
[1089796] modemSend waitResponse CCHSEND called 
[1091808] modemSend called 
[1091809] modemSend waitResponse> called 
[1091822] modemSend waitResponse CCHSEND called 
[1092129] modemGetAvailable   called 
[1092130] modemGetAvailable  +CCHRECV? called 
[1092142] modemGetAvailable  +CCHRECV?2 called 
[1092142] ### Available: 340 on 0
[1092142] modemRead  called 
[1092144] modemRead  CCHRECV called 
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 20 Jun 2023 22:42:08 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.4.33
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
X-Powered-By: PleskLin

30
{"status":200,"status_message":"OK","data":null}
0

[1092186] modemGetAvailable   called 
[1092198] modemGetAvailable  +CCHRECV? called 
[1092208] modemGetAvailable  +CCHRECV?2 called 
[1092210] ### Available: 4294957297 on 0
Response status code: 200
Response Headers:
    Server : nginx
    Date : Tue, 20 Jun 2023 22:42:08 GMT
    Content-Type : application/json
    Transfer-Encoding : chunked
    Connection : keep-alive
    X-Powered-By : PHP/7.4.33
    Access-Control-Allow-Origin : *
    Access-Control-Allow-Headers : Content-Type
    X-Powered-By : PleskLin
The response is chunked
[1092248] modemRead  called 
[1092250] modemRead  CCHRECV called 
[1092259] modemRead  called 
[1092260] modemRead  CCHRECV called 
[1092273] modemRead  called 
[1092275] modemRead  CCHRECV called 
[1092287] modemRead  called 
[1092289] modemRead  CCHRECV called 
[1092301] modemRead  called 
[1092303] modemRead  CCHRECV called 
[1092313] modemRead  called 
[1092315] modemRead  CCHRECV called 
[1092325] modemRead  called 
[1092327] modemRead  CCHRECV called 
[1092337] modemRead  called 
[1092338] modemRead  CCHRECV called 
[1092347] modemRead  called 
[1092349] modemRead  CCHRECV called 
[1092360] modemRead  called 
[1092362] modemRead  CCHRECV called 
[1092372] modemRead  called 
[1092374] modemRead  CCHRECV called 
[1092384] modemRead  called 
[1092385] modemRead  CCHRECV called 
[1092395] modemRead  called 
[1092396] modemRead  CCHRECV called 
[1092407] modemRead  called 
[1092408] modemRead  CCHRECV called 
[1092418] modemRead  called 
[1092420] modemRead  CCHRECV called 
[1092433] modemRead  called 
[1092434] modemRead  CCHRECV called 
[1092448] modemRead  called 
[1092450] modemRead  CCHRECV called 
[1092464] modemRead  called 
[1092465] modemRead  CCHRECV called 
[1092479] modemRead  called 
[1092481] modemRead  CCHRECV called 
[1092495] modemRead  called 
[1092496] modemRead  CCHRECV called 
[1092508] modemRead  called 
[1092510] modemRead  CCHRECV called 
[1092522] modemRead  called 
[1092524] modemRead  CCHRECV called 
[1092538] modemRead  called 
[1092539] modemRead  CCHRECV called 
[1092553] modemRead  called 
[1092555] modemRead  CCHRECV called 
[1092567] modemRead  called 
[1092568] modemRead  CCHRECV called 
[1092580] modemRead  called 
[1092582] modemRead  CCHRECV called 
[1092596] modemRead  called 
[1092598] modemRead  CCHRECV called 
[1092610] modemRead  called 
[1092611] modemRead  CCHRECV called 
[1092623] modemRead  called 
[1092625] modemRead  CCHRECV called 
[1092637] modemGetAvailable   called 
[1092638] modemGetAvailable  +CCHRECV? called 
[1092652] modemGetAvailable  +CCHRECV?2 called 
[1092652] ### Available: 0 on 0
[1092653] modemGetConnected called 
[1092654] modemGetConnected +CCHOPEN? waitResponsecalled 
[1092671] ************Modem is connected Found in sim7600 Library****************
[1092671] Dats is "api.mywebsite.com"
[1093138] modemGetAvailable   called 
[1093139] modemGetAvailable  +CCHRECV? called 
[1093154] modemGetAvailable  +CCHRECV?2 called 
[1093154] ### Available: 0 on 0
[1093154] modemGetConnected called 
[1093156] modemGetConnected +CCHOPEN? waitResponsecalled 
[1093172] ************Modem is connected Found in sim7600 Library****************
[1093173] Dats is "api.mywebsite.com"
Response:
{"status":200,"status_message":"OK","data":null}
Body length is: 48

The library appears to be filling up the buffer (CCHSEND) with only a handful of bytes, every 2 secs and it takes approx 30 secs to finish filling the buffer.

Here is the recorded TX RX UART data, showing 30 seconds of CCHSEND:

image

Then it reads the buffer back(CCHRECV) all in one go, fine. But then sends the following command 30 times, all receiving the same ERROR response from the SIM7600:

AT+CCHRECV=0,649\r\n ERROR\r\n

...executed 30 times in quick succession and then finishes with...

AT+CCHRECV?\r\n +CCHRECV: LEN,0,0\r\n\r\nOK\r\n

Why? It means that a simple HTTPS GET request is unnecessarily long. Any insight would be much appreciated.