[Solved] Problem using sprintf on spark

I’m trying to use NRF24L01+ to send data from my sensors to the spark core. They work fine and I can get data from them individually and they are also constantly updated. This is part of the code.

if (radio.available())
{
   bool done = false;

       while (!done)
     {
       done = radio.read(data, sizeof(uint16_t)+1);
     }

    if (data[0] != 'NULL'){

      char transmitter = data[0];
      uint16_t sensorValue = data[2] | data[1] << 8;

      if (transmitter == 'A'){

        moistureA = sensorValue;

        } else if (transmitter == 'B') {
        
        moistureB = sensorValue;

        }
    
        delay(1000);
} else {

Serial.println("No radio available...");

}

However, the moment I add in this line

sprintf(message, "{\"SmartGarden\":{\"moistureA\":\"%d\",\"moistureB\":\"%d\",\"temperature\":\"%d\",\"humidity\":\"%d\"}}",moistureA,moistureB,temperature,humidity);

to combine all my sensor values into 1 variable to output as a JSON, the whole thing seems to break and can only read the data once and it stops updating. My received variables are all being sent to a variable in the spark called sensorValue.

I’m not sure but after narrowing it down the problem could be in the fact that all values are being sent to the variable called sensorValue or it could be the problem with sprintf itself since it breaks when I add that. Any ideas?

[Mod Edit - Solution - @HarrisonHJones]
Character array message was a little too short. Changing char message[80] to char message[150] fixed the problem. The desired string now fits inside of the allocated memory and sprintf does not overflow the buffer.

How large is your message array variable? Where and how is it declared?

I’m not sure which one you’re referring to but one is before the void setup like so

char message[80];

this was originally 50 but I increased it to 80 in case it was due to the length exceeding. The other is inside void setup like so

Spark.variable("message", &message, STRING);

Thank you.

By my count you’ve got far more than 80 characters up in there. Spark.variable can handle 622 bytes of data in a string so let’s make the char buffer MUCH larger. How about 150 characters? Let me know how that goes

Alright. After trawling through the forum, I found this post in which the OP is using a sprintf as well. As I’m new to spark and programming in general I have not idea why but when I used the method he uses in the last post which is

char message[80];
char *messagePtr = message;

in void setup

Spark.variable("message", messagePtr, STRING);

and lastly in loop

sprintf(messagePtr, "{\"SmartGarden\":{\"moistureA\":\"%d\",\"moistureB\":\"%d\",\"temperature\":\"%d\",\"humidity\":\"%d\"}}",moistureA,moistureB,temperature,humidity);

it works.

The problem is solved then. However, if you could spare the time would you be able to explain to me the differences between the old and new code? Thank you so much.

I have no idea why that works (and what you have currently doesn’t more specifically). Someone more knowledgeable than I when it comes to C/C++ will need to respond.

message is simply a pointer to a location in memory. Grabbing the value of message will return an address. By dereferencing that address you can get the value of your char array (the first char actually). Interestingly both message and &message have the same value so my original suggestion to replace

Spark.variable("message", &message, STRING)

with

Spark.variable("message",message,STRING)

seems worthless (but probably worth a try if you have a second)

That being said I’m still worried that you are going to overflow your message buffer there. When you query the variable what do you get in response? Is that response over 80 characters? If so you could clobber some important variable at some point in the future.

Hi thanks so much. After testing with your suggestion and the method I found, it seems like as you said the problem lies with the character count. When I increased it to 150 and removed the & it works like a charm. Turns out the fix was so simple after all! Thanks again!

1 Like

You are so welcome! Have fun with your core!

1 Like

@harrisonhjones and @suckms, just a tiny clarification. When an array is specified (eg. message[80]) without an index, you are referencing the address of the first element of that array. You can also specify this address by using &message[0]. Using &message with no index specifies the address pointed to by the first elements of the array, which is not quite what you want. :wink:

2 Likes

Ok. And just to clarify further do you mean this:

Lets say message is being stored in memory location 0xFE. And it’s values are 0x61, 0x21, 0x43, etc…

So is the following correct:
message = 0xFE
&messsage[0] = 0xFE
&messsage[1] = 0xFF
&message = 0x61

Is that correct?

@harrisonhjones, correct except for &message which would be the address pointed to by the 32bit pointer (ie the first four bytes) made up of message [0],[1],[2],[3]. Confuses the hell out of me since this only applies to arrays and not single vars! So for “int somevar”, the address of somevar is &somevar. :smile:

2 Likes

I think it's neither 0x61 nor 0x612143.. (if I interpret @peekay123 's [0],[1],[2],[3] correctly). It rather would be 0xFE again.

