Float to 4 Byte Array & Back


/*
  floatTo4ByteArr_4ByteArrToChar.ino
  
  Demonstration of encoding float values into four byte values
  (in an array) and then decoding the byte array back into a float.  

  Related online tool:  https://gregstoll.com/~gregstoll/floattohex/
  
*/


void setup () {
  Serial.begin(9600);
  while (!Serial) {
    delay(1);
  }
  Serial.println("\nSerial ready");

  uint8_t buf[31];
  encodeData(buf, sizeof(buf));
  printByteArr(buf, sizeof(buf));
  // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
  // ff ff 55 1e 47 3b cf 33 33 6f 42 da 6f f5 46 43 ce d5 82 ff 2b 93 4e 00 00 00 00 00 00 00 00 
  
  decodeData(buf, sizeof(buf));
  // floatVal[3..6] = -3142000128.0
  // floatVal[7..10] = 59.80
  // floatVal[11..14] = 31415.925
  // floatVal[14..18] = -0.00000000000000000000000000000000000031415927410125
  // floatVal[19..22] = 1234567040.0

} // setup()


void loop() {

} // loop()



void encodeData(uint8_t* arr, byte len) {
  // NOTE:  Large positive numbers limited to 8 significant digits and 1.xE9 size.
  //        Small negative numbers good all the way down to -3.1415926E-37
  // If you intend to transmit arr to another computer, then you need to be
  // sure the same decode procedure (byte order is used).  

  byte arrPos = 0;

  // Fill buf with null char
  for (byte i = 0; i<len; i++) {
    arr[i] = 0x0;
  }

  // Add 2 byte identifier to positions 0 & 1
  arr[arrPos++] = 0xff;
  arr[arrPos++] = 0xff;

  // Add 1 byte custom data set identifier to position 2
  arr[arrPos++] = 0x55;  

  
  // Convert a 32 bit float to array of 4 bytes; 3.4E +/- 38 (7 digits)
  // and save to positions 3 to 6 in arr.
  float floatVal = -3.142E+09;
  uint8_t payload4byte[4];
  packFloat(&payload4byte, floatVal);
  //printByteArr(payload4byte, sizeof(payload4byte));
  // Assign payload4Byte contents to arr
  for (uint32_t i=0; i<sizeof(payload4byte); i++) {
    arr[arrPos] = payload4byte[i];
    arrPos++;
  }
  // 03 04 05 06
  // 99 28 3b cf
  //printByteArr(arr, len);
  //Serial.print("arrPos = "); Serial.println(arrPos);

  // Convert a float to array of 4 bytes and save to positions 7 to 10
  floatVal = 59.8;
  packFloat(&payload4byte, floatVal);
  // Assign payload4Byte contents to arr
  for (uint32_t i=0; i<sizeof(payload4byte); i++) {
    arr[arrPos] = payload4byte[i];
    arrPos++;
  }
  // 07 08 09 10
  // 33 33 6f 42
  
  // Convert a float to array of 4 bytes and save to positions 11 to 14
  floatVal = 31415.926;
  packFloat(&payload4byte, floatVal);
  // Assign payload4Byte contents to arr
  for (uint32_t i=0; i<sizeof(payload4byte); i++) {
    arr[arrPos] = payload4byte[i];
    arrPos++;
  }
  // 11 12 13 14
  // da 6f f5 46
   
  // Convert a float to array of 4 bytes and save to positions 15 to 18
  floatVal = -3.1415926E-37;
  packFloat(&payload4byte, floatVal);
  // Assign payload4Byte contents to arr
  for (uint32_t i=0; i<sizeof(payload4byte); i++) {
    arr[arrPos] = payload4byte[i];
    arrPos++;
  }
  // 15 16 17 18
  // 7b e3 57 b1
  
  // Convert a float to array of 4 bytes and save to positions 19 to 22
  // floatVal = 1.2345678E9  decoded = 1234567808.0 limited to 8 significant digits
  // floatVal = 1.234567890E10 decoded = overflow
  // floatVal = 1.234567E9 decoded = 1234567040.0 limited to original 7 significant digits
  floatVal = 1.234567E9;
  packFloat(&payload4byte, floatVal);
  // Assign payload4Byte contents to arr
  for (uint32_t i=0; i<sizeof(payload4byte); i++) {
    arr[arrPos] = payload4byte[i];
    arrPos++;
  }
  // 19 20 21 22
  // e6 40 3b 4f

  //printByteArr(arr, len);
  // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
  // ff ff 55 1e 47 3b cf 33 33 6f 42 da 6f f5 46 43 ce d5 82 ff 2b 93 4e 00 00 00 00 00 00 00 00
    
} // encodeData()



