unsigned long versus uint32_t

Following code is used to transmit an unsigned long with LoRa:

   unsigned long cycleTotal = 0;
   LoRa.write((const uint8_t*)&cycleTotal, sizeof(cycleTotal));

Why is there a (const uint8_t*) while the value to be transmitted contains 4 bytes?
Should that not be (const uint32_t*) ?

Check the prototype for the LoRa.write() function. What argument types is it looking for?

No it's correct :slight_smile:

This function is used to send an array of bytes, so its parameters are a pointer to a byte and a length (sizeof(cycleTotal) == 4)

1 Like

brice3010:
Following code is used to transmit an unsigned long with LoRa:

   unsigned long cycleTotal = 0;

LoRa.write((const uint8_t*)&cycleTotal, sizeof(cycleTotal));




Why is there a (const uint8_t*) while the value to be transmitted contains 4 bytes?
Should that not be (const uint32_t*) ?

Obvious question; Which one works correctly in practice ?

srnet:
Obvious question; Which one works correctly in practice ?

This works:

  LoRa.write((const uint8_t*)&cycleTotal, sizeof(cycleTotal));

But the reason I am asking my initial question is because I did not understand this code; and guix did answer and now I understand :).

The real answer lies in Reply #1.

gfvalvo:
The real answer lies in Reply #1.

From LoRa.cpp:

size_t LoRaClass::write(uint8_t byte)
{
  return write(&byte, sizeof(byte));
}

size_t LoRaClass::write(const uint8_t *buffer, size_t size)
{
  int currentLength = readRegister(REG_PAYLOAD_LENGTH);

  // check size
  if ((currentLength + size) > MAX_PKT_LENGTH) {
    size = MAX_PKT_LENGTH - currentLength;
  }

  // write data
  for (size_t i = 0; i < size; i++) {
    writeRegister(REG_FIFO, buffer[i]);
  }

Could this be the answer to your question gfvalvo?

Yes, right here:
size_t LoRaClass::write(const uint8_t *buffer, size_t size)
The function wants a pointer to a const uint8_t. If cycleTotal is not a uint8_t, then you must cast its pointer appropriately.

gfvalvo:
Yes, right here:
size_t LoRaClass::write(const uint8_t *buffer, size_t size)
The function wants a pointer to a const uint8_t. If cycleTotal is not a uint8_t, then you must cast its pointer appropriately.

For what reason would/should/could this become a 16 bit instead of a 8 bit variable?

Say your variable cycleTotal is stored at address 0xAAAA (and it’s 4 bytes so its end address is 0xAAAD)

The first parameter of the function is a pointer to the byte stored at address 0xAAAA, and the function will send bytes from there

1 Like

It would have been preferable for the library's author to have defined the function as:

size_t LoRaClass::write(const void *buffer, size_t size)

then, casting wouldn't be required.

@OP

The following example sketch may help to get better meaning of this cryptic code:
LoRa.write((const uint8_t*)&cycleTotal, sizeof(cycleTotal));

void setup() 
{
  Serial.begin(9600);
  uint8_t myData[] = {0x41, 0x42, 0x43, 0x44};  //uint8_t could be replaced by byte
  //----------------------------------------
  uint8_t *ptr; //ptr: a pointer variable; it points the beginning of a byte/uint8_t organized space
  ptr = (uint8_t*)&myData; //ptr holds beginning address of a byte (8-bit) organized array 
  for(int i=0; i<sizeof(myData); i++)
  {
    Serial.write(*ptr);  //get the first byte (8-bit) of the myData[] array pointed by ptr and send
    ptr++;                  //point ot the next byte of the array
  }
  //--all the above 5 lines of codes could be replaced by the following single line
  //Serial.write((uint8_t*)&myData, sizeof(myData));
}

void loop() 
{

}
1 Like

GolamMostafa:
@OP

The following example sketch may help to get better meaning of this cryptic code:
LoRa.write((const uint8_t*)&cycleTotal, sizeof(cycleTotal));

void setup() 

{
  Serial.begin(9600);
  uint8_t myData = {0x41, 0x42, 0x43, 0x44};  //uint8_t could be replaced by byte
  //----------------------------------------
  uint8_t ptr;
  ptr = (uint8_t
)&myData; //ptr holds begining address of a byte (8-bit) organized array
  for(int i=0; i<sizeof(myData); i++)
  {
    Serial.write(ptr);  //get the first byte (8-bit) of the myData[] array pointed by ptr and send
    ptr++;                  //point ot the next byte of the array
  }
  //–all the above 5 lines of codes could be replaced by the following single line
  //Serial.write((uint8_t
)&myData, sizeof(myData));
}

void loop()
{

}

GREAT!!
Thanks for that explainer; pity only once an hour can Karma be added :slight_smile:

brice3010:
For what reason would/should/could this become a 16 bit instead of a 8 bit variable?

There is no reason for it to EVER be anything but uint8_t*. That allows a single function to send ANY size data, without having to define multiple functions to handle different sized data. And, uint8_t is ALWAYS an 8-bit value, regardless of what platform you are running on, while int, long, etc. can be different sizes on different processors. On AVR, int is 16-bits, on ARM and ESP int is 32-bits. One AVR, long is 32-bits, while on some other platforms it is 64-bits.

1 Like

RayLivingston:
There is no reason for it to EVER be anything but uint8_t*.

I disagree. Take a look at the prototype for memcpy():

void * memcpy ( void * destination, const void * source, size_t num );

gfvalvo:
I disagree. Take a look at the prototype for memcpy():

void * memcpy ( void * destination, const void * source, size_t num );

But now that the library has been out there for some time, why change it, when there is really no benefit? Changing it now would break existing code for no good reason.

RayLivingston:
But now that the library has been out there for some time, why change it, when there is really no benefit? Changing it now would break existing code for no good reason.

It wouldn't break anything. A function that specifies a parameter of 'void *' can be called using an argument of ANY pointer type. That's the whole purpose of 'void *'

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.