Floating Point to Hex Converter

Dear All,

Currently, I read data from EMR-4 by command code as below:

Example:

  1. Get Meter Gross Totalizer Reading For Current Product

Command Request:

Packet: 7e01ff4766537e

EMR-4 RESPONSE:

Command Code: 0x46 F
Field Code: 0x66 f

Packet: 7eff01466600000000d0e80441577e (Hex)

0x00000000d0e80441 ==> Volume: 171290.0

I get this volume by using this website. Floating Point to Hex Converter

and tick Swap endianness and past in convert to Double

my question :

Did anyone know the library of arduino or android?

OP's image:

vectoroung:
Dear All,

Currently, I read data from EMR-4 by command code as below:

Example:

  1. Get Meter Gross Totalizer Reading For Current Product

Command Request:

Packet: 7e01ff4766537e

EMR-4 RESPONSE:

Command Code: 0x46 F
Field Code: 0x66 f

Packet: 7eff01466600000000d0e80441577e (Hex)

0x00000000d0e80441 ==> Volume: 171290.0

I get this volume by using this website. Floating Point to Hex Converter

and tick Swap endianness and past in convert to Double

my question :

Did anyone know the library of arduino or android?

this C-code does the trick:

#include<stdio.h>

int main() {
    union{
        long val; 
        unsigned char bytes[sizeof(long)];
    }x;
    
    union{
        double val;
        unsigned char bytes[sizeof(double)];
    }y;
    
    x.val = 0x00000000d0e80441; //171290.0
    
    //Swap endianness
    for(char i=0; i<sizeof(long);++i){
        y.bytes[(sizeof(long)-1)-i] = x.bytes[i];
    }

    printf("y = %.2f, %d, %d", y.val, sizeof(double), sizeof(long)); //prints out y = 171290.00, 8, 8
}

however if I'm not mistaken, on the Uno and other ATMEGA based boards for example, 'double' occupies 4 bytes and therefore depending on the arduino board you are using, the above code may (or may not!) work.

for the above code to work correctly for your conversion, 'double' and 'long' BOTH need to be 8 bytes wide.

hope that helps...

OK! By reverse engineering (see the sketch below), I have found your both float and hex values are correct; the data comes in 64-bit binary64/IEEE-754 Floating Point Format(Fig-1). You can apply this trick in the solution of your problem.
Sketch: (tested in DUE)

union  
{
  double x ;
  long long y;
}data;

void setup()
{
  Serial.begin(9600);
  data.y = 0x4104E8D000000000;
  Serial.println(data.x, 1); //shows: 171290.0
}

void loop()
{

}

binary64.png
Fig-1:

binary64.png

sherzaad:
for the above code to work correctly for your conversion, 'double' and 'long' BOTH need to be 8 bytes long.

In UNO/NANO/MEGA:
float and double refer to the same data size of 32-bit (4-byte) in binary32 format (Fig-1) for the representation/storage of floating point number.

In DUE:
float refers to 32-bit data size in binary32 format(Fig-1) and double refers to 64-bit (8-byte) data size in binary64 format (Fig-2) for the representation/storage of floating point number.

long data type:
It refers to a 32-bit (4-byte) data size for integer signed numbers in all Arduinos (range:0x80000000 to 0x7FFFFFFF).

binary32.png
Figure-1:

binary64.png
Figure-2:

binary32.png

binary64.png

The description of that protocol for electronic meter registration is here [PDF]: https://www.veeder.com/gold/download.cfm?doc_id=6462

It includes the IEEE 64 bit float specification and also the packet format which the OP gave an example of: Packet: 7eff01466600000000d0e80441577e (Hex)

The 7E at the beginning and end of the packet is a delimiter and cannot appear in the body of the packet. That is, if that double which is encoded in the packet, just happens to contain a '7E', then it has to be escaped according to a rule in the specification (Table 1 - OBC packet formats). Conversely, if the OP is attempting to decode a packet, he has to undo any escaping before converting the number it contains.

This will do what you want

const char packet[] = "7eff01466600000000d0e80441577e";

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  char revString[17];
  char byteStr[5];
  byte byteVal;
  int idx = 0;
  
  for ( int i = 24; i > 9; i -= 2 ) {
    revString[idx++] = packet[i];
    revString[idx++] = packet[i + 1];
  }
  revString[16] = 0;
  Serial.println(revString);

  byteStr[0] = revString[0];
  byteStr[1] =  0;
  byteVal = strtol(byteStr, NULL, 16 );
  int sign = (byteVal & 0x08) ? -1 : 1;
  memcpy(byteStr, revString, 3);
  byteStr[3] = 0;
  int exponent = strtol(byteStr, NULL, 16 );

  if ( sign < 0 ) exponent -= 2048;

  float divisor = 256.0;
  float mantisa = 1.0;
  for (int i = 3; i < 15; i += 2 ) {
    memcpy(byteStr, revString + i, 2 );
    byteStr[2] = 0;
    Serial.print("byteStr=" ); Serial.println( byteStr );
    mantisa += strtol(byteStr, NULL, 16 ) / divisor;
    divisor *= 256.0;
  }
  memcpy(byteStr, revString + 15, 1 );
  byteStr[1] = 0;
  Serial.print("byteStr=" ); Serial.println( byteStr );
  mantisa += strtol(byteStr, NULL, 16 ) / divisor;

  float value = pow( 2, exponent - 1023) * mantisa;
  Serial.print( "sign = " ); Serial.println(sign);
  Serial.print( "exp = " ); Serial.println(exponent);
  Serial.print( "mantisa = " ); Serial.println(mantisa, 10);
  Serial.print( "final value = " ); Serial.println(value, 4);
}

void loop() {
  // put your main code here, to run repeatedly:

}