Arduino Forum upgrade scheduled for Monday, October 20th, 11am-4pm (CEST). Sorry for the inconvenience!
Pages: [1]   Go Down
Author Topic: convert from binary string to long  (Read 1224 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to read binary data from a motorola GPS. Some of the info such as lat and lon come across as 4 byte long integers. I read those bytes into a 4 character string, but I really need to read them directly into a long variable.

Is there a way that I can read bytes from the serial port directly into a long. Or is there a way I can change the data type of my string to a long? In short, how to I get the 4 byte binary data into a long? Thanks!
« Last Edit: December 09, 2010, 12:16:20 pm by quemazon » Logged

Central Europe
Offline Offline
Edison Member
*
Karma: 7
Posts: 1220
Use the Source, Luke.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Assuming the byte order is correct, you can read it into a character buffer and then do some pointer magic. If the byte order is wrong, you need to read it in the right place before doing the casting. Assuming your data is read into instr, the code would look something like this:
Code:
char instr[slen];
// ... Fill somehow instr ...
long mylong = *((long *) instr);

One small warning, when playing around with casting pointer to other types, the compiler does what you tell it to do and you circumvent many protections that would alert you about problems. If you mess up, it's your fault and be hard to figure out. It's a bit like locking the blade guard of a buzzsaw.

Korman
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the reply. As I'm new to C and especially pointers, I'm having a hard time wrapping my mind around that last line. Would it be the same as:

Code:
char instr[slen];
// ... Fill somehow instr ...
long * temp;
temp = &instr;
long mylong = *temp;

I think this is exactly what I was looking for. Thanks again.
Logged

Central Europe
Offline Offline
Edison Member
*
Karma: 7
Posts: 1220
Use the Source, Luke.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not exactly, you confuse the types. instr is of type char * or char[] (which is the same), so it's already a pointer and  you shouldn't use the address operator & here. Your code should look like this.
Code:
char instr[slen];
// ... Fill somehow instr ...
long * temp;
temp = [glow](long *)[/glow]instr; // Here you tell the compiler
      // that you know what you're doing and he should shut up
long mylong = *temp;

The highlighted part is necessary to keep the compiler from complaining about your mixing of incompatible pointer types.

Korman
« Last Edit: December 09, 2010, 01:31:49 pm by Korman » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess this is what's called type casting? I didn't know what it was for until now. Thanks.
Logged

Central Europe
Offline Offline
Edison Member
*
Karma: 7
Posts: 1220
Use the Source, Luke.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I guess this is what's called type casting?

Exactly. You tell the compiler to look at a variable in a different way. If the compiler know how to convert from one type to another (like int to float) it will do that for you. With pointers, the compiler will just assume the pointer now points to something of another type and interpret the bytes at this location differently without touching them.
You just have to be a little careful with pointer arithmetic, as adding 1 to a pointer increments the memory location by the size of the type. Here's an example:

Code:
char str[16] = "abcdefghijklm";
long *lp = (long *) str;
*lp or lp[0] is the long made up from "abcd"
lp[1] or *(lp + 1) is the long made up from "efgh", not "bcde"

That's where it gets confusing.

Korman
Logged

0
Offline Offline
Shannon Member
****
Karma: 226
Posts: 12963
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Assuming the byte order is correct, you can read it into a character buffer and then do some pointer magic. If the byte order is wrong, you need to read it in the right place before doing the casting. Assuming your data is read into instr, the code would look something like this:

Code:
char instr[slen];
// ... Fill somehow instr ...
long mylong = *((long *) instr);

One small warning, when playing around with casting pointer to other types, the compiler does what you tell it to do and you circumvent many protections that would alert you about problems. If you mess up, it's your fault and be hard to figure out. It's a bit like locking the blade guard of a buzzsaw.

Korman

There's a better approach IMO that doesn't involve assumptions about endianness (byte order) on your processor, nor require char arrays to be aligned on word boundaries (on many architectures):

Code:
byte instr[slen];  // use byte which is unsigned to prevent sign-extension
// ... Fill somehow instr ...

long convert_bytes2long (byte b[])
{
  long result = 0L ;
  // can loop whichever direction is appropriate for your device.
  for (byte i = 0 ; i < slen ; i++)
    result = (result << 8) | b[i] ;
  return result ;
}

long mylong = convert_bytes2long (instr) ;

It may take a little more code to do, but it will be portable to other microprocessors with no hidden endianness dependencies or alignment restrictions.  It is also much more obvious to the human reader what's going on.  I think.

PS I haven't tested this code, there might be a bugs smiley-wink
Logged

[ I won't respond to messages, use the forum please ]

Pages: [1]   Go Up
Arduino Forum upgrade scheduled for Monday, October 20th, 11am-4pm (CEST). Sorry for the inconvenience!
Jump to: