Arduino Library and Strings

Hi guys,
I have developed o sketch in arduino , and now i am trying to include it in a library.
However, in my sketch i use String objects. Is there any way to keep these "String objects logic " inside my arduino library or i have to convert everything to C++?
Thank you in advance!

Everything you've developed is C++, so it's hard to understand your question.

CaptainNemo:
Hi guys,
I have developed o sketch in arduino , and now i am trying to include it in a library.
However, in my sketch i use String objects. Is there any way to keep these "String objects logic " inside my arduino library or i have to convert everything to C++?
Thank you in advance!

As AWOL said, what you have now is C++ so there is nothing to convert. However, given the memory limitations of an Arduino microcontroller and the resource hogging and poor memory management of the String class it's not very friendly to write a library that uses String objects. In the world of PCs with gigabytes of RAM it's not an issue. But on a microcontroller with only 2K for the heap and the stack to share it can cause issues in larger programs where your library might be used. And given that the offending code would be inside a library the end user may not notice what you've done there and may just say that your library is not working. It would be much nicer to the end user for you to refactor that code to use c-style strings (null terminated char arrays) instead to save on resources and memory.

AWOL:
Everything you've developed is C++, so it's hard to understand your question.

Well...to be more specific....
In my Arduino approach, I used String class and indexOf() function to search for a character inside a string.
What i was asking, (probably with wrong way...) was if i could use this implementation to search inside my library, or if i have to reconstruct my code to use " a string out of an array of type char and null-terminate it". In anyway, Delta_G is absolutely right. It is clear for me now that i have to reconstruct my code in a more efficient approach.

Yes, it is possible to use a String object in your library. But it's a lot faster and a lot less memory hungry to use C style strings instead.

An “index-of” function should be extremely easy to write for char arrays.

It's already written for you. strchr - C++ Reference

MorganS:
It’s already written for you. strchr - C++ Reference

That returns a pointer. The OP will want to know how to convert that to an index.

aarg:
That returns a pointer. The OP will want to know how to convert that to an index.

Just subtract the pointer to the start of the string.
Instant index.

Hi guys,
After your very useful comments/suggestion I restructured my library code using c style strings arrays.
The library is now functional and ready to use. However I have a question.

A brief description of the functionality:
*In my implementation I use an array of integers where I store measurements from an RF receiver. *
For the time being, I store 150 sequential measurements and afterwards I check this array trying to
extract a valid measurement. If no valid measurement has been received the code reads next
150 measurements and the story goes on and on until a correct measurement is received.

In case the implementation is performed without the use of my new library, the sketch size is
correctly calculated from Arduino IDE, and if the size of my array exceeds 150 I get an error
that the sketch size is too big. However when I implement the same logic using my library
(the initiation of array size is performed inside my lib) , it seems that Arduino IDE can’t calculate
the required sketch size. For example, when I initialize my array size 150 or 1500 ( inside my lib)
after program compilation, my sketch the size remains the same…. Which is strange for my….
Any thoughts on my issue?

However when I implement the same logic using my library

Would that be the library you didn't post or provide any details of?

Did you utilize the array? The compiler has an optimizer which omits unused code and objects. But yeah, it's a wild guess without seeing the code.

ok …bellow you can find my lib code

RF433::RF433(int PIN) // sets the RX pin
{
  RXPIN = PIN;
  pinMode(RXPIN, INPUT);
}
// Public Methods //////////////////////////////////////////////////////////////

float RF433::getTemperature()
{
  int timings[buffer_size];
  captured_state = false;
  int i = 0;
  Temperature= 0.0;
  int counter;
  while (pinstate == 1)
  {
    pinstate = digitalRead(RXPIN);//wait until pinstate=0
  }
  while (i < buffer_size) {
    counter = 0;
    while (pinstate == 0)
    {
      counter++;
      pinstate = digitalRead(RXPIN);
    }

    if (counter > BIT0_LENGTH - DEVIATION / 2 && counter < SYNC + DEVIATION / 2)
    {
      timings[i] = counter;
      i++;
    }
    counter = 0;
    while (pinstate == 1)
    {
      pinstate = digitalRead(RXPIN);
    }

  }
  /*
  *********print buffer*****************
  for (int i = 0; i < buffer_size; i++)
  {
     Serial.println(timings[i]);
  }
  *********print buffer*****************
*/
  i = 0;
  while ( i < buffer_size && captured_state == false )
  { 
    if (timings[i] > SYNC - DEVIATION && timings[i] < SYNC + DEVIATION && i + 33 < buffer_size)
    {
      for (int k = 1; k < 34; k++)
      {
        if (timings[i + k] > (BIT1_LENGTH - DEVIATION) && timings[i + k] < (BIT1_LENGTH + DEVIATION)) {
          bitreceived = '1';
        } else if (timings[i + k] > (BIT0_LENGTH - DEVIATION) && timings[i + k] < (BIT0_LENGTH + DEVIATION)) {
          bitreceived = '0';
        } else if (timings[i + k] > (SYNC - DEVIATION) && timings[i + k] < (SYNC + DEVIATION)) {
        }
        else {
          bitreceived = '?';
        }
        captured_data[k - 1] = bitreceived;
      }

      //checks of captured data
      char *ret;
      ret = strchr(captured_data, '?');
      bool corrupted = 0;
      if (ret != NULL)
      {
        corrupted = 1;
      }
	  
	  
	  
	  
      if (corrupted == 0)
      {
			for(int i=8;i<16;i++)
				test[i-8]=captured_data[i];
			
			
           if(test=="10000000")
		   {
			
			if (crc(captured_data))
			{
			captured_state = true;
			Temperature = bintodec(captured_data);
			}
			
		   }
      }
    }
    i++;
  }

  return Temperature;
}


