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;