Pages: [1]   Go Down
Author Topic: Converting unix time to byte array  (Read 1062 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am transmitting data wirelessly via two XBee wireless modules in API mode. This works by sending a packet consisting of a series of bytes. I am attempting to pass a unix time (number of seconds past since 1/1/1970 ~ currently around 1,280,xxx,xxx) to the Arduino as a series of bytes. Then the Arduino would convert it back to a usable number. Here's what I tried:

Code:
// the 4 byte array containing the Unix time is stored in incomingData
unsigned long unixTime = (incomingData[1] << 24) + (incomingData[2] << 16) + (incomingData[3] << 8) + incomingData[4];

But it appears that Arduino can't handle a bitshift more than 8. Is there another way to do this?
Logged

Boston, MA
Offline Offline
Edison Member
*
Karma: 0
Posts: 1024
wiblocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you cast each byte as a 32 bit value it will work.

Code:
((uint32_t)incomingData[1]<<24) + ((uint32_t)incomingData[2] ...

Alternatively a union will work --

Code:
union U {
  uint32_t unixTime;
  uint8_t   data[4];
}

(* jcl *)

------------------------------------
www: http://www.wiblocks.com
twitter: http://twitter.com/wiblocks
blog: http://luciani.org


(* jcl *)
Logged


Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 5
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If you cast each byte as a 32 bit value it will work.
It assembles the bytes in the order in which they were received.  This is probably what you want to do.  (Note to the Original Poster: If array has size 4, the byte index values are 0, 1, 2, 3 not 1, 2, 3, 4.)

Quote
Alternatively a union will work --
The bytes are stored in memory in the order in which they are received, but the integer result depends on the endianness of the machine's architecture.

This is a problem with ATmega chips (and Intel/AMD chip architectures used on PC platforms these days), in which the bytes of multi-byte integers are stored least-significant byte first.

Code:
union {
  unsigned long ul;
  byte data[sizeof(unsigned long)];
} ulc;

    
void setup ()
{
    Serial.begin(9600);
    // Pretend the data came in here
    ulc.data[0] = 0x12;
    ulc.data[1] = 0x34;
    ulc.data[2] = 0x56;
    ulc.data[3] = 0x78;

}

void loop()
{
    char buf[30];
    unsigned long x;
    
    Serial.print("Here are the bytes: ");
        for (int i = 0; i < 4; i++) {
        sprintf(buf, "0x%02x ", ulc.data[i]);
        Serial.print(buf);
    }
    Serial.println(); Serial.println();
    
    x = (unsigned long)ulc.data[0] << 24 |
        (unsigned long)ulc.data[1] << 16 |
        (unsigned long)ulc.data[2] << 8  |
        (unsigned long)ulc.data[3];
    Serial.print("Here is the long int from the shift operations: ");
    sprintf(buf, "0x%08lx\n", x);
    Serial.print(buf);
    
    
    Serial.print("Here is the long int from the union           : ");
    sprintf(buf, "0x%08lx\n", ulc.ul);
    Serial.println(buf);
    
    delay(5000);
    
}

Output:

Here are the bytes: 0x12 0x34 0x56 0x78

Here is the long int from the shift operations: 0x12345678
Here is the long int from the union           : 0x78563412



For compatibility with just about all network communications with platforms of any architecture I think you should always figure on sending (and receiving) big-endian order.  (Like the shift stuff, not the union.)

Regardless of whether you decide to follow ubiquitous networking standards, programmers should at least be aware that the two methods (union versus shifting) give different integer results from the same byte stream for some system architectures (including the ATmega chips).

Regards,

Dave

« Last Edit: July 28, 2010, 08:42:25 pm by davekw7x » Logged

Pages: [1]   Go Up
Jump to: