1

I have a string: String outputValue = "" that I then append to to build a JSON-like structure to send to a remote device. This code runs on an ATMEGA328P using the Arduino bootloader. I append values by doing outputValue += "hello".

The library I am using to send the values needs a uint8_t * for it's payload with the associated length of that payload. Is there any way to cast/convert this String to a uint8_t array or is there a preferred way to do a builder rather than using String? I'm open to any suggestions

My working code that I used to test the library has the following. Note, this is just the result of me copying the raw outputValue to Notepad, enclosing each character in single quotes, then hardcoding this new array to test:

uint8_t testCmd[] = { '{', '"', 'T', '"', ':', '"', 'A', '1', '"', ',', '"', 'E', '"', ':', '-', '1', ',', '"', 'I', '"', ':', '[', '[', '1', ',', '[', '[', '[', '[', '2', '5', '0', ',', '2', ']', ',', '[', '0', ',', '4', ']', ']', ']', ']', ']', ']', '}' };

ZBTxRequest txReq = ZBTxRequest(coordinatorAddr64, testCmd, sizeof(testCmd));   
ZBTxStatusResponse txResp = ZBTxStatusResponse();

xbee.send(txReq);
Justin
  • 24,288
  • 12
  • 92
  • 142
Phillip McMullen
  • 453
  • 2
  • 5
  • 15
  • 2
    What `String` type is this? Also, use a serialization library/framework! https://stackoverflow.com/a/11486538/461597 uses protobuf for arduino. – Unapiedra May 02 '18 at 23:28

2 Answers2

3

Yes there is.

Do something like this:

String testString = "Test String";
uint8_t* pointer = (uint8_t*)testString.c_str();
int length = testString.length();

EDIT:

You should apply it to your problem as follows:

String testString = "Test String";
uint8_t* pointer = (uint8_t*)testString.c_str();
int length = testString.length();

ZBTxRequest txReq = ZBTxRequest(coordinatorAddr64, pointer, length);   
ZBTxStatusResponse txResp = ZBTxStatusResponse();

xbee.send(txReq);
Ricardo Alves
  • 1,071
  • 18
  • 36
  • This will work, assuming `String` even has a `c_str()` method that returns a pointer to the raw character data, and it is using 8-bit characters. If `String` is using 16/32-bit characters instead, you will have to multiple the `length` by the character size, assuming the library is expecting a byte count and not a character count. Or encode the `String` data to an 8-bit format, like UTF-8. Also, you probably should be casting to a `const` pointer – Remy Lebeau May 02 '18 at 23:33
  • For arduino, it indeed uses 8bit characters on strings. – Ricardo Alves May 02 '18 at 23:34
  • The Arduino might be using 8-bit strings, but the OP didn't say which `String` class is being used in his C++ code. `String` is not a standard C++ string (that would be `std::string` instead). For all we know, `String` could be a 3rd party Unicode string class instead. – Remy Lebeau May 02 '18 at 23:36
  • Yes you are right, but I highly doubt it since memory on microprocessors are a very very very precious resource. Still, it really can be. – Ricardo Alves May 02 '18 at 23:38
  • The pointer returned from `c_str()` could also be invalid immediately. Better to copy the data to make sure it stays valid until the response is completed. – Retired Ninja May 02 '18 at 23:39
  • @RetiredNinja that would only be the case if `testString` is modified, or goes out out scope, after `c_str()` is called and before the character data is read from `pointer`. If you do something like `ZBTxRequest txReq(coordinatorAddr64, (uint8_t*)testString.c_str(), testString.length());`, that would certainly not be the case. – Remy Lebeau May 02 '18 at 23:40
  • @RemyLebeau Not necessarily. Without knowing how the underlying class is implemented you can't be sure unless it offers the same guarantees as `std::string`. There are implementations that construct the null terminated buffer on demand, and you either copy it or lose it. – Retired Ninja May 02 '18 at 23:42
  • Worked like a charm, thanks everyone! It was an arduino String class FYI for anyone referencing this. – Phillip McMullen May 03 '18 at 18:00
1

You can write your array like this:

uint8_t testCmd[] = R"({"T":"A1","E":-1,"I":[[1,[[[[250,2],[0,4]]]]]]})";

The difference is that it will have 48 elements instead of 47 like your original one, because of terminating 0. Since you are providing the length of packet you could -1 it:

ZBTxRequest txReq = ZBTxRequest(coordinatorAddr64, testCmd, sizeof(testCmd) - 1);   
ZBTxStatusResponse txResp = ZBTxStatusResponse();

xbee.send(txReq);

Looking at Arduino reference. String object has c_str() method as well as length(). So you can simply try:

String testCmd R"({"T":"A1","E":-1,"I":[[1,[[[[250,2],[0,4]]]]]]})";

ZBTxRequest txReq = ZBTxRequest(coordinatorAddr64, (uint8_t *)testCmd.c_str(), (uint8_t)testCmd.length());   
ZBTxStatusResponse txResp = ZBTxStatusResponse();

xbee.send(txReq);
Killzone Kid
  • 6,171
  • 3
  • 17
  • 37