Concatenating strings in a uint8_t array

I am a newcomer to Arduino. I have a simple problem to solve, but don't understand all of the many options in this environment.

Int counter
unint8_t MyMessage[16];
...
//main loop
++ counter;
MyMessage = "Test message number" + counter;
....rest of the code

I have tried strcat ("Test message number" + String(counter));
I tried making a new array as uint8_t CounterArray = String(counter);

I have tried

        strcat (MyMessage, (uint8_t *)counter);

there must be a simple way please

thanks

Have you tried reading the manual?

23.11.3.14 char *strcat ( char * dest, const char *src )

Concatenate two strings.
The strcat() function appends the src string to the dest string overwriting the '\0' character at the end of dest, and then adds a terminating '\0' character. The strings may not overlap, and the dest string must have enough space for the result.

Returns
The strcat() function returns a pointer to the resulting string dest.

You did see that I am not actually concatenating strings right? The first is an array of type uint8_t and the second is an integer.

So strcat fails with “invalid conversion from ‘uint8_t* {aka unsigned char*}’ to ‘char*’ [-fpermissive]”

So? Cast.

Isn't that what I tried when I put in 'uint8_t' in front of 'counter'

I am not a c++ programmer, more familiar with python.

I read through this forum for 2 hours before posting, then searched another 2 hours on google but cannot find an example of what I am trying to do.

which is concatenate a uint8_t array with an integer back into the original uint8_t array which I sized to be more than large enough to take the result.

What do you expect the result to be? There are options. The first bit is easy. You need to make sure that the destination is large enough to handle the result so pick some arbitrarily large number, say 32. Declare your array as byte, uint8_t dest[32];

The strcat() function works from the end of the string that currently exists in the dest array. In char-speak that is a NULL or "\0". In byte-speak it's simply 0. To make certain that the cat function is starting from scratch, make the first array entry in the array a 0. If an array is declared as local, it is not automatically initialised, you must do so yourself. You can either set dest[0] = 0, or when you declare, uint8_t dest[32] = {}; will set the entire array to 0s. As you may reuse the array, it's probably better you get in the habit of setting index 0 to 0.

Once that mess is accomplished, simply cat your message to your byte array. To not piss off the compiler, cast the array -> strcat((char*)dest, MyMessage). Done.

Next, you have to decide how you want your integer tacked on, as printable characters or as the digit values. When you get that far say something.

And it's not C++, it's C.

This should work if you are willing to convert to the right data type

int counter = 10;
char MyMessage[30] = "Test Message";
...
//main loop
++ counter;
sprintf(MyMessage, "%s %d", MyMessage, counter);

Content of MyMessage now is: "Test Message 11";

So something like this?

unint8_t MyMessage[32] = [];
...
//main loop
++ counter;
strcat ((char *) MyMessage, "Test message number = ");
strcat ((char *) MyMessage, String(counter);

Would that then build the whole string into MyMessage as a string ready to send as a LoRa packet?

Tried it and got:

changed it to:

        strcat ((char *) MyMessage, "Test message number = ");
        strcat ((char *) MyMessage, (char *) counter);

and my Heltec LoRa OLED devcie went into an endless reboot loop
Memory overflow, maybe the string is not long enough?

Get rid of the String bit, that's really a no-no. What you're looking for is the itoa() function. Do you not have a copy of the AVR library user manual?

That still doesn’t necessarily detail what is expected of the integer value. ASCII array? Digit array? 2/4 byte value?

First, what is the AVR user manual?

I tried this based on your example

        sprintf(MyMessage, "%s %d", MyMessage, counter);
        mydata = (uint8_t *) MyMessage;

and got the error message:

sketch_aug04b:181: error: incompatible types in assignment of 'uint8_t* {aka unsigned char*}' to 'uint8_t [64] {aka unsigned char [64]}'

mydata = (uint8_t *) MyMessage;

^

exit status 1
incompatible types in assignment of 'uint8_t* {aka unsigned char*}' to 'uint8_t [64] {aka unsigned char [64]}'

I need the value 'mydata' as an uint8_t array to pass to the LMIC library for LoRa

smbunn:
First, what is the AVR user manual?

I tried this based on your example

        sprintf(MyMessage, "%s %d", MyMessage, counter);

mydata = (uint8_t *) MyMessage;




and got the error message:

sketch_aug04b:181: error: incompatible types in assignment of 'uint8_t* {aka unsigned char*}' to 'uint8_t [64] {aka unsigned char [64]}'

mydata = (uint8_t *) MyMessage;

^

exit status 1
incompatible types in assignment of 'uint8_t* {aka unsigned char*}' to 'uint8_t [64] {aka unsigned char [64]}'

I need the value 'mydata' as an uint8_t array to pass to the LMIC library for LoRa

You can cast MyMessage to unit8_t array to pass to the function

(uint8_t*)My_Message

Isn't that what I did with

mydata = (uint8_t*)MyMessage

The line of code that passes mydata on is:

LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);

