vshymanskyy / TinyGSM

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

Improvement which prevents infinitive while loop #691

Open sw-dev-code opened 1 year ago

sw-dev-code commented 1 year ago

Thru the development using ESP32 and SIM7070, we were faced with a problem in which the device was stuck in an infinitive loop while waiting for data from the SIM module.

The issue was solved by making updates on two files TinyGsmFifo.h and TinyGsmTCP.h. Updates include the implementation of timeouts to prevent an infinitive loop.

Below you can see the critical points which were changed. My proposal is to take a consideration of implementing this changes in future versions.

TinyGsmFifo.h

    int get(T* p, int n, bool t = false)
    {
        unsigned long startTimeMs = millis();
        int c = n;
        while (c)
        {
            int f;
            for (;;) // wait for data
            {
                f = size();
                if (f)  break;        // free space
                if (!t) return n - c; // no space and not blocking
                /* nothing / just wait */;
                if (millis() - startTimeMs > 5000) 
                    return n - c;

                delay(1);
            }
            // check available data
            if (c < f) f = c;
            int r = _r;
            int m = N - r;
            // check wrap
            if (f > m) f = m;
            memcpy(p, &_b[r], f);
            _r = _inc(r, f);
            c -= f;
            p += f;
            startTimeMs = millis();
        }
        return n - c;
    }

TinyGsmTCP.h

#elif defined TINY_GSM_BUFFER_READ_AND_CHECK_SIZE
      // Reads characters out of the TinyGSM fifo, and from the modem chips
      // internal fifo if avaiable, also double checking with the modem if
      // data has arrived without issuing a UURC.
      at->maintain();
      uint32_t _startMillis = millis();
      _timeout = 5000;
      ///while (cnt < size) 
       while ( (cnt < size) && (millis() - _startMillis < _timeout)) 
       {
        size_t chunk = TinyGsmMin(size - cnt, rx.size());
        if (chunk > 0) 
         {
          rx.get(buf, chunk);
          buf += chunk;
          cnt += chunk;
          continue;
         } 

        // Workaround: Some modules "forget" to notify about data arrival
        if (millis() - prev_check > 500) 
          {
          // setting got_data to true will tell maintain to run
          // modemGetAvailable()
            got_data   = true;
            prev_check = millis();
          }
        // TODO(vshymanskyy): Read directly into user buffer?
        at->maintain();
        if (sock_available > 0) 
        {
          int n = at->modemRead(TinyGsmMin((uint16_t)rx.free(), sock_available),
                                mux);
          if (n == 0) break;
        } else {
          break;
        }
      }//while
      return cnt;