Determining 2's complement of a hex number

Hello all,
I am reading a powermeter and it gives me negative values in 2's complement in HEX which i am reading on the serial port of arduino.I read 8 bytes of data once I take the reading from the meter.Lets say 'FFFFD43C' is the value given by the meter for reading '-11' from the meter which is in 2's complement.I have problem writing code on converting this value to decimal(even hex will work).
I store those 8 bytes in an array.I tried method of (XOR)inverting the bits and adding 1 but its not working.I think the part of the problem is the arduino is treating the hex values outputted by meter as ASCII and I try XOR the ASCII symbol which would probably be incorrect.
buffer[0]=(buffer[0]^0xf);//XORing the bits
buffer[1]=(buffer[1]^0xf);
buffer[2]=(buffer[2]^0xf);
buffer[3]=(buffer[3]^0xf);
buffer[4]=(buffer[4]^0xf);
buffer[5]=(buffer[5]^0xf);
buffer[6]=(buffer[6]^0xf);
buffer[7]=(buffer[7]^0xf);
I still need to add 1 after I XOR the array.Please help!!

Lets say 'FFFFD43C' is the value given by the meter for reading '-11' from the meter which is in 2's complement.

Nope. Not even close. 0xFFFFD43C = -11204.

Is there an implied decimal point? Is the expect value -11.204?

You perhaps miss the obvious point that that value is a valid 32 bit signed integer, you just need to convert it to binary in a 'long' and it will be negative! So read in the nybbles, shift and add...

arduinokid:
I store those 8 bytes in an array.I tried method of (XOR)inverting the bits and adding 1 but its not working.I think the part of the problem is the arduino is treating the hex values outputted by meter as ASCII and I try XOR the ASCII symbol which would probably be incorrect.
buffer[0]=(buffer[0]^0xf);//XORing the bits
buffer[1]=(buffer[1]^0xf);
buffer[2]=(buffer[2]^0xf);
buffer[3]=(buffer[3]^0xf);
buffer[4]=(buffer[4]^0xf);
buffer[5]=(buffer[5]^0xf);
buffer[6]=(buffer[6]^0xf);
buffer[7]=(buffer[7]^0xf);
I still need to add 1 after I XOR the array.Please help!!

Huh? Your meter is sending ASCII namely: 'F', 'F', 'F', 'F', 'D', '4', '3', 'C'.

That's the only way it is sending you 8 bytes.

In hex this is:

0x46 0x46 0x46 0x46 0x44 0x34 0x33 0x43

Now you have xord them with 0xF, so you now have:

0x49 0x49 0x49 0x49 0x4B 0x3B 0x3C 0x4C

In ASCII that is: IIIIK;<L

Adding 1 to that lot isn't going to help very much.

In any case, -11 in hex twos-complement is: FFFFFFF5

As MarkT said, you probably need to take each byte, strip out the ASCII part, and shift into a long. But you still won't get -11 from FFFFD43C.

At Coding badly,you are correct 0xFFFFD43C = -11204. Then i divide it by 1000 which i have done for postive numbers.
At Nick Gammon,you are correct. "IIIIK;<L" was what my reader what outputting when I read it on serial port.Now I understood why it was doing that.Thanks a lot.
MarkT: I am trying to do what you are suggesting.I know what to do but cant figure out how to do it.Could you please break down into smaller steps on how to do it.I changed the code now as follows:
buffer[0]=~buffer[0];
buffer[1]=~buffer[1];
buffer[2]=~buffer[2];
buffer[3]=~buffer[3];
buffer[4]=~buffer[4];
buffer[5]=~buffer[5];
buffer[6]=~buffer[6];
buffer[7]=~buffer[7]; so that all bits are flipped
Now I need to do a binary addition of 1 bit and read the nibbles as you said.I tried different ways but not working out.
Please help.Thank you all for your posts.I am really greatful for all your comments.It helped me to clear some of my fuzzy concepts regarding ASCII and how the arduino treats numbers.

The usual loop for reading in a 32 bit radix 16 number is

long value = 0 ;
for (byte i = 0 ; i < 8 ; i++)
{
  byte nibble = convert_char (buffer [i]) ;
  value = (value << 4) + nibble ;
}