So using your example I would have to change this to

LMIC_setTxData2(1, (uint8_t*)MyMessage, sizeof((uint8_t*)MyMessage)-1, 0);

Correct?

I tried

          sprintf(MyMessage, "%s %d", MyMessage, counter);
          LMIC_setTxData2(1, (uint8_t*)MyMessage, (MyMessage.length)-1, 0);

based on the fact the MyMessage is string so I should use MyMessage.length instead of sizeof((uint8_t*)MyMessage)

and got a new error message:

sketch_aug04b:183: error: request for member 'length' in 'MyMessage', which is of non-class type 'char'

LMIC_setTxData2(1, (uint8_t*)MyMessage, (MyMessage.length)-1, 0);

^

exit status 1
invalid conversion from 'const char*' to 'char' [-fpermissive]

Wow this is so hard, I have done way more complex coding in python using ByteArray which is trivial compared to this.

Try to relate this back to what I said.

uint8_t dest[32];
dest[0] = 0;
char * MyMessage = "Test message number";
strcat((char*)dest, MyMessage);

char int_array[6];
itoa(counter, int_array, 10);
strcat((char*)dest, int_array);

See attached.

avr-libc-user-manual-2.0.0.pdf (1.6 MB)

OK almost there, I have this working

static uint8_t mydata[36];
static int counter;

//later in the code 
................
  ++counter;
  mydata[0] = 0;
  char*  MyMessage = "Test Message Number ";
  char counter1[12];
 
       strcat ((char*)mydata, MyMessage);
       itoa(counter,counter1,10);
       strcat ((char*)mydata, counter1);
        LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);

and this is now working and sending data via LoRa BUT the string is 36 characters long, it is not getting terminated after the counter so a sample message is
" Test Message Number 21\u0000\u0000 \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"

so how do I make 'mydata' long enough to hold values up to say 6 digits but not have trailing \u0000 in the message being sent? I thought that the 'sizeof(mydata)-1' would work, but assume that mydata[0] = 0 has filled the entire 36 positions with nulls, so it looks to be already 36 characters long?

Not sure how to create a string that is only long enough to hold the message and the counter, when the number of digits in the counter will increase at 10, 100, 1000 etc

In python I wrote this to pack 11 floats plus an integer into an array to pass thru as JSON over LoRa

    data = bytearray(48)
    data[0:4] = bytearray(struct.pack(">i", count))
    data[4:8] = bytearray(struct.pack(">f", vt))
    data[8:12] = bytearray(struct.pack(">f", dew))
    data[12:16] = bytearray(struct.pack(">f", temp1))
    data[16:20] = bytearray(struct.pack(">f", roll1))
    data[20:24] = bytearray(struct.pack(">f", press1))
    data[24:28] = bytearray(struct.pack(">f", temp2))
    data[28:32] = bytearray(struct.pack(">f", hum1))
    data[32:36] = bytearray(struct.pack(">f", relhum))
    data[36:40] = bytearray(struct.pack(">f", acc1))
    data[40:44] = bytearray(struct.pack(">f", acc2))
    data[44:48] = bytearray(struct.pack(">f", acc3))

super easy to code, and struct.pack supports integers, floats (big and little endian) strings all with ease. Is there nothing like this in C?

Easy to decode in Node Red using

var buf = new Buffer(msg.payload,'hex');
value1 = parseFloat(buf.readFloatBE(4).toFixed(3));
msg.payload = value1;
msg.topic = "Voltage";
return msg;

LMIC_setTxData2(1, (uint8_t*)MyMessage, sizeof((uint8_t*)MyMessage)-1, 0);

should be:

LMIC_setTxData2(1, (uint8_t*)MyMessage, strlen(MyMessage), 0);