Byte array to int is not working

Hi,

I get a byte array with following values.

buf[0] = 0x00
buf[1] = ox00
buf[2] = 0x00
buf[3] = 0x00
buf[4] = 0x90
buf[5] = 0xCF
buf[6] = 0x00
buf[7] = 0x00

red = values for capacity
black = values for voltage
green = values for power

The values in buf are in luittle endian. I just need the values for the voltage buf[4] and buf[5].
The above value => 0xCF90 => d53136

I have following method to calulate that:

unsigned long byteArrayToInt(byte *data, int startIndex, int byteCount) {
  switch (byteCount) {
	  case 2:
	        return (data[startIndex + 1] << 8)
	        | data[startIndex];
	  break;  
	  case 4:
	      return (data[startIndex + 3] << 24)
	      | (data[startIndex + 2] << 16)
	      | (data[startIndex + 1] << 8)
	      | data[startIndex];
	  break;
  }
}

and I call the method like

 unsigned long actualVoltage = byteArrayToInt(buf,4,2);

but the result for actualVoltage is = 429495286. Looks for me like an overflow. :confused:

I tryed also following method. This method is more flexible.

unsigned long byteArrayToInt(byte *data, int startIndex, int byteCount) {
 unsigned long value = 0;
 for (int i = 0; i < byteCount; i++) {
	 int shift = i * 8;
	 value += data[startIndex + i] << shift;
 }
 return value;
}

but with the same result. Some idea?

Many thanks for the help.

You could let the compiler do the byte assembly.

union {
  byte buf[8];
  struct {
    unsigned long capacity;
    unsigned int voltage;
    unsigned int power;
  } value;
} test;

void setup() {
  Serial.begin(115200);
  test.buf[4] = 0x90;
  test.buf[5] = 0xCF;
  Serial.print(F("Voltage = "));
  Serial.print(test.value.voltage);
  Serial.print(F(", 0x"));
  Serial.println(test.value.voltage, HEX);
}

void loop() {}
Voltage = 53136, 0xCF90

I had to look up how to initialize a union, so here a better version.

union {
  byte buf[8];
  struct {
    unsigned long capacity;
    unsigned int voltage;
    unsigned int power;
  } value;
} test = { .buf = {0,0,0,0, 0x90,0xCF, 0,0 } };

void setup() {
  Serial.begin(115200);
  Serial.print(F("Voltage = "));
  Serial.print(test.value.voltage);
  Serial.print(F(", 0x"));
  Serial.println(test.value.voltage, HEX);
}

void loop() {}

Voltage = 53136, 0xCF90

You may want to consider doing your arithmetic on something wider than a sixteen bit int.

quick and dirty hack: treat the array as 4 unsigned integers rather than 8 bytes
sot the voltage is just the third value of the 4-element array.

unsigned voltage = ((unsigned *)buf)[2];

wg0z:
quick and dirty hack: treat the array as 4 unsigned integers rather than 8 bytes
sot the voltage is just the third value of the 4-element array.

unsigned voltage = ((unsigned *)buf)[2];

A byte is an unsigned integer.

One can change 'unsigned * to 'unsigned short *' if one so desires.

wg0z:
well, a byte is not 16 bits... and can be treated as negative.

an unsigned integer cannot be treated as negative.

I only implemented the 2-byte version of your function, but this:

void setup() {
  uint8_t buf[] = {0, 0, 0, 0, 0x90, 0xcf, 0, 0};
  uint32_t byteArrayToInt(uint8_t *, uint8_t, uint8_t);
  Serial.begin(115200);
  delay(2000);

  Serial.println(byteArrayToInt(buf,4,2));  
}
void loop() {
}
uint32_t byteArrayToInt(uint8_t *data, uint8_t startIndex, uint8_t byteCount) {
  return (uint32_t) *(data+startIndex+1) << 8 | *(data+startIndex);
}

Printed "53136" on the serial console.

I would avoid storing one data type in a union and then pulling out a different type. The results are implementation-dependent and thus non-standard.

Thanks for all the answers.

The union part works fine for me, but I have not realy understand it.
I think I have to read more about that.
I tryed this and works like a charm.

union {
  byte buf[8];
  struct {
    unsigned long capacity;
    unsigned long voltage;
    unsigned long power;
  } value;
} test;

void setup() {
  Serial.begin(115200);
}

void loop() {
  test.buf[4] = 0x90;
  test.buf[5] = 0xCF;
  Serial.print(F("Voltage = "));
  Serial.println(test.value.voltage);

  delay(2000);

  test.buf[0] = 0x90;
  test.buf[1] = 0xDF;
  Serial.print(F("cap = "));
  Serial.println(test.value.capacity);
  delay(2000);
}
cap = 57232
Voltage = 53136

unsigned longs are 4 bytes each, so you're actually going past the end of buf with 'power'
you'd presumably see that if you ever tried to use it.

wg0z:
unsigned longs are 4 bytes each, so you're actually going past the end of buf with 'power'
you'd presumably see that if you ever tried to use it.

Oh yes right, THX

(Ab)using a union like that is most definitely processor and compiler dependent. It may work with the Arduino IDE and the particular board you're programming, but it's not guaranteed to be portable.