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.
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:
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?
@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.
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.
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;
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.
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