Shop OBEX P1 Docs P2 Docs Learn Events
Little Endian to Big Endian — Parallax Forums

Little Endian to Big Endian

bboy8012bboy8012 Posts: 153
edited 2009-04-09 14:04 in Propeller 1
How would I convert bytes being recieved from little endian to big endian? Or just get MSB first instead of LSB? I have been trying to use the shift operators, but no avail. Thanks

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

Comments

  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-04-08 02:30
    Here are a couple of solutions in assembly that do it for nibbles.· I believe the general idea could be expanded to work with·bytes.

    http://forums.parallax.com/showthread.php?p=616821



    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • bboy8012bboy8012 Posts: 153
    edited 2009-04-08 04:39
    Thanks Beau I am looking at it, and I think I can comprehend it and try it. Last question, say im getting 8byte message, and of that I only want the first four bytes for one cmd, and the last 4 for another. How would I go about this. Also is there a place on here to learn about bit resturcting so to call it?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-08 04:54
    Spin does have byte arrays, so rearranging bytes is fairly easy. The Extended FullDuplexSerial object has routines to read a sequence of serial characters into a byte array (a string) and you might use that.

    To learn about programming, you might start with the various tutorials you can access via the "Propeller: Getting Started and Key Thread Index" sticky thread. The Propeller Education Kit tutorials also help introduce you to Spin programming.

    There really isn't a tutorial on "bit restructuring" since it's really about binary arithmetic including bit shifts. You should be able to find this sort of stuff in any introductory programming course, especially one dealing with embedded systems or hardware design as well. A number of universities now have free lectures on-line including some introductory programming courses. The Apple iTunes Store has some of these and some you can find through the various Universities' sites. Try places like MIT and Carnegie-Mellon for a start.
  • Brian FairchildBrian Fairchild Posts: 549
    edited 2009-04-08 12:42
    How about...
    CON
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    
    OBJ
    
      text : "vga_text"
      
    VAR
    
      long var_32
      word var_16
      byte var_8
    
    PUB start | x
    
      'start term
      text.start(16)
      text.str(string(13,"   Bit Reversing Demo",13,13))
    
      'reverse the bits in a 32-bit value
      var_32 := $01234567
      text.hex(var_32,8)
      text.out(13)
      
      var_32 := (var_32 & $55555555) <<  1 | (var_32 & $AAAAAAAA) >>  1 
      var_32 := (var_32 & $33333333) <<  2 | (var_32 & $CCCCCCCC) >>  2 
      var_32 := (var_32 & $0F0F0F0F) <<  4 | (var_32 & $F0F0F0F0) >>  4 
      var_32 := (var_32 & $00FF00FF) <<  8 | (var_32 & $FF00FF00) >>  8 
      var_32 := (var_32 & $0000FFFF) << 16 | (var_32 & $FFFF0000) >> 16
    
      text.hex(var_32,8)
      text.out(13)
    
      'reverse the bits in a 16-bit value
      var_16 := $0123
      text.hex(var_16,4)
      text.out(13)
      
      var_16 := (var_16 & $5555) <<  1 | (var_16 & $AAAA) >>  1 
      var_16 := (var_16 & $3333) <<  2 | (var_16 & $CCCC) >>  2 
      var_16 := (var_16 & $0F0F) <<  4 | (var_16 & $F0F0) >>  4 
      var_16 := (var_16 & $00FF) <<  8 | (var_16 & $FF00) >>  8 
    
      text.hex(var_16,4)
      text.out(13)
    
      'reverse the bits in an 8-bit value
      var_8 := $55
      text.hex(var_8,2)
      text.out(13)
    
      var_8 := (var_8 & $55) <<  1 | (var_8 & $AA) >>  1 
      var_8 := (var_8 & $33) <<  2 | (var_8 & $CC) >>  2 
      var_8 := (var_8 & $0F) <<  4 | (var_8 & $F0) >>  4 
    
      text.hex(var_8,2)
      text.out(13)
    
    
  • Brian FairchildBrian Fairchild Posts: 549
    edited 2009-04-08 12:58
    There's also the specialised case...
      'reverse the bits in each byte in a 32-bit value leaving the byte order unchanged
      var_32 := $01234567
      text.hex(var_32,8)
      text.out(13)
      
      var_32 := (var_32 & $55555555) <<  1 | (var_32 & $AAAAAAAA) >>  1 
      var_32 := (var_32 & $33333333) <<  2 | (var_32 & $CCCCCCCC) >>  2 
      var_32 := (var_32 & $0F0F0F0F) <<  4 | (var_32 & $F0F0F0F0) >>  4 
    
      text.hex(var_32,8)
      text.out(13)
    
    
    
  • bboy8012bboy8012 Posts: 153
    edited 2009-04-08 13:57
    Thanks Brian I am going to try that.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-08 14:18
    If I understand the REV command correctly that would be easier.

    First you use the REV to convert the whole 32 bits. This will of course change the order of the bytes inside the long. But then you can use the BYTE[noparse][[/noparse]@var_adr] to restore the order of the bytes again.


    var_32 := var_32 >< 32
    byte_buffer:=byte[noparse][[/noparse] @var_32 ]
    byte[noparse][[/noparse] @var_32 ]:=byte[noparse][[/noparse] @var_32+3 ]
    byte[noparse][[/noparse] @var_32+3 ]:=byte_buffer
    byte_buffer:=byte[noparse][[/noparse] @var_32+1 ]
    byte[noparse][[/noparse] @var_32+1 ]:=byte[noparse][[/noparse] @var_32+2 ]
    byte[noparse][[/noparse] @var_32+2 ]:=byte_buffer

    (Didn't try that cause my prop is at home and I'm at work)

    Post Edited (MagIO2) : 4/8/2009 2:23:39 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-08 14:43
    You can also use the notation "var_32.byte[noparse][[/noparse] x ]" where "x" is any expression. Look at the Propeller Manual under BYTE / WORD / LONG
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2009-04-08 15:37
    This might help:

    In SPIN, to swap the WORDs from Little Endian to Big Endian within a single LONG:
        temp1 := (Source & $FFFF0000)>>16
        temp2 := (Source & $0000FFFF)<<16
        Dest := temp1 + temp2
    


    In SPIN, to swap the BYTEs from Little Endian to Big Endian within a single LONG:
        repeat i from 0 to 3
          Dest.byte[noparse][[/noparse]i] := Source.byte[noparse][[/noparse]3-i]
    
    

    In SPIN, to swap the NIBBLE's from Little Endian to Big Endian within a single LONG:
        repeat i from 0 to 3
          Dest.byte[noparse][[/noparse]i] := Source.byte[noparse][[/noparse]3-i]
        temp1 := (Dest & $F0F0F0F0)>>4
        temp2 := (Dest & $0F0F0F0F)<<4
        Dest := temp1 + temp2
    

    Note: Define both 'Dest' and 'Source' as longs ; temp1 and temp2 are also defined as longs

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Brian FairchildBrian Fairchild Posts: 549
    edited 2009-04-08 16:15
    I've just realised I'm slightly confused as to what the OP wants to achieve so to complete the line up and in the same style as my other code...
      'reverse the byte order in a 32-bit long
      var_32 := $01234567
      text.hex(var_32,8)
      text.out(13)
      
      var_32 := (var_32 & $00FF00FF) <<  8 | (var_32 & $FF00FF00) >>  8 
      var_32 := (var_32 & $0000FFFF) << 16 | (var_32 & $FFFF0000) >> 16
    
      text.hex(var_32,8)
      text.out(13)
    
    



    To explain a little, if you look at the top example I gave you'll see five lines of code doing the swap. The first line swaps every pair of adjacent bits, the second every pair of two adjacent bits, the third every pair of 4 adjacent bits and so on. By picking your combination of lines you can achieve just about any conceivable swapping arrangement.

    The nice thing about these methods is that they translate to very tight assembler needing no loops.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-08 18:29
    I'm confused as well, the original poster talks about a bytes to be converted from little endian to big endian. This only makes sense when we talk about bits. Otherwise he should have said: I want to convert a long or a word which comes in bytes to big endian. Unfortunately the abbreviation MSB and LSB can be read as Most/Least Significant Byte or as Most/Least Significant Bit.

    Nevertheless, the code given in the last post is not converted to assembler at all, it's converted to bytecode. Each assignment and each boolean operation is converted in bytecode which has to be interpreted and you need constants that need to be stored as well. The pure conversion will at least result in 6 bytecode commands. So we have 12 commands all in all.

    Using the .byte[noparse][[/noparse]0]-.byte to access the longs bytes seems to be more effective for me for both, memory and speed. A loop as given in Beaus example will at least optimize memory usage. I'm not sure about speed, because there we have the loop against not needed assignments to the byte_buffer.

    My original example is switching the bits keeping the byte-order. But if you remove the line with ><, it is switching the byte-order keeping the bits.
  • Brian FairchildBrian Fairchild Posts: 549
    edited 2009-04-08 20:23
    MagIO2 said...

    ...Nevertheless, the code given in the last post is not converted to assembler at all...
    What I meant to say was that they "can translate to very tight assembler needing no loops."
  • bboy8012bboy8012 Posts: 153
    edited 2009-04-08 22:23
    Sorry to be vague, LSB/MSB was meant for byte. But there are to different verisions to the problem, one is when the prop receives the data it is sent little endian style as 2 bytes. Then i tried sending it as a string and well that works, but i do not know how to add and array of byte together to produce one word. Say for example the string coming in is 8 bytes "10003000". I know to get just the "3000" part of the string would be arrayBuff[noparse][[/noparse]4], but how do I get just the first four bytes? And I am still testing the examples you guys have show me as we speak to get the results, I am looking for.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-04-09 00:03
    Hello bboy,

    to stay in your example

    an incomming string stored in a bytearray

    defined as

    VAR
    Byte arrayBuf[noparse][[/noparse]8]

    and this byte-array contains "1ABC3EFG"

    this means
    arrayBuf[noparse][[/noparse] 0] contains the "1"
    arrayBuf[noparse][[/noparse] 1] contains the "A"
    arrayBuf[noparse][[/noparse] 2] contains the "B"
    arrayBuf[noparse][[/noparse] 3] contains the "C"
    arrayBuf[noparse][[/noparse] 4] contains the "3"
    arrayBuf[noparse][[/noparse] 5] contains the "E"
    arrayBuf[noparse][[/noparse] 6] contains the "F"
    arrayBuf[noparse][[/noparse] 7] contains the "G"

    so after this explanation. Could you please post a more specific question what your problem is ?

    best regards

    Stefan

    Post Edited (StefanL38) : 4/9/2009 6:26:14 AM GMT
  • bboy8012bboy8012 Posts: 153
    edited 2009-04-09 02:47
    My appologies once again for my incompleteness. Example

    arrayBuff[noparse]/noparse = "10003000"

    temp1 := @arrayBuff[noparse][[/noparse]4]

    temp2 := @arrayBuff?? I want to only have the arrayBuff[noparse][[/noparse]0] to arrayBuff[noparse][[/noparse]3]

    print.Str(temp1) displays "3000"

    print.Str(temp2) should display only "1000" not "10003000"





    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-09 06:01
    As I understood your post, you switched to string representation because you did not manage to convert MSB to LSB endian. Do the numbers you want to transfer really have ONLY 4 digits each? The number range of a word is 0 to 65535. So, what happens with your decoding, if you only send a one digit number? What happens if you send a 5 digit number? For one or both numbers? If you send string data you should always terminate the string. For example with CR ( carriage return / $0d / 13 ). In your receiving loop you can replace that with 0 which is the string end sign for SPIN.

    Why send CR then and not 0? Because you could attach your propeller with any terminal program and feed it with numbers. No need to write a program for that until everything is tested.

    If you don't want to send CR, and you are sure you only have 4 digit numbers, you can of course add the string terminator to the bytestream in the receiving function:
    if bytecount==3
    arrayBuff[noparse][[/noparse] bytecount++ ]:=0

    Using string on the other hand means the number of bytes is variable. 4 up to 12 bytes have to be transferred (including the CR). If you want to do more than only display the numbers, you have to convert the strings back to words. So, if speed is an issue you should go back think about the words to be transferred binary. Your propeller would be the first one that is not able to switch a word from MSB to LSB endian numbers ;o)

    You see, there are a lot of ways to solve problems. Some only work, some are optimized to the needs (for example speed or codesize).

    Let's go back to the endian problem:
    You receive 2 words which is 4 bytes and store it in a receive buffer.

    byte rec_buf[noparse][[/noparse] 4 ]
    word word1, word2

    The sender sends the numbers $03E8 and $0BB8 in the following order (edit: read your post again .. it's send in·little endian and prop is using·big endian, right?):
    $03, $E8, $0B, $B8
    $E8, $03, $B8, $0B

    So, that's now the content of your rec_buf. To convert it to LSB you simply do (edit: but that does not change anything here for words):
    word1.byte[noparse][[/noparse] 0 ] := rec_buf[noparse][[/noparse] 1 ]
    word1.byte[noparse][[/noparse] 1 ] := rec_buf[noparse][[/noparse] 0 ]
    word2.byte[noparse][[/noparse] 0 ] := rec_buf[noparse][[/noparse] 3 ]
    word2.byte[noparse][[/noparse] 1 ] := rec_buf[noparse][[/noparse] 2 ]

    Post Edited (MagIO2) : 4/9/2009 6:20:18 AM GMT
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-04-09 06:37
    hello bboy,

    MagIO did already mention i

    strings are TERMINATED by a zero.

    This why you get the reuslt
    arrayBuff[noparse]/noparse = "10003000"

    temp1 := @arrayBuff

    temp2 := @arrayBuff?? I want to only have the arrayBuff[noparse][[/noparse]0] to arrayBuff

    print.Str(temp1) displays "3000"

    print.Str(temp2) should display only "1000" not "10003000"

    print.Str(temp2) runs though until it finds the first zero-VALUE $00 and then it stops
    and this is after the third "0" of "3000" "10003000"

    This means you have to add a zero at the end of EVERY bytesequence that should be treadted as a str using a .str-method
    best regards

    Stefan
  • bboy8012bboy8012 Posts: 153
    edited 2009-04-09 14:04
    Thanks StefanL38, MagIO2 for the information, it not only pointed me in the right direction, but resolved the problem.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Sign In or Register to comment.