Shop OBEX P1 Docs P2 Docs Learn Events
SparkFun GPS mini-mod string help — Parallax Forums

SparkFun GPS mini-mod string help

grasshoppergrasshopper Posts: 438
edited 2009-02-23 23:55 in Propeller 1
I made a very crude object for the SparkFun GPS mini-mod www.sparkfun.com/commerce/product_info.php?products_id=8416

My question is how can I pack more than 4 byes into a long variable? I receive data from the module in a byte array and typically I can pack them into a long (4 bytes make a long) as long as the string is => 4 bytes.

Take a look at the code
obj

  Ser             :             "FullDuplexSerial"
  Math            :             "FloatMath"
  
Var
      byte SerialData[noparse][[/noparse] 70 ]
      byte Float_String[noparse][[/noparse] 20 ]       
      Long Array[noparse][[/noparse] 30 ]
      
Pub loadcogs | Scrap
          
  ser.start(0,30,0,baud)
  waitcnt (500_000 + cnt ) 
  
  Repeat
       If (ser.rxcheck == $24)
         GetCom
         
      GetTime(@SerialData[noparse][[/noparse] 5 ]) [b]' This is my troubled area cause the first 5 bytes are letters[/b]  
        
Pub getcom | stringCount

  StringCount~
  
  Repeat until (SerialData[noparse][[/noparse] StringCount ] := Ser.rx ) == "*"         
      StringCount ++

Pub GetTime(In) | Int, Dec, Sign, X, Letter 

  Int~
  Dec~
  Sign~
  Letter~
  X := 0
  
  Repeat Until(byte[noparse][[/noparse] In ] == $2A)
  
      Case byte[noparse][[/noparse] In ]
      
          $2D:                  Sign := 1
                    
          $2E:                  Dec := 1
          
          $30..$39:             Int := Int * 10 + byte[noparse][[/noparse] In ] - $30
                                IF Dec 
                                                        Dec++
                                                        
          $41..$5A:             Letter := 1
                                Array[noparse][[/noparse] X ] := byte[noparse][[/noparse] In ]
                                                                                                                                          
          $2C:
                                IF Letter    
                                                        Int~
                                                        Dec~
                                                        Sign~
                                                        Letter~                                                         
                                                        X++
                                                                                                                                                                  
                                IF Sign
                                                        Int := -Int                                                        
                                                        Array[noparse][[/noparse] X ] := math.FFloat(Int)
                                                        Int~
                                                        Dec~
                                                        Sign~
                                                        Letter~
                                                        X++
                                                                                               
                                IF Dec
                                                        Array[noparse][[/noparse] X ] := math.FFloat(Int) 
                                                        Repeat Dec - 1
                                                            Array[noparse][[/noparse] X ] := Math.FDiv(Array[noparse][[/noparse] X ],10.0)                                                                                                                                                                                                                                  
                                                        Int~
                                                        Dec~
                                                        Sign~
                                                        Letter~
                                                        X++
                                                       
      In++




