Shop OBEX P1 Docs P2 Docs Learn Events
Process serial string input? — Parallax Forums

Process serial string input?

Just checking before reinventing some wheels...

Getting data input on a P2 pin as TTL serial text.
The data string looks like this:

VAC1=3.99e+01 VAC2=2.17e-01 VAC3=9.04e+02

Is there something already that can turn a string into a float?

Would also be convenient if something could parse this input, but guessing not...

Comments

  • JonnyMacJonnyMac Posts: 9,269

    This probably won't help -- but maybe it will inspire something. Last year I helped a friend who wanted to send floats through serial commands. I used my standard parser to get the chunks out of the string, and then this simple code to convert values from string to float. It doesn't support scientific notation though.

  • RaymanRayman Posts: 15,108

    Thanks @JonnyMac, this does look like will help.

  • RaymanRayman Posts: 15,108

    tokenizer seems to work.
    Zero based token index.
    Seems rigged to tokenize on white space.
    got the input parsed into three strings now.
    Close to having it done...

  • RaymanRayman Posts: 15,108

    Actually want to process input from two serial ports. Don't want to waste cogs though.
    Fortunately, found the @"Stephen Moraco" 8x serial input code in OBEX:
    https://obex.parallax.com/obex/p2-high-speed-8-port-serial-subsystem/

  • JonnyMacJonnyMac Posts: 9,269
    edited 2025-04-09 20:50

    got the input parsed into three strings now.

    You probably have this sorted, but I knocked this together while having lunch and waiting on the Zoom call. It will take a "parameter=value" string and breaks up the parts, filling strings you specify.

    pub parse_cmd_value(p_str, p_cmd, p_val) | i
    
      i := find_chr("=", p_str)                                     ' look for separator
    
      if (i < 0)                                                    ' abort if not found
        return
    
      bytemove(p_cmd, p_str, i)                                     ' copy command to own string
      byte[p_cmd][i] := 0
    
      i++                                                           ' skip separator
    
      bytemove(p_val, p_str+i, strsize(p_str)-i)                    ' copy value to own string
      byte[p_val][strsize(p_str)-i] := 0 
    
    
    pub find_chr(c, p_str) : pos  
    
    '' Return index of first occurance of c in p_str
    '' -- returns -1 if not found
    
      repeat pos from 0 to strsize(p_str)-1 
        if byte[p_str][pos] == c
          return 
    
      return -1
    

    I almost have parsing an FP string in Scientific notation working.

  • JonnyMacJonnyMac Posts: 9,269
    edited 2025-04-10 16:28

    This gets a little long, but -- so far -- seems to work. I added the ability to detect sci-notation and deal with the exponent. I checked the return values using this page:
    -- https://www.h-schmidt.net/FloatConverter/IEEE754.html

    pub str2fp(p_str) : result | sign, dpflag, d, e, b      
    
    '' Convert string to floating point
    '' -- legal characters: "-", "+", "0".."9", ".", "E", "e"
    
      repeat                                                        ' strip leading spaces
        if (byte[p_str] == " ")
          p_str++
        else
          quit
    
      sign, dpflag, d := 1.0, false, 1                              ' preset locals
    
      if (byte[p_str] == "-")                                       ' check for sign
        sign := -1.0                                                '  set
        p_str++                                                     '  skip
      elseif (byte[p_str] == "+")
        p_str++
    
      repeat                                                        ' get significand 
        b := byte[p_str++]                                          ' get byte from string    
        case b
          "e", "E", " ", 0 :                                        ' done?
            quit
    
          "0".."9" :                                                                             
            result := (result * 10) + (b - "0")                     ' add new digit                
            if (dpflag)                                             ' past dpoint                  
              d *= 10                                               '  yes, bump divisor           
    
          "." :                                                                                  
            if (dpflag == false)                                    ' new decimal point?                      
              dpflag := true                                        ' set flag
            else
              return 0.0                                            ' invalid 2nd decimal point                                                                
    
          other :                                                                                
            return 0.0                                              ' illegal character
    
      result := sign *. float(result) /. float(d)
    
      if (b <> "e") && (b <> "E")                                   ' done if no exponent
        return
    
      sign, e := 1.0, 0                                             ' reset for exponent
    
      if (byte[p_str] == "-")                                       ' check for exponent sign
        sign := -1.0
        p_str++
      elseif (byte[p_str] == "+")
        p_str++        
    
      repeat                                                        ' get exponent
        b := byte[p_str++]
        case b
          0, " " :
            quit
    
          "0".."9" :                                                                            
            e := (e * 10) + (b - "0")
    
          other :                                                                             
            return
    
      if (e == 0)                                                   ' done if exponent == 0
        return
    
      ' adjust significand with exponent
    
      if (sign == 1.0)
        result := result *. float(XPower[e])
      else
        result := result /. float(XPower[e])  
    
    
    dat
    
      XPower        long    1                                       ' 10 ^ 0
                    long    10
                    long    100
                    long    1_000
                    long    10_000
                    long    100_000
                    long    1_000_000
                    long    10_000_000
                    long    100_000_000
                    long    1_000_000_000                           ' 10 ^ 9
    
  • RaymanRayman Posts: 15,108

    For this app, there's a very limited range of exponents possible.
    So, just did significand and exponent separately.
    Also, turning this Torr floating point value into integer number of milliTorr....

    Processed exponent like this:

    pub sExponent_To_Factor(p):fac  'Turn exponent into a factor to multiply significand by
    'Neet to turn "-03" into 1 and "+03" into 1_000_000
      if strcomp(p,string("-03"))==-1
        return 1
      if strcomp(p,string("-02"))==-1
        return 10
      if strcomp(p,string("-01"))==-1
        return 100
      if strcomp(p,string("-00"))==-1
        return 1_000
      if strcomp(p,string("+00"))==-1
        return 1_000
      if strcomp(p,string("+01"))==-1
        return 10_000
      if strcomp(p,string("+02"))==-1
        return 100_000
      if strcomp(p,string("+03"))==-1
        return 1_000_000
    
  • JonnyMacJonnyMac Posts: 9,269

    Cool.

Sign In or Register to comment.