For example this code

int a = 0;
int b;
char message[20];
int c;

void setup()
{
    
    Serial.begin(115200);
    while(!Serial.available())
        SPARK_WLAN_Loop();
        
    strcpy(message, "a!C&somemore");
    Serial.println((long)&a, HEX);
    Serial.println((long)&b, HEX);
    Serial.println(message);
    Serial.println(message[0], HEX);
    Serial.println(message[1], HEX);
    Serial.println(message[2], HEX);
    Serial.println(message[3], HEX);
    Serial.println((long)message, HEX);
    Serial.println((long)&message[0], HEX);
    Serial.println((long)&message[1], HEX);
    Serial.println((long)&message, HEX);
    Serial.println((long)&c, HEX);
}

void loop() { }

produces this output (not easy to place the array at 0xFE ;-))

2000048C
20000490
a!C&somemore
61
21
43
26
20000478
20000478
20000479
20000478
20000494

And… now I’m confused. @peekay123 would you mind commenting when you get a chance? Thanks!

@harrisonhjones, @ScruffR just gave me a migraine and I have no comments at this time :stuck_out_tongue:

The confusion is not uncommon :wink: :dizzy_face: :dizzy: I know why it is but I’m always stumped for words, how to explain it somwhat understandable.
Let me think about it - especially of how to say in my non-native language :wink: - I’ll come back to you :zzz:

I hope I’m not making a complete fool of myself and can bring across what I think to understand and intend to tell :wink:


I guess things are in fact a bit more complicated, but this should come pretty close.
The thing is, that the compiler does need a repository of all variables it needs to take care of.

This can be seen as a lookup table where the locations of these variables are stored and when you want to retrieve the value of a variable the compiler knows that it needs to follow the pointer stored in its own lookup table to find the actual memory location. On the other hand when you apply the & operator to a variable name we tell the compiler to show us the contents of the respective cell in its lookup table.
This said, this applies to “normal” variables and even pointer variables.

In case of pointer variables the compiler needs two “hops” to find the desired memory location (lookup table -> pointer value -> memory location).

And while arrays can be seen as pointers the compiler treats them differently, since it usually already knows the location in memory at compile time - unlike propper pointers which usually tend to keep changing the address they are pointing to.
So it just “drops” the middle man (lookup table -> not needed -> memory location) and the contents of the lookup table is actually the pointer to the memory location of the first byte of the array.

Consequently when applying the & to the array-name the compiler shows you - as for other variables too - the contents of its lookup table cell which in fact contains the address of the array start.

On the other hand when you only write the array name without any operator the compiler needs to act as if it hadn’t dropped the middle man and has to give you the address again.

Now when you apply the [] operator the compiler has to interpret this the same way as the * deref operator with a normal pointer, but since it’s missing the middle man again it will apply the deref to the pointer in its lookup table.

And finally when doing both & and [] you actually instruct the compiler to give you the address of the dereferenced pointer which in turn is the pointer value itself, which is the contents of the lookup table cell.

Hence array == &array== &array[0] and array[0] == *array


I hope this makes things somehow understandable - even if it’s completely wrong :stuck_out_tongue_winking_eye:

But I could have had it easier if I first googled. Then I might have found this and hadn’t come up with the longwinded story above :wink:
http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=aryptr

1 Like