My troubled area is that the first 5bytes are letters and I need to pack them into a long so that I can look up commands in a table. Otherwise this whole program works.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Those who criticize our generation forget who raised it.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2009-02-22 21:08
    You can't pack more than 4 bytes into a long. Longs are only 32 bits in length and there's no place to put the 5th set of 8 bits.

    If you encode characters differently, you can pack more than 4 characters into a 32 bit word.
    For example, you can represent 26 letters, 10 digits and quite a few punctuation characters in 6 bits with appropriate conversion.
    5 of these will fit in a 32 bit long. The easiest way to do this would be to check that the character is between $20 and $5F, convert
    all the lower case letters to upper case, and discard all the rest. You'd then subtract $20 to get a value between $00 and $3F and
    pack them into a 32 bit long. You'd have to write some kind of utility program to allow you to type in a command and it would do
    the translation into a 32 bit hex value which you could copy down or cut and paste into your program.

    It's not hard to write a subroutine to look up one string in a table of strings and return the table entry number for use in a CASE
    statement. FemtoBasic uses a table like this. Have a look at the "tokenize" routine.

    Post Edited (Mike Green) : 2/22/2009 9:15:34 PM GMT
  • grasshoppergrasshopper Posts: 438
    edited 2009-02-22 22:11
    Mike I think I understand what you are suggesting. Follow me here and see if I am on to the idea.

    Steps

    1. Allow data to be received from $20 to $5A this translates as Space - Z (I wont need lowercase letters)
    2. Take data and subtract $20 from it thus making Space = $0, 1 = $10 and A = $21 etc...
    3. Pack into a long

    This seems right? Ill start some type of code to do this.

    *Edited - How do I squeeze this all into 6bits? Should I use Decimal instead of hex ?

    Mike you are always a great help and...
    ...Thanks!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Those who criticize our generation forget who raised it.
  • kwinnkwinn Posts: 8,697
    edited 2009-02-22 22:56
    It is already "squeezed" into 6 bits. All the upper bits should be 0. Just make sure the input is from Space - Z before doing the subtract otherwise you will get incorrect results.
  • grasshoppergrasshopper Posts: 438
    edited 2009-02-23 15:25
    I still cant figure out how i can get all that information in 6 bits?

    I mean a hex value is still A Byte right?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Those who criticize our generation forget who raised it.
  • J. A. StreichJ. A. Streich Posts: 158
    edited 2009-02-23 20:46
    Are you running that low on space that your worried about packing the data into a single long, or is there another reason why it must fit into a long?

    ASCII doesn't use the top bit. It only uses the lower 7. You scheme of subtracting ASCII value of space should work to get that down to even less (6?).
    What you need to do after that transformation is to fit them into the long by shifting and ORing.

    A Hex value is representation of bits. A two digit hex number will fit inside a byte.
  • grasshoppergrasshopper Posts: 438
    edited 2009-02-23 21:00
    Well I figured after i received the data I would pack it all into a long like this

    
     Data := ((SerialData [noparse][[/noparse] 0 ] << 24) | (SerialData [noparse][[/noparse] 1 ] << 16) | (SerialData [noparse][[/noparse] 2 ] << 8) | SerialData[noparse][[/noparse] 3] ) 
    
    
    



    **Scratches head // Must do this differently

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Those who criticize our generation forget who raised it.
  • kwinnkwinn Posts: 8,697
    edited 2009-02-23 23:40
    Grasshopper, the basic ascii character set consists of 128 symbols represented by numbers from 0 to 127. To any computer they are just binary numbers. Seven bits are all that is required to represent all 128 ascii characters. If you only need 64 (or fewer) characters you can represent them in 6 bits (0 to 63). For the characters you are interested in, (space), which is 20 hex or 32 decimal, to Z, which is 5A hex or 90 decimal you would need to represent (90 - 32) +1 = 59 characters which can fit in 6 bits.
    What you need to do for each character is:
    1 - Make sure it is not less than 20 hex and not greater than 5A hex
    2 - Subtract 20 hex from the character. Now you have a number between 0 and 3A hex, 3A hex being 0011 1010 in binary or 58 decimal
    3 - Add this to your long and shift it left 6
    4 - Repeat for the next four characters

    You will end up with 5 characters squeezed into 30 bits of a long. I think the code you have will work (not a spin expert yet) provided you adjust it to shift 6 bits instead of 8

    Data := ((SerialData [noparse][[/noparse] 0 ] << 24) | (SerialData [noparse][[/noparse] 1 ] << 18) | (SerialData [noparse][[/noparse] 2 ] << 12) | SerialData[noparse][[/noparse] 3] << 6 | SerialData[noparse][[/noparse] 4] )
  • Mike GreenMike Green Posts: 23,101
    edited 2009-02-23 23:55
    pri packItIn(currentValue,newChar) : newValue
       case newChar
          "a".."z":
             newValue := (currentValue << 6) | (newChar - "a" + "A" - " ")
          "0".."9", "A".."Z": 
             newValue := (currentValue << 6) | (newChar - " ")
    


    For each new character C, call "Data := packItIn(Data,C)". You can fit 5 characters into a long this way.
Sign In or Register to comment.