0

is there a specific catch with storing Arduino String objects into a QueueArray? when I try the following code, Arduino just stops executing at "enqueue" function.

QueueArray <String> q;
String s = "blah";
q.enqueue(s);
Serial.println("checkpoint"); delay(1000);
Serial.println(q.peek()); delay(1000);

Same code works for storing integers, and even (char *). what am I missing?

Makan
  • 2,508
  • 4
  • 24
  • 39

1 Answers1

0

by inspecting the headerfile (only template functions, so also source): http://playground.arduino.cc/uploads/Code/QueueArray.zip

I believe the constructor of the queue gets you into this trouble. I have had troubles allocating objects in the queue.

I have decided to only put the references in there as a number, and then on the recieving end set that as the address value of a pointer of the object type. This is btw. a risky strategy!

why not just use enqueue the c_str attribute https://www.arduino.cc/en/Reference/CStr ?


Edit: this answer to a comment would bee too long:

The Arduino is a µProcessor and have a very limited memory (~2K). (32K for your program, and similar in flash).

Remember that it is also a machine with a limited memory management. so stack and heaps are both very small, and in general when the heap is used, it can get really fragmented very quickly.

As a C++ programmer that looks at your code, one might expect that the string is in fact stack allocated. (hint: there is no new keyword in there) so even if it internally would hold characters in the heap, this should allow you to assume that the string object would be destroyed when you exit the scope.

(you should also expect that it would clean up after it self, and deallocate the dynamic memory used for characters. Depending on your version of the libraries, this does in fact work, or there is a problem with re-allocate / deallocate, making stuff worse than we need to discuss here..)

learn the difference between heap and stack: C++ Object Instantiation

you can do something with arduino strings minimize the ehap fragmentation, like reserving memory before doing string operations.

But every time you decide to use a string, you will most likely fragment the heap, especially if you let it stay alive after scope is exited (for use on the other end of the queue).

To avoid the fragmentation issues, (remember it's a small system), you could use enums or similar for predefined messages. However if you insist that you actually need to enqueue a string I have a better suggestion.

You could create a small global array of strings, to hold the strings that will be enquede. (whis will ofcourse limit the queue size, since no more messages can be in the queue, than the array of string objects allow.. This array will be stack allocated, but the characters referenced by each string would be heap allocated. This allows you to let the reader of the queue clear the string, and thus free memory on the heap. However as the array never leaves scope, the strings are never automatically deleted by the sender. You would have to actively clear the string after recieving the string. For this solution, there will be some constant overhead on the stack.

Alternatively (and in my opinion much better, since fragmentation is non-existing), you could use something like a global character buffer, reserved to allocating messages that is being transferred. Before enqueueing, append the new message (c-styled null terminated string) after the last one currently in the buffer. The queue should contain the pointer to the message in the char array.

You must always test if there is room in the buffer for the string, before allocating some new message.

The way I do this is by having a global "recieved" pointer, that the worker will update when it reads the message. It simply moves the pointer to the strings ending null character, when it's done treating it.

The producer will then have another local pointer used for remembering where it wrote the last time it wrote something. Since the recieved pointer is global, the producer can always calculate the "distance" available between the pointers, and know how many characters can be written to the message buffer..

This is a simple circular buffer, so you need to handle overflowing etc. by adding a read and a write method.

Community
  • 1
  • 1
Henrik
  • 2,180
  • 16
  • 29
  • Good option, A basic Question though: If the function scope is finished, does the String object get "destroyed"? (if so, the CStr pointer is no good also. Hence, QueueArray is of no use either.) – Makan Nov 20 '15 at 13:12