I have made some test firmware that essentially spams Serial print as frequently as possible and sends a big json string to my PC, which I then track and graph using dearpygui (really good python based ui).
At the moment I am using Serial.println every 20 ms. I am having trouble checking vitals and using particle functions. Is this related to my overusing of Serial.println?
I have tried using System.thread(enabled) and without.
I think you might be overrunning the USB serial buffer. The default for USB serial is to block when the output buffer is full, which is probably affecting the system performance. The setting of blockOnOverrun defaults to true and affects this behavior.
However, if you don't block, excess data is discarded, which you also probably don't want. Instead, use availableForWrite to write your data in chunks only when there is enough room in the serial buffer to write the data.
Thanks Rick, I am sending a json string (~400 chars), seems like the buffer is 256, so this is most likely it.
I am going to try split my json in two halves and send them one after the other. I taught I was making my life easy for myself sending a json string, but i guess the bloat from the keys pushed me over the 256. I will revert back when solved.
What is the behavior of Serial.availableForWrite() when I am not connected to my PC via serial.
Will my delay watchdog function above ever reach the break statement?
EDIT: I am now trying to print to the Serial as fast as possible, but only printing when Serial.availableForWrite() is 256. I am also printing less than 256. But I am still seeing the same behavior, where after a few mins of running, I can no longer call vitals from the console or use particle functions.
I would inject the delay only when the free space "approaches" zero.
Otherwise you'd delay when there would still be 255 of 256 bytes to use even when you only intend to write less then that.
It's also not best practivce to "assume" the maximum size of your buffer, unless you have set your own buffer via acquireSerialBuffer().
I'd also not use delay() for that but rather go a non-blocking approach.
Just thinking out loud here, but would love your input. So to go non blocking, I could just check that Serial.availableForWrite() is greater than my char array. I have also split up my big json char array into two smaller jsons (there may be more jsons to come) so as to keep each Serial.println below 256. If I check Serial.availableForWrite() before printing, it may end up that I will always skip the second json if the first json hasn't cleared yet.
There are many possible ways to skin that cat, but one I'd consider is using the Serial.availableForWrite() result as len parameter for Serial.write(buf, len). This way you only ever send as many bytes as the buffer can take - obviously while keeping track what portion of your full payload you already sent and what should follow next.
I am still seeing the blocking behavior even though now I am printing less than 256 and only when the full buffer is available. I have also put Particle.process() before each print as well.
I am running SYSTEM_THREAD(ENABLED); and SYSTEM_MODE(AUTOMATIC);.
I am going to just make a completely empty project that spams serial similarly to what my app is doing and see if the issue persists. While overrunning the USB serial buffer may have exacerbated the issue, it may not be the only cause.
So while I may have been overrunning the serial buffer previously, I think something else is going on. I have implemented the following function that is run every iteration of the main loop.
If it was a blocking issue then I was hoping the above would solve the issue. The problem is that the device is breathing cyan, so thinks it's connected, but I cannot communicate with the device from the particle console, ie. vitals, signal or particle functions. So it seems like the device thinks that it is connected when it is not. I did read in the api that if particle.process is not being called enough that the device can think its connected when infact it is not.
Does anyone have any ideas how I can trouble shoot this a bit further?
Should I just force Particle process to run for x amount of time every loop?
If so, what would be an appropriate amount of time to call Particle process for to see if this resolves my issue?
Could this be a bad signal issue?
EDIT: One other thing I have noticed is that when I try to push a new firmware to device using workbench cloud flash, I still get the started event but it will fail to update. Does the started event mean that the cloud has successfully connected to the particle?
I am still seeing this weird behavior where the particle thinks its still connected to the cloud (breathing cyan), but I am unable to check vitals or call a particle function. When I try to flash a new firmware to the device in this state, I will get a started on the event console, but it will always fail.
It seems like when it gets to this state, I can't just reset the device, I need to remove power and then put power back before it will connect again, once power is removed and replaced, it connects no problem.
The instructions for Particle.process are mostly only relevant when not using threading mode, or using MANUAL mode, neither of which are recommended. Under normal circumstances you should never need to call it.
I didn't see a mention of the kind of device, but cellular devices can go up to the keep-alive period (23 minutes) without realizing that they can no longer be communicated to from the cloud side. So it's not unexpected that cellular devices could breathe cyan and not be able to be communicated with from the cloud side.
The mostly likely two possibilities are:
There actually is a cellular issue which is preventing the cloud from communicating with the device. This could be debugged using the USB serial logs, except you're also using them for other purposes so you might need to find a different way.
The other is some code path that prevents the loop() function from returning. This will prevent a number of cloud operations like calling functions from working properly because these are dispatched between calls to loop. You should try to return from loop as often as possible, even with threading enabled.
However, since resetting the device does not solve the problem, there's a third possibility. The difference between reset and removing power is that the cellular modem is reset only on removing power, not after pressing the reset button or System.reset(). Something is likely causing the cellular modem to not work properly, which would also explain not being able to communicate from the cloud. For this you really want to be able to see the LOG_LEVEL_TRACE calls from Device OS. If you are not using the UART serial port, you could redirect those logs to UART TX and use a FT232-type 3.3V UART to USB adapter to view the logs.
Sorry I was mistaken here. If I reset the device (B5SOM) it will think its connected, ie. it passes Particle.connected() and breathes cyan, but the issue where i am unable to check vitals, call particle functions or flash new firmware persists.
See below for a log trace, for when I restart the device until it thinks its connected.