Where convert_char() would convert whatever is in the buffer to 4 bit binary value. If you already have the values as binary then omit this.

arduinokid:
I changed the code now as follows:
buffer[0]=~buffer[0];
...

You are still inverting the ASCII character. Here is a clue about the general way you would write the convert_char function that MarkT is talking about:

byte convert_char (const byte x)
  {
  byte a = toupper (x);   // unless you are sure it is upper-case, in which case you could do: byte a = x
   if (a >= 'A')     // change 0x41 through to 0x45  to 0x3A to 0x3F
       a -= 7;
   return a - '0';  // get rid of the 0x30 part, leaving 0x00 through to 0x0F
  }

What exactly are you trying to do? This may be easier than you think!

Using it within the Arduino should be easy -- the Arduino uses two's complement as well so you should just have to stuff the bytes into an integer assuming it is 16 bit. But you are showing 4 byte -- so stuff it into a signed long (just a long) -- then use it...

You might have to flip ends, but if you know what the number should be that should be no big deal. I flip ends when I move the data to a PC so It conforms to the internet "standard" such as it is. (Big Endian, Little Endian and all that)

If the objective is to send this to a pc -- this code works at the PC end.

At the PC end -- if that's where it is going...

This is Pascal code -- but you should get the idea...
":=" is the same as the C "=" sign.

wSesnVal is a 16 bit integer. Two's complement -- could have a sign.
I think the number below would be "2147483648" for a four byte integer --- 2^31

     if (wSensVal > 32767) then
     begin
        //convert from two's complement used by Arduino
        wSensVal := Not wSensVal+1;
        iSensorValue := Integer(wSensVal) * -1;
     end
     else   iSensorValue := wSensVal;

Yay!!It works perfectly now!Now my whole code even looks very short and beautiful.I was using long way to calculate positive numbers too.
Thankyou MarkT and Nick Gammon.But I would like to clear my concepts here.

byte convert_char (const byte x)
  {
  byte a = x;   // Yes I read only upper case,
   if (a >= 'A')     // change 0x41 through to 0x45  to 0x3A to 0x3F
       a -= 7;
   return a - '0';  // get rid of the 0x30 part, leaving 0x00 through to 0x0F
  }

In this function above,I am getting 1-9 and if it is A-F i am converting to 10-15 which are in ASCII

long value = 0 ;
for (byte i = 0 ; i < 8 ; i++)
{
  byte nibble = convert_char (buffer [i]) ;
  value = (value << 4) + nibble ;
}

In this code,I am reading four bits of each ASCII that I get above and put it in the 'long' binary format.Each bit will
set or clear the 2^ position and final value will be assembled as long format.Is it correct that since negative numbers
are in 2's complement, the 'long' type will read the most significant bit as 1 and creates a negative number of that value.
Again, million thanks for help that has saved my hours of work and help me to understand more.
thanks
Arduinokid

arduinokid:
In this function above,I am getting 1-9 and if it is A-F i am converting to 10-15 which are in ASCII

Your terminology is a bit fuzzy, but basically, yes. You are getting '0' to '9' (0x30 through to 0x39 in hex). And if you get 'A' to 'F' (0x41 to 0x45) we are subtracting 7, changing 0x41 to 0x3a and so on (in decimal, 65 - 7 = 58). 0x3A is really ':' in ASCII, 0x3B is ';' and so on.

And as WillR says, you don't need to start taking the 2's complement. Once you have finished shifting in the 4-bit quantities it should be the right number anyway (if you use "long" type which is 32-bit signed integer).

For thoroughness I'd code a conversion function like this:

#define INVALID_HEX_DIGIT 0xFF

byte convert_char (char x)
{
  return (x >= '0' && x <= '9') ? x - '0' :
         (x >= 'A' && x <= 'F') ? x - 'A' + 10 :
         (x >= 'a' && x <= 'f') ? x - 'a' + 10 : INVALID_HEX_DIGIT ;
}

This code's only assumption about character codes is that the digits are ascending/contiguous and the letters A--F are ascending/contiguous. It works with upper or lower case and catches bad digits returning an error value. It also demonstrates the conditional expression syntax which is nice and concise.