void decodeData(uint8_t* arr, byte len) {
  // NOTE:  Large positive numbers limited to 8 significant digits and 1.xE9 size.
  //        Small negative numbers good all the way down to -3.1415926E-37

  byte arrPos = 0;
  uint8_t payload4byte[4];
  float floatVal = 0.0;

  // Decode float from 4 byte array in positions 3 thru 6
  arrPos = 0;
  for (uint32_t i=6; i>2; i--) {
    payload4byte[arrPos] = arr[i];
    arrPos++;
  }
  //printByteArr(payload4byte, sizeof(payload4byte));
  floatVal = bytesToFloat(payload4byte);
  Serial.print("floatVal[3..6] = "); Serial.println(floatVal,1);

  // Decode float from 4 byte array in positions 7 thru 10
  arrPos = 0;
  for (uint32_t i=10; i>6; i--) {
    payload4byte[arrPos] = arr[i];
    arrPos++;
  }
  //printByteArr(payload4byte, sizeof(payload4byte));
  floatVal = bytesToFloat(payload4byte);
  Serial.print("floatVal[7..10] = "); Serial.println(floatVal,2);

  // Decode float from 4 byte array in positions 11 thru 14
  arrPos = 0;
  for (uint32_t i=14; i>10; i--) {
    payload4byte[arrPos] = arr[i];
    arrPos++;
  }
  //printByteArr(payload4byte, sizeof(payload4byte));
  floatVal = bytesToFloat(payload4byte);
  Serial.print("floatVal[11..14] = "); Serial.println(floatVal,3);
  
  // Decode float from 4 byte array in positions 15 thru 18
  arrPos = 0;
  for (uint32_t i=18; i>14; i--) {
    payload4byte[arrPos] = arr[i];
    arrPos++;
  }
  //printByteArr(payload4byte, sizeof(payload4byte));
  floatVal = bytesToFloat(payload4byte);
  Serial.print("floatVal[14..18] = "); Serial.println(floatVal,50);
  
  // Decode float from 4 byte array in positions 19 thru 22
  arrPos = 0;
  for (uint32_t i=22; i>18; i--) {
    payload4byte[arrPos] = arr[i];
    arrPos++;
  }
  //printByteArr(payload4byte, sizeof(payload4byte));
  floatVal = bytesToFloat(payload4byte);
  Serial.print("floatVal[19..22] = "); Serial.println(floatVal,1);
  
} // decodeData()



void printByteArr(const uint8_t* arr, byte len) {
  Serial.println();
  for (byte i=0; i<len; i++) {
    char str[4];
    sprintf(str, "%02u ", i);
    Serial.print(str);
  }
  Serial.println();
  for (byte i = 0; i<len; i++) {
    char str[4];
    sprintf(str, "%02x ", arr[i]);
    Serial.print(str);
  }
  Serial.println();  Serial.println();
} // printByteArr()



float bytesToFloat(const uint8_t* arr) {
    float output;

    *((byte*)(&output) + 3) = arr[0];
    *((byte*)(&output) + 2) = arr[1];
    *((byte*)(&output) + 1) = arr[2];
    *((byte*)(&output) + 0) = arr[3];

    return output;  
} // bytesToFloat()


int packFloat(void *buf, float x) {
  // pack method for storing data in network,
  //   big endian, byte order (MSB first)
  // returns number of bytes packed
  // usage:
  //   float x, y, z;
  //   int i = 0;
  //   i += packFloat(&buffer[i], x);
  //   i += packFloat(&buffer[i], y);
  //   i += packFloat(&buffer[i], z);
    unsigned char *b = (unsigned char *)buf;
    unsigned char *p = (unsigned char *) &x;
#if defined (_M_IX86) || (defined (CPU_FAMILY) && (CPU_FAMILY == I80X86))
    b[0] = p[3];
    b[1] = p[2];
    b[2] = p[1];
    b[3] = p[0];
#else // Arduino
    b[0] = p[0];
    b[1] = p[1];
    b[2] = p[2];
    b[3] = p[3];
#endif
    return 4;
} // packFloat()