float RF433::bintodec(char input[])
{
  float  value = 0;
  for (int i = 16; i < 24; i++)
  {
    if (input[i] == '1')
    {
      value = value + pow(2, 23 - i);
    }
  }
  return value / 10;
}

bool RF433::crc(char  input[])
{
  char x ;
  int checksumcalc = 0;
  for (int i = 30; i > -1; i--) {
    x = input[i];
    if (x == '1')
    {
      checksumcalc = checksumcalc ^ 1;
    }
    else
      checksumcalc = checksumcalc ^ 0;
  }
  x = input[31];
  int y = x - '0'; //convert char to string
  if (y == checksumcalc)
    return true;
  else
    return false;
}

float RF433::getTemperature2()
{
  float temp;
  int i = 0;
  do
  {
    temp = getTemperature();
    i++;
   } while (temp == 0.0 && i < 100);

  return temp;



}

and the header

class RF433
{
  // user-accessible "public" interface
  public:
    int pinstate =1;
	int RXPIN;
	int buffer_size = 120;
    char captured_data[33];
    char bitreceived;
    bool captured_state;
    int SYNC = 1800;
    int BIT1_LENGTH = 780;
    int BIT0_LENGTH = 390;
    int DEVIATION = 200;
    float Temperature= 0.0;
	
    RF433(int RXPIN);
    float getTemperature();
	float getTemperature2();
	float bintodec(char  input[]);
	bool crc(char input[]);
};
RF433::RF433(int PIN) // sets the RX pin
{
  RXPIN = PIN;
  pinMode(RXPIN, INPUT);
}

When is your constructor called, relative to when init() is called to get the hardware ready? If you do not know, or are not absolutely sure that the constructor is only called after init(), do NOT do pinMode() in the constructor.

    RF433(int RXPIN);
    float getTemperature();
	float getTemperature2();
	float bintodec(char  input[]);
	bool crc(char input[]);
};

Your tab key appears to be having issues.

      char *ret;
      ret = strchr(captured_data, '?');

Was there really a need
to use two lines to do this?

      if (corrupted == 0)
      {
			for(int i=8;i<16;i++)
				test[i-8]=captured_data[i];
			
			
           if(test=="10000000")

Drinking and coding don’t go together. If you must, at least use Tools + Auto Format to hide the evidence.

Without even looking at the type of test, I can tell you that the if test will NEVER evaluate to true. The address of the array is NOT ever going to equal the string “10000000”.

If test IS a NULL terminated array of chars, AND it is large enough to hold “10000000” and the NULL terminator, strcmp() is the way to compare strings.

Well you are totally right!
I wasn’t drunk …too much :slight_smile:
Anyway,comments … for your comments

  1. That was a mistake. I hadn’t realized that I should take care to call the constructor after init(). For safety reasons I followed your suggestion- I removed it from constructor.
  2. In notepad++ these particular lines of code seems to be aligned… anyway you win….i have a tab issue. Fixed!!
  3. No comments! Fixed!!
  4. This particular check is incomplete and of course wrong. I have not even declared test… I copied it by accident.
    However my question remains unanswered :slight_smile:

However my question remains unanswered

Well, this far after you posted it, and after so many code changes, perhaps you could re-ask the question.

Fair enough!

The question is:
As you can see in my lib, I declare the “int buffer_size = 120;”
It seems that even if I declare it to “int buffer_size = 1200;” (change it inside my lib)
the final sketch is not affected. On the other hand, when I do the same stuff with pure
commands (I mean that I implement the same code without using my lib), whenever
I declare this value higher than 150, I get an error from IDE about exceeding my global
variables size. For me it seems that when this declaration is performed inside the lib,
the compiler somehow can’t calculate the correct global variables size ….which seems strange for me…

It seems that even if I declare it to "int buffer_size = 1200;" (change it inside my lib)
the final sketch is not affected.

I would guess (and, mind you, this is only a guess) that the memory used information is computed by the IDE, not the compiler/linker. And, that the value is not based on scanning libraries.

On the other hand, when I do the same stuff with pure
commands (I mean that I implement the same code without using my lib),

The stuff in your library is just as "pure" as the stuff in the sketch.

For me it seems that when this declaration is performed inside the lib,
the compiler somehow can't calculate the correct global variables size ….which seems strange for me…

The compiler CAN allocate the proper amount of memory. That the IDE doesn't show that amount of memory is possibly due to a bug in how the IDE gets the information it shows.