Casting a negative value??

I am communicating with a roomba. It sends certain int-sized values (-32768 - 32767), two bytes at a time, high byte first. I am having trouble keeping the value signed when I receive it, and put the two bytes into an int variable using bit math. At the top of my code, I declare ‘distance’ as an int, and later in the code, I do this:

distance = ((sensorbytes[2] << 8) | sensorbytes[3]);

sensorbytes[2] is the high byte, and sensorbytes[3] is the low byte.

What am I doing wrong? I have tried this:

distance = ((int)(sensorbytes[2] << 8) | sensorbytes[3]);

Now I have something to help this problem; this code works:

  lcd.clear();
  char var1, var2;
  signed short int var3, var4;
  var1 = 0xab;
  var2 = 0xcd;
  var3 = ((signed short int) (var1 << 8) |(0xff & var2) );
  if(sizeof(var3) == 2)
      printf("signed short is 2 bytes\n");

  if (var3 == 0xabcd) {
    lcd.print("it's right!");
  }
  else {
    lcd.print("var3=");
    lcd.print(var3);
  }
  return;

Showing that the casting is done correctly. This must be a problem with the roomba protocol. Does anyone know anything about the ROI (Roomba Open Interface) to shed some light on this? It is really important that I get the arduino to receive negative values from the roomba, otherwise the project I am working on for my current internship will never be finished!!

Now I see in the Arduino reference page the word() constructor. For anyone who doesn’t know, it takes two bytes (word(highByte, lowByte)) and puts them into a word. The problem with this is that I need this value I’m trying to create by casting two bytes to be SIGNED. Word only goes from 65,535 to 0. I need a range of -32768 to 32767. One of these two bytes (the high byte) has a leading ‘1’, indicating that when it is combined with the low byte, you should get a NEGATIVE value. Is there not something like int(h, l)? :-?

Well, on the Arduino, an “int” is a 16 bit signed, as is an unqualified “short”, so “signed short int” is somewhat redundant.

You could try:

byte var1, var2;
  int var3;
  var1 = 0xab;
  var2 = 0xcd;
  var3 =  ((int)var1 << 8) | (0xff & (int)var2) ;

Have you printed the values back from the Roomba?

Right. I just copied a friend’s code that he created in a C compiler to test this. That is not the issue, though, but thanks otherwise I guess…

quackmaster,

There’s another way to assemble a 16-bit integer from two 8-bit bytes:

union twobytes
{
int i;
byte b[2];
};

int assemble_bytes(byte b1,byte b2)
{
    union twobytes t;

    t.b[0] = b1;
    t.b[1] = b2;
    return(t.i);
}

I didn’t try to compile this, so this may not be exactly correct, but you get the idea. Also, I’m not sure about the order of the bytes, so they may need to be switched around.

-Mike

Ok great; thanks, mfm9. I’ll try this tomorrow when I pick it up again…

A union, neat idea!

(Though I’d have used uint16_t and uint8_t)

A union is not ideal, I think, if there is different endianness.
The shift-OR approach is probably preferable from a portability POV.

Looks like this has to do with the Roomba ROI. Unioning is not working with the roomba (but although it does work when I pass it a negative value as it should). Neither does the shift-OR approach…Something about the way the roomba sends these negative values does not work with this code…

What are the values?

Are you sure you’re passing the right “hi-byte” and “low byte” ?
Make some test code that prints all of “high byte”, “low byte”, and the calculated “distance.”

Problem solved: http://forums.ladyada.net/viewtopic.php?f=25&t=12049&p=57746#p57746