Convert string array to byte array

I am working on a project where I first need to build up the payload as a string then later on convert it to byte when sending the payload. I am having issues with conversion.

Reson why payload build-up is in string is due to the way it generates each single string, "02", "12", "31", "03" and "36" are the result after diffrent methods of calculations.

String lockHexString[5];  
lockHexString[0] = "02"; 
lockHexString[1] = "12"; 
lockHexString[2] = "31"; 
lockHexString[3] = "03"; 
lockHexString[4] = "36"

Now when I have lockHexString, I need convert the lockHexString to byteArray, so It looks like

byte lockByte[5] = {0x02, 0x12, 0x31, 0x03, 0x36};

UPDATE
Here is the documentation Im trying to follow:

The problem Im having is the calulation of the checksum (last byte) and as you can see, top open LOCK 1 och CONTROL UNIT 1 (CU), you send these following bytes:

TX(command):02 00 31 03 36 

Why do you need to do that? Strings often cause memory problems and unpredictable program crashes on AVR-based Arduinos, and we generally recommend to avoid using them.

Those calculations could undoubtedly produce character arrays rather than Strings. Tell us about them.

Are you aware that these two lines result in the same (binary) byte array?

byte lockByte[5] = {0x02, 0x12, 0x31, 0x03, 0x36};
byte lockByte[5] = {2, 18, 49, 3, 54};

you can use strtol to convert to byte indicating that the source is hex but I’m also curious why do you need to have String

Not true. Strings on AVR are very very reliable and DO NOT produce crashes on AVR micros. See Taming Arduino Strings

If you have a real example of Strings causing problems on AVR, please post it on a new topic.

Edit -- Having said that the snippet of code posted seems to be an odd use of Strings. Would like to see more of the code that produces those numbers.

@ drmpf Most people disagree with you, but do carry on the crusade for your arduous workarounds! You may find a few converts.

I have a feeling this is another case of XY problem

https://xyproblem.info/

@jremington Where are the examples of Strings causing crashes in that lot? None that I can see.
Strings DO NOT crash Arduino AVR micros unlike c-strings offered as the alternative.

That is easy enough to do, although it may not help the OP very much :

// String test - contrived to fragment the heap store
//  by asynchronously creating and destroying Strings
//  lasts about 6 seconds on a Uno (clone)


#include "TimerOne.h"

void callback ( ) {
  volatile String str = "Hello World" ;
}


void setup() {
   Serial.begin( 9600 ) ;
   Serial.println( "String Test" ) ;
   Timer1.initialize(100000);  // 10Hz
   Timer1.attachInterrupt(callback);
}

void loop() {
  uint32_t ms = millis() ;
  static uint32_t millis_last = 0 ;
  
  String str ; 
  str = "Hello World "  ;
  str += String( ms ) ;

  if ( ms % 1000 == 0 && millis_last != ms ) {
    Serial.println( str ) ;
    millis_last = ms  ;
  }
}

I have made an update to my original post with the documentation Im trying to follow.
If anyone as a good way of calculating the TX command to open a specific lock on a specific CU (control unit) Im open to it and would appreciate it.

The TX check sun is simply the addition of the previous 4 bytes ( mod 256).
In other words, simply add the 4 bytes in a Byte variable.

1 Like

As suspected, you are messing with String with no real reason, you need just "raw bytes" or rather just raw numbers.
The protocol used from your device is quite simple..

So according to the document, you have 3 type of commands avalaible:

  • 0x30 to get the status of specific locker
  • 0x31 to send open request to specific locker
  • 0x32 to get status and infrared sensor f all lockers on RS485 bus

Your request has to be long 5 bytes:

STX - ADR - CMD - ETX - SUM

STX is start byte "start of trasmission" and is equal to hex value 0x02
ETX is end byte "end of trasmission" and is equal to hex value 0x03
ADR is the address of target device
CMD is one of the 3 avalaible command listed before
SUM is an error checksum byte calculated simply as the sum(8bit) of bytes before

If you get the TX example from document 02 F0 32 03 27

SUM = 0x02 + 0xF0 + 0x32 + 0x03 = 0x0127
0x0127 is two byte long, but you need only less significative byte 0x27

