E-Series resetting after publish

He already has here (note that I am not currently using SYSTEM_THREAD): Electron SLEEP_MODE_DEEP tips and examples. Also, that post doesn't suggest a short delay. Let me know if either of you think I'm misinterpreting something there.

Sorry, "loop" was a poor word choice. I did not mean loop() and I do expect it to start from the beginning every time it wakes as you describe. But I don't suspect that is necessarily related. What I meant by loop, rather, was that it should stay within case SYSTEM_STATE_DATA_UPLOAD: (see full case code below if you wish to dig in that deeply...) as long as bin_file.length() is not equal to zero (there are a couple other conditions that cause it to break but that's the main one that I was using to describe this inner while loop).

I've checked a handful of the other causes for a break from that case and none of them are occurring, which I can confirm individually by working out the byte-by-byte behavior manually or, more conclusively, for all cases having seen that it works properly for a given file sometimes even after not working (that is, resetting) for that same exact file and same exact messages sometimes.

////////////////////////////////////////////////////////////////////////////////
      case SYSTEM_STATE_DATA_UPLOAD:
      // upload data bit by bit either by serial or data upload

      // Some notes on this...
      // Data upload is done by uploading the very last chunk of data in the file
      //  and then truncating it.  This allows us to have a good "lost connection/partial upload scheme"
      //  as what is uploaded is removed from the file.  Files are natually uploaded in order of
      //  the last file in the SPI   Data is stored in 496byte "blocks" and data doesn't
      //  span across blocks, so data upload can be asyncronous, even within the file
      //  Also, data is compressed using base85 before being uploaded.

#if USING_CELL_NETWORK_UPLOAD
      // make sure that we are connected to the cloud and not doing more than 1/sec
      while(Particle.connected() && ((millis() - time_of_init_state_exit_ms) > 1000))
#else
      // make sure we are not outputting (over serial) more than 1x/sec
      while(((millis() - time_of_init_state_exit_ms) > 1000))
#endif
      {
        // multiple byte read
        // if the file's length is not divisable by the block length (496)
        if ((bin_file.length() % MAX_SPI_DATA_BLOCK_LENGTH) != 0)
        {
          // seek to the last chunk of data after blocks of 496
          bin_file.lseek(-1 * (bin_file.length() % MAX_SPI_DATA_BLOCK_LENGTH), SPIFFS_SEEK_END);
          // grab the data chunk
          num_of_bytes_to_encode = bin_file.readBytes((char *)data_to_encode, (bin_file.length() % MAX_SPI_DATA_BLOCK_LENGTH));
        }
        // otherwise just grab the last block of the file
        else
        {
          // seek to the last MAX_SPI_DATA_BLOCK_LENGTH of data and read it in
          bin_file.lseek((-1 * MAX_SPI_DATA_BLOCK_LENGTH), SPIFFS_SEEK_END);
          num_of_bytes_to_encode = bin_file.readBytes((char *)data_to_encode, MAX_SPI_DATA_BLOCK_LENGTH);
        }

        // pad with zeros till we have multiple of 4 for even conversion to b85
        //  IMPORTANT to keep track of how many extra so we don't truncate the file
        //    too much (multiple upload bug!)
        while (((num_of_bytes_to_encode + extra_bytes_to_encode) % 4) != 0)
        {
          data_to_encode[(num_of_bytes_to_encode + extra_bytes_to_encode)] = 0;
          extra_bytes_to_encode++;
        }

        // print out data to encode
        Serial.println("Data to Encode: (" + String((num_of_bytes_to_encode + extra_bytes_to_encode)) + "bytes)");
        for(int i = 0; i < (num_of_bytes_to_encode + extra_bytes_to_encode); i++) Serial.print(data_to_encode[i]);
        Serial.println();

        // convert to base85
        // function returns a pointer to a \0 at the end of the string
        //  ...so, subtracting the data_to_publish pointer gives us how many chars
        //  we should publish
        num_of_bytes_to_publish = (bintob85( data_to_publish, data_to_encode, (num_of_bytes_to_encode + extra_bytes_to_encode)) - data_to_publish);


        if (upload_num > MAX_NUM_UPLOADS)
       {
         Serial.println("Upload number > MAX_NUM_UPLOADS, deleting file and exiting!");

         // remove the uploaded file
         bin_file.remove();
         bin_file.close();

         // reset the upload attempts so it doesn't try on reboot
         num_upload_attempts_remaining = -1;

         // go to deep sleep
         glo_next_system_state = SYSTEM_STATE_DEEP_SLEEP;
         break;
       }
////////////////////////////////////////////////////////////////////////////////



      // print out data to publish that has been enocded
      Serial.println("Data to Publish: (" + String(num_of_bytes_to_publish) + "bytes)\n" + String(data_to_publish));

      // generate the publish id
      strcpy(publish_id, ("Sfin-" + String(glo_device_id) + "-" + bin_file_name + "-" + String(upload_num) + "\0")); // PJB commented out

      // print out publish ID to screen
      Serial.println(publish_id);

      // publish data
// #if USING_CELL_NETWORK_UPLOAD
      // I think a good idea is to use the MAC address of the device + date/time (filename)
      // if the publish is a success....
      // Serial.println("trying to publish...");
      if (Particle.publish(publish_id, data_to_publish, 60, PRIVATE))

// #endif
        {

          Serial.println("Publish Success");

          // increment upload number
          upload_num++;
          // truncate the file
          bin_file.truncate(bin_file.length() - num_of_bytes_to_encode);
          bin_file.flush();

          // reset "no upload" timeout timer
          time_of_init_state_exit_ms = millis();
        }

// #if USING_CELL_NETWORK_UPLOAD
        // if the publish wasn't successful
        else
        {
          // basically, don't truncate the last bit of the file so it will retry.
          // reset "no upload" timeout timer
          time_of_init_state_exit_ms = millis();
        }

        // keep connection alive (do once every 20 seconds or more often)
        Particle.process();
// #endif

        // Debugging info about file length.
        Serial.println("File Length = " + String(bin_file.length()));

        // if we have uploaded the entire file, close the file and go to sleep?
        if (bin_file.length() == 0)
        {
#if USING_CELL_NETWORK_UPLOAD
          // publish a EOF success event (TODO)
          //  if (Particle.publish(publish_id, data_to_publish, 60, PRIVATE))
#endif
          {
            Serial.println("File fully published, deleting file: ");

            // remove the uploaded file
            bin_file.remove();
            bin_file.close();

            // probably check to make sure there aren't any more files to upload (TODO)

            // reset the upload attempts so it doesn't try on reboot
            num_upload_attempts_remaining = -1;

            // go to deep sleep
            glo_next_system_state = SYSTEM_STATE_DEEP_SLEEP;
            break;
          }
        }
      }


      // if we aren't connected and CELL_SIGNAL_TIMEOUT_MS has gone by without a publish event
      //  shut the system down for a later reattempt
#if USING_CELL_NETWORK_UPLOAD
      if (!Particle.connected() && (millis() > (time_of_init_state_exit_ms + CELL_SIGNAL_TIMEOUT_MS)))
#endif

      if ((millis() > (time_of_init_state_exit_ms + CELL_SIGNAL_TIMEOUT_MS)))
      {
        // if this is the first failure (num_upload_attempts_remaining == -1)
        //  setup the number of reattempts to try and send to deep sleep
        if (num_upload_attempts_remaining == -1)
        {
          num_upload_attempts_remaining = NUM_UPLOAD_ATTEMPTS_MAX;
        }
        glo_next_system_state = SYSTEM_STATE_DEEP_SLEEP;
      }
      break;