What is the maximum number of characters I can send with LMiC?

Good day!

I am new with TTN and there is one small thing I do not understand with byte.

I am working with that exemple
https://github.com/mikenz/LoRa-LMIC-1.51/blob/master/examples/nano-lmic-v1.51-F/nano-lmic-v1.51-F.ino#L98

the variable mydata store the message to be sent. I know that the message must be smal as possible,

I am collecting sensors values. I have 10 sensors and it would be fine to have one record, at TTN console, for one loop of measurement. I means all sensors values by record.

I am not sure

  1. How many caracters I can save into mydata because of the 64
  2. and, first all, can I enlarge the value of 64, and if yes, what is the limit?

How many bits take one caracter? One?

So if one byte have 8 bits, I can have 8 carcaters in one bytes, I can have 512 caracters in my variable mydata.
That’s correct?

I am sorry for my basic question, but I mainly would like to know if I can enlarge mydata[64], if needed?

Many thank for your help
Cheers

You should not think in characters, but only in bits and bytes. See Working with Bytes in the documentation and learn that strcpy((char *) mydata,"{\"Hello\":\"World\"}"); in your example code is bad practice.

When you understand bits and bytes, the uint8_t mydata[64] in the example won’t be your problem: increasing that will make your own code compile just fine. However, the LMiC library you’re using has a limit of 51 bytes (totalling to 64 bytes when including the 13 bytes LoRaWAN headers). So without modification of that library, even using all 64 bytes in uint8_t mydata[64] will already fail as that would exceed the 51 bytes LMiC can send. To increase the maximum size in the libraries, see LMiC fails to send application payload larger than 51 bytes and https://github.com/matthijskooijman/arduino-lmic/issues/100.

But still then, in many (or all) regions, the maximum payload size is 51 bytes for SF12, so trying to go beyond that might be futile.

The good news: I doubt each of your 10 sensors needs a lot of bytes for its measurements. If only few need, say, 6 bytes and most just need 1 or 2 bytes, or even just half a byte or a single bit, then the total result will probably fit just fine.

For an example of combining a 4 bits and 12 bits value into 2 bytes, see here.

Thank a lot for your reply.
I am going to read your link and reconsider my code followinf your comment.
But for you, I still do not how large (maximum) should be my json string to fit in mydata.

I red, that I should not send a json form fomart and I will change it, but has my sensor meseaurement return my a double and I convert it to a char, I need to how how many value (caracters) I can sent.

a caracter take one or some bits, no?

Have a nice day and tank for your help

The answer is in “Working with Bytes”. After reading that, never, ever think about sending human-readable data again. And when not convinced, read Limitations: data rate, packet size, 30 seconds uplink and 10 messages downlink per day Fair Access Policy. Now, go read!

Thank a lot for your reply.
Sure, I will change my message and make sure , it is byte and not a human-readable value but I atill confuse about the convertion of my double value or char value to a bits/byte

But, the thing which still troube me. If I print

Serial.println(mydata)

my terminal return me an error.

exit status 1
call of overloaded ‘sprintln(uint8_t [64], int)’ is ambiguous

However, if I print

Serial.println((char *)mydata);

it print me an human-raedable value.

So does mydata value are already in bytes (no human-redable)? because (char *) should convert in readable value, no?
Morever, mydata is declare in this way

uint8_t mydataAll[64];

But for sure, I have to review this part of my code (and remove the ’ {}:" ’ which consist of a json format

Tnank a lot

In computer memory and when transmitting, everything is just a sequence of bits (and 8 bits are then called a byte). That might be hard to understand at first, but you’ll need to read and re-read “Working with Bytes” (and the links it refers to) until you do understand.

When you think you understand, you should be able to see:

  • When (erroneously) using human-readable text, the value 34.51:
    • is stored as the 48 bits 00110011 00110100 00101110 00110101 00110001 00000000 which includes a trailing NUL-character for a null-terminated string,
    • which is the same the decimal ASCII codes 51, 52, 46, 53, 49 and 0,
    • which is the same as hexadecimal 0x33 34 2E 35 31 00,
    • and further below you’ll see that using Serial.println((char *)mydata) will show “34.51” for the above ASCII codes.
  • When (nicely) using an integer number, the value 34.51 can be multiplied by 100 to get 3451, which:
    • is stored as the 16 bits 00001101 01111010,
    • which is the same as 0x0D 7B,
    • and (erroneously) using Serial.println((char *)mydata) might then print a new line (for ASCII code 0x0D) followed by { (for 0x7B), followed by whatever is in memory until it finds the first 0x00 NUL-character, meanwhile printing garbage for all bytes that cannot be converted to ASCII.

Using the (char *)mydata above you’re telling the compiler that the program knows that what is currently in the memory buffer mydata is in fact human-readable text (and not, for example, some image, or a PDF document, or a simple number). The only reason the program knows, is because it has stored the value there itself (like by using strcpy earlier).

So, (char *) does not convert anything; it is already human-readable text in memory. And when trying to use a built-in function such as Serial.println to show its contents, then your program needs to share that knowledge with the compiler, by prefixing mydata with (char *). (Here, (char) tells the compiler it’s human-readable text, and * gives the compiler a “pointer” to the memory location, which is simply what Serial.println expects.) That line would then print garbage if it was in fact not human-readable text. But as it apparently shows the value you expected, you’re still storing human readable text in memory (and so you would also be sending that to TTN).

Just removing the {...} does not suffice. JSON is one of the many human-readable formats. Changing {"x": 123.45, "y": 45.678} into, e.g., 123.45,45.678 would still be a human-readable format, wasting bytes when sending to TTN.

2 Likes