In C++ just force the cast to byte data type:

byte ADR = 0x10;    // just an example address
byte CMD = 0x31;    // the command for open the locker
byte SUM = (byte) 0x02 + ADR + CMD + 0x03;
1 Like

Well that failure has nothing to do with fragmentation.
It is not String's fault that the interrupt is making reentrant calls to malloc/realloc which was not designed to support reentrant calls on AVR. Interrupts are an advanced programming technique, which comes with its own issues.

Adding the appropriate guard block makes the sketch run forever, as it should

// String test - contrived to fragment the heap store
//  by asynchronously creating and destroying Strings
//  lasts about 6 seconds on a Uno (clone)
// >>>>>> making an re-enterent call to malloc() :-(
//  so need to add guard block to prevent this

#include "TimerOne.h"
#include <util/atomic.h>
void callback ( ) {
  volatile String str = "Hello World" ;
}

void setup() {
  Serial.begin( 9600 ) ;
  for (int i = 10; i > 0; i--) {
    delay(500);
    Serial.print(i); Serial.print(' ');
  }
  Serial.println( "String Test" ) ;
  Timer1.initialize(100000);  // 10Hz
  Timer1.attachInterrupt(callback);
}
unsigned long count = 0;
void loop() {
  count++;
  uint32_t ms = millis() ;
  static uint32_t millis_last = 0 ;
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
    String str ;
    str += "\nHello World "  ;
    str += String(ms);
    if ( ms % 1000 == 0 && millis_last != ms ) {
      Serial.println(count);
      Serial.println( str ) ;
      millis_last = ms  ;
    }
  }
}

BUT..
You may still argue that a simplistic sketch using Strings has failed, and that is a fair enough stand to take, so and I will update Taming Arduino Strings to highlight that
a) it uses malloc/realloc and
b) malloc/realloc are not reentrant
so you should not use Strings in an interrupt context without taking the extra coding precautions needed.
Thanks @6v6gt for highlighting this.

@drmpf I'm happy to read this sentence expecially from an experienced user as you are.

As my experiences, I have been trying to say for a while that, as with everything in this world, it is the way as used that can be wrong, not the class itself.
Instead I only read sentences of the type YOU SHOULD NOT USE in any case, without really explaining the mechanisms that can give rise to a malfunction.

Alright, for some reson ADR (lock) is giving me wrong value.

int lock = 1;

lock = lock -1; //Open Lock at pos 0 on CU

byte STX = 0x02;     //Start byte "start of trasmission" and is equal to hex value 0x02
byte ADR;            //The address of target device (Lock)
byte CMD = 0x31;     //one of the 3 avalaible command listed (0x30 - Request door status, 0x31 – Request door open, 0x32 - Get lock status and infrared sensor status)
byte ETX = 0x03;     //End byte "end of trasmission" and is equal to hex value 0x03
byte SUM;            //Error checksum byte calculated simply as the sum(8bit) of bytes before
   
ADR = (lock, HEX) <-- givs me value 16??
SUM = STX + ADR + CMD + ETX;

  Serial.println(String(lock, HEX)); <-- prints "16", it should be "0" or "0x00"

it gives me the value of 16 but Im looking for the value 0 or 0x00. This also means that my check SUM is wrong.

Correct. Look up the C/C++ comma operator.

1 Like

Thank you!

Why this "strange" line?
ADR is just a byte not an int because your communication protocol support only a byte for addressing (so a max of 255 devices).
It is a number! HEX is only a way of representing a number (in base 16), don't get confused from this.

For example 15 in decimal is equal to 0x0F in Hexadecimal (base 16) or 0b00001111 in Binary (base 2) or 017 in Octal (base 8) or XV like the ancient romans were used to!!!
It is always the same "entity" represented in different "languages".

In your case
0 => 0x00 => 0b00000000 => 000 (the ancient romans didn't have the zero)!

Furthermore, Serial.print() is already capable to print in hex format without passing a String

Serial.println(lock, HEX);

Thank you....

It is not a normal statement even if compiler doesnt complain about it lZo9gV - Online C++ Compiler & Debugging Tool - Ideone.com

Hello! I am having the same problem, did you got a solution for it?