I am using Particle.Subscribe and a handler function to listen to events published by my server.
However when the server goes down it sends back a HTML “Server not available” message. When this happens my Photon freezes. I think it is due to the size of the message which I have no control over - maybe causing the stack to overflow?
Is there a size limit on the data returned?
Is there any way I can ignore messages over a certain size?
Any other ideas of what could cause this behavior or how to debug it further?
@joe4465, any chance you can post the message? A webhook response can send back multiple 512byte payloads so that would be the limit on a single message I suspect. However, that message is buffered by the system so there is no buffer overflow. How you parse the message in your event handler may be the issue.
The issue seems to happen once the Photon has received about 80 messages sent once per second. When normal messages are received the code runs correctly.
I’m running a state machine with transitions triggered by the received messages (or lack of) so if the above looks correct the problem is probably with that.
I think the potential problems with heap fragmentation in the use of String also exist with std::string since both actually wrap up their own, internal buffers and have to move/reallocate the string if it outgrows the reserved area and since we are dealing with a microcontroler “OS” with (to say the least) less sophisticated garbage collection/heap defragmentation routines you might still end up with a highly fragmented heap preventing your application from allocating a new string or moving an existing string that outgrew its buffer.
This is all no problem on a fully fletched OS, hence you’ll find most programmers on that side to vouch for std::string (as I’d do there too), but on these devices I personally rather go the potentially more cumbersome but safer route, where I have full control over things
But in any case, if you know what you are doing, you can choose either way, just asses the risks and take precautions.
Looks good, but since we can’t see your functions handle...() it might be an idea to just set an FSM flag and move the actual calls out of the handler and have an FSM outside do the calling.
This would be something to ask Particle direct (maybe @mdma), but here my personal guess
Particle.function() was implemented some generations before Particle.subscribe() and only a while after the Spark Core got into the hands of people who tried to push the boundaries and squeeze every byte out of RAM, the implications of using String excessively became evident and there was no time or call to overhaul Particle.function()
But I might be completely off the beam, with this
…
Sure, you can pass a C string into a constructor, but instead of storing the address you might rather pull a copy of the string and store it in a private field (which could be a char[] or a dynamic buffer, with all the heap implications again).
Please could explain the second part a bit more, i.e. what is the correct way to have a global char array in a class that is assigned when the constructor is called.
It depends what you’ll do with this string inside your class.
When you mention “a global char array”, you’d have to go with a pointer, but have to make sure, that this string be safe to use at any time. But this somehow counteracts the encapsulation and self-sufficiency idea of OOP classes.
If you only want to pass in a string once so that the class can be constructed based on that string and thereafter owns the string, then you’d do something like this
class myClass
{
public:
myClass(const char* setupInfo);
private:
char __setupInfo[MAX_LEN];
}
myClass::myClass(const char* setupInfo)
{
int len = strncpy(__setupInfo, setupInfo, MAX_LEN);
if (len < 0 || len >= MAX_LEN)
{ // input string was too long, so manually terminate
__setupInfo[MAX_LEN-1] = '\0';
};
}
If you want to manipulate the string from outside, you’d need to provide a public (setter) method to do so.
And for reading the contents back, you also provide a (getter) method which should return a const char*.
I’d say these are the most common ways to do this, but there are others too (e.g. dynamic mem allocation)
char __setupInfo[MAX_LEN]; already reserves the memory space required to hold MAX_LEN-1 characters, while char* __setupInfo would only reserve a four byte portion to hold a pointer, which might point anywhere (or nowhere), but no space for the string will be reserved.