Shop OBEX P1 Docs P2 Docs Learn Events
Array of Bytes to a "String" --- HELP!!! — Parallax Forums

Array of Bytes to a "String" --- HELP!!!

zlantzzlantz Posts: 136
edited 2013-09-02 19:04 in Propeller 1
Ok, so this seems like a simple one, but it is giving me the most trouble.

I am recieving via serial a string of bytes "$1000|1500|1250|2000|<CR>" that is servo position data from my pc. I understand that being sent via serial, it is being received one char at a time, so I can create an array with the bytes myarray[0] = $, myarray[1] = 1, myarray[2] = 0 etc, but I cannot use this data to set my servo position. I need a full string in one var ie servopos1 = 1000, servopos2 = 1500, servopos3 = 1250, servopos4 = 2000.

how do I convert myarray[#] into a "string"?

bytemove just ends up with another array[#] of individual letters.

I have tried recoding the gps readNEMA code, as it is a stream of bytes, no luck.

I have a working parsing code, but it needs a full string (myString := "1000|1500|1250|2000|<CR>") to work.

I am stuck with a one byte array string that wont convert into a full sentence and is the only thing stopping my project.

Comments

  • Mike GMike G Posts: 2,702
    edited 2013-09-02 09:43
    Welcome to the forum zlantz,

    I'm thinking - you don't want to convert the incoming byte array to a string. It looks like a packet protocol, where the packet starts with a "$" and ends with a <CR>. In between the positions are 2 byte values - most likely- sent as [LSB][MSB].

    For example, the value 1000 decimal is 0x03E8 hexadecimal. When received it looks like [0xE8][0x03].

    But that's just a guess since there's no datasheet or reference accompanying the original post.
  • zlantzzlantz Posts: 136
    edited 2013-09-02 10:29
    I think I have solved my problem just now...

    Con

    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000


    obj

    ser : "fullduplexserial"


    VAR


    PUB Main | mStr, aStr, bStr
    ser.start (31, 30, 0, 115200)

    aStr := string("ABCD")

    repeat
    mStr := 0

    AddString(mStr, aStr, string("ABcd"))

    AddString(mStr, mStr, string("1234"))

    AddString(mStr, mStr, string("$"))
    AddString(mStr, mStr, string("1"))
    AddString(mStr, mStr, string("0"))
    AddString(mStr, mStr, string("0"))
    AddString(mStr, mStr, string("0"))
    AddString(mStr, mStr, string("|"))

    ser.str(mStr)
    ser.tx(13)


    PRI AddString( dstStrPtr, srcStrPtr1, srcStrPtr2 ) | len
    len := StrSize(srcStrPtr1)
    ByteMove(dstStrPtr, srcStrPtr1, len)
    ByteMove(dstStrPtr += len, srcStrPtr2, StrSize(srcStrPtr2)+1) '+1 for zero termination


    on to parsing the data and testing with servos.

    as for a little more info on how i have it set up:

    PC running program that connects to a Raspberry Pi via tcp/ip, sends servo position data and receives sensor data

    RPi running serial to ip 2 way redirector. Connected via WiFi. (Couldnt get RN-171 working completely (no data flow))

    Prop receives servo data from RPi via serial uart and sends sensor data back

    Prop decodes servo position data & updates position.
  • zlantzzlantz Posts: 136
    edited 2013-09-02 10:42
    or not, seems to work fine if your typing the string in by hand, but not if i replace string("$") with myArray[0]
  • Mike GMike G Posts: 2,702
    edited 2013-09-02 10:45
    Wrap the SPIN code in code tags to preserve the indentation format.
    [ code ]
    ... Code here
    [ / code]

    Are you sure the transmitted data is ASCII?
  • zlantzzlantz Posts: 136
    edited 2013-09-02 10:45
    Booyah!

    Con

    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000


    obj

    ser : "fullduplexserial"


    VAR

    byte myArray[6]



    PUB Main | mStr, aStr, bStr, tmp
    ser.start (31, 30, 0, 115200)

    aStr := string(" ")

    myArray[0] := string("$")
    myArray[1] := string("1")
    myArray[2] := string("0")
    myArray[3] := string("0")
    myArray[4] := string("1")
    myArray[5] := string("|")


    repeat
    mStr := 0

    AddString(mStr, aStr, myArray[0])
    AddString(mStr, mStr, myArray[1])
    AddString(mStr, mStr, myArray[2])
    AddString(mStr, mStr, myArray[3])
    AddString(mStr, mStr, myArray[4])
    AddString(mStr, mStr, myArray[5])

    ser.str(mStr)
    ser.tx(13)


    PRI AddString( dstStrPtr, srcStrPtr1, srcStrPtr2 ) | len
    len := StrSize(srcStrPtr1)
    ByteMove(dstStrPtr, srcStrPtr1, len)
    ByteMove(dstStrPtr += len, srcStrPtr2, StrSize(srcStrPtr2)+1) '+1 for zero termination
  • AribaAriba Posts: 2,690
    edited 2013-09-02 11:00
    In your first post you say you will receive a string with the servo positions from the PC. But in your following posts you send the string to the PC. So what will you do really?

    You can replace your code above with one line: ser.str(string("$1000|1500|1250|2000|",13))

    Andy
  • zlantzzlantz Posts: 136
    edited 2013-09-02 11:52
    PC sends SERVO pos data to MCU,
    MCU sends SENSOR data to PC.

    At the same time.

    the code above was to see if it worked by displaying the rebuilt string on the serial terminal.

    in my code, ser.tx sends to propterm and rpi.tx sends to PC

    btw im still having problems. that code works fine by itself, but when i join it in my big spin it gets all funky.

    depending on how much code is running depends on weather my mcu sends/receives the correct data. one extra ser.tx(13) or anything basic can jam it all up.

    but i have PLENTY of free space (nearly 6,000 longs)

    i guess now i am having problems building the array from each recieved character. it needs to keep it self in order, $ starts <CR> ends data in the middle.

    each time i try something new it garbles all my io data.


    from the looks of it, as of right now, i can see the entire line, but it looks like the matrix on propTerm and it takes a while for one whole line to show up... i know its recieving very fast, i can un comment and recomment some code and it displays everything the pc is sending just fine.
  • AribaAriba Posts: 2,690
    edited 2013-09-02 12:22
    Okay, here is a possible solution.

    This waits for Servo data and then sends the Sensor data back. Not both at the same time. You can use a second cog if you need it at the same time. I find it much simpler to receie and parse the characters in the same methode, than first receive a string and parse it later.
    CON
     _clkmode = xtal1 + pll16x
     _xinfreq = 5_000_000
    
    VAR
     long sensorData[4]
     long servoPos[4]
    
    OBj
     ser : "FullDuplexSerial"
    
    PUB Main
     ser.start (31, 30, 0, 115200)
    
     repeat
       rxServoData
       txSensorData
    
    
    PRI txSensorData             'send 4 sensors decimal
     ser.tx("$")
     ser.dec(sensorData[0])
     ser.tx("|")
     ser.dec(sensorData[1])
     ser.tx("|")
     ser.dec(sensorData[2])
     ser.tx("|")
     ser.dec(sensorData[3])
     ser.tx("|")
     ser.tx(13)
    
       
    PRI rxServoData : v | i,ch   'receive and parse servo data
     repeat until ser.rx=="$"
     repeat i from 0 to 3
       v := 0
       repeat
         ch := ser.rx
         case ch
           "0".."9":  v := v*10 + ch-"0"
           other:     quit
       servoPos[i] := v
    
    this is not tested, but it compiles...

    Andy
  • zlantzzlantz Posts: 136
    edited 2013-09-02 12:44
    this is in no way complete but this is what i have been using to test different areas, and right now is just returning trash
    Con
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      CR = 13
    
      RPitx  = 14
      RPirx  = 15
    
      
    obj
    
      ser : "fullduplexserial"
      rpi : "fullduplexserial"
      
    
    VAR
    
      long Servo1Pos, Servo2Pos, Servo3Pos, Servo4Pos, Servo5Pos, Servo6Pos, TxPower   ' RN-171 Storage
      long IR[12], BMP085_Pressure, HIH6130_Temp, HIH6130_Humidity                     ' Sensor Storage
      long Accel[3], Gyro[3], Magnet[3], RSSI                                          ' Sensor Storage
    
      long Altitude, Valid, Speed, Heading, Date, GPSaltitude, Time                    ' GPS Info
      long Latitude, N_S, Longitude, E_W, Satellites, Hdop, Vdop                       ' GPS Info                   
    
      long Data_stack[20], Build_stack[20]  
      long cog, cog2, cptr
    
      byte SVO_buff[23], sPos     
    
      
    PUB Main | mStr, aStr
      ser.start (31, 30, 0, 115200)                ' To Prop Term
      rpi.start (RPirx, RPitx, 0, 57600)           ' To Raspberry Pi to PC
      
      cog  := cognew(DoRelay,    @Data_stack)  + 1 ' Data Relay
      cog2 := cognew(BuildArray, @Build_stack) + 1 ' Data Relay
    
      repeat
    
        SendDataRPi
         
        'Tmp := MakeStr
         
        ser.str(sPos)
        ser.tx(13)
         
        'if strsize(sPos) > 0
        '  ser.tx(sPos)
        '  ser.tx(13)
          
         
    Pri BuildArray                  ' *** Runs in own cog
    
      repeat
         
        bytefill(svo_buff , 0, 23)
        
        repeat until sPos == "$"      ' wait for the $ to insure we are starting with
    
        cptr := 0
    
         
        repeat until sPos == CR       '  continue to collect data until the end of the NMEA sentence 
    
          svo_buff[cptr++] := sPos   '  else save the character                        
           
            
         
    Pri DoRelay | TmpData, TmpData2  ' *** Runs in own cog    ( Any Delay will cause data to become garbled )
    
      repeat
              
        TmpData := rpi.rxCheck       ' Echo RPi Data  *** Had to use .rxCheck as .rx would just hang
        TmpData2 := ser.rxCheck      ' Echo Ser Data
                                                                                                         
        if TmpData > 0               ' Send RPi to PropTerm                                  
          sPos := TmpData            ' Export Data to Main Loop
          
        if TmpData2 > 0              ' Send PropTerm to RPi                                  
          rpi.tx(TmpData2)           ' *** Contains Debug Raw Write
    
          
    Pri MakeStr | mStr, aStr  
                                         
      ' Currently Data = "$1500|1000|1250|2000|<CR>"  for servos 1, 2, 3, & 4   but sPos is only 1 char per rx     
    
      aStr := 13    ' *** Must Start with "something"
    
      mStr := 0     ' Reset myString
       
      ' 22 chars including CR
       
      AddString(mStr, aStr, SVO_buff[0])     ' Starts with <CR>
      AddString(mStr, mStr, SVO_buff[1])     ' $
      AddString(mStr, mStr, SVO_buff[2])
      AddString(mStr, mStr, SVO_buff[3])
      AddString(mStr, mStr, SVO_buff[4])
      AddString(mStr, mStr, SVO_buff[5])     
      AddString(mStr, mStr, SVO_buff[6])     ' |
      AddString(mStr, mStr, SVO_buff[7])
      AddString(mStr, mStr, SVO_buff[8])
      AddString(mStr, mStr, SVO_buff[9])
      AddString(mStr, mStr, SVO_buff[10])    
      AddString(mStr, mStr, SVO_buff[11])    ' |
      AddString(mStr, mStr, SVO_buff[12])
      AddString(mStr, mStr, SVO_buff[13])
      AddString(mStr, mStr, SVO_buff[14])
      AddString(mStr, mStr, SVO_buff[15])    
      AddString(mStr, mStr, SVO_buff[16])    ' |
      AddString(mStr, mStr, SVO_buff[17])
      AddString(mStr, mStr, SVO_buff[18])
      AddString(mStr, mStr, SVO_buff[19])
      AddString(mStr, mStr, SVO_buff[20])    
      AddString(mStr, mStr, SVO_buff[21])    ' |
      AddString(mStr, mStr, SVO_buff[22])    ' <CR>     *** Might get removed
       
          
      return mStr   
    
      
    Pri AddString( dstStrPtr, srcStrPtr1, srcStrPtr2 ) | len
      len := StrSize(srcStrPtr1)
      ByteMove(dstStrPtr, srcStrPtr1, len)
      ByteMove(dstStrPtr += len, srcStrPtr2, StrSize(srcStrPtr2)+1)   '+1 for zero termination
                
     
    Pri SendDataRPi                    ' Send Data to Base Station (Wifi Out)
         
        ' $GPRMC,081836,A,3751.6565,S,14507.3654,E,000.0,360.0,130998,011.3,E*62
        ' $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75
        ' $PGRMZ,453,f,2*18
    
        rpi.str(string("$GPS"))    ' GPS
        rpi.str(string(","))
        rpi.dec(0)
        'rpi.dec(GPS.Altitude)
        rpi.str(string(","))
        'rpi.dec(GPS.Valid)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Speed)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Heading)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Date)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.GPSaltitude)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Time)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Latitude)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.N_S)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Longitude)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.E_W)
        rpi.dec(0)
        rpi.str(string(","))
        'rpi.dec(GPS.Satellites)
        rpi.dec(0)
        rpi.str(string(","))    
        'rpi.dec(GPS.Hdop)
        rpi.dec(0)
    '    rpi.str(string(","))
    '    rpi.dec(GPS.Vdop)
    '    rpi.tx(13)         
        
        
    
  • zlantzzlantz Posts: 136
    edited 2013-09-02 12:52
    Ok u did it! had to swap a few things around but this is showing correct data from my pc now:
    CON
     _clkmode = xtal1 + pll16x
     _xinfreq = 5_000_000
    
     
    VAR
     long sensorData[4]
     long servoPos[4]
    
     
    OBj
     ser : "FullDuplexSerial"
     rpi : "fullduplexserial"  
     
    PUB Main
     ser.start (31, 30, 0, 115200)
     rpi.start (15, 14, 0, 57600)           ' To Raspberry Pi to PC
     
     repeat
       rxServoData
       ShowServoData
    
    
    PRI ShowServoData  | i           'send 4 sensors decimal
    
      ser.tx(0)
    
      repeat i from 0 to 3
        ser.str(string("Servo "))
        ser.dec(i)
        ser.str(string(" Pos: "))
        
        ser.dec(servoPos[i])
    
        ser.tx(13)
       
    PRI rxServoData : v | i,ch   'receive and parse servo data
     repeat until rpi.rx=="$"
     repeat i from 0 to 3
       v := 0
       repeat
         ch := rpi.rx
         case ch
           "0".."9":  v := v*10 + ch-"0"
           other:     quit
       servoPos[i] := v
       
    
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 12:59
    I am recieving via serial a string of bytes "$1000|1500|1250|2000|<CR>" that is servo position data from my pc.


    As a matter of curiosity, what PC program are you using to send this data? (I do a lot of work with animatronics)
  • zlantzzlantz Posts: 136
    edited 2013-09-02 13:02
    OMFG IT WORKS! HAHA! on to getting this thing hooked up to my helicopter!

    Thank you soo much!

    Zack




    but exactly how does that handle the parsing?? if i were to change my chars around i would have no clue were to start. (notibly i probibly wont, but would still like to know)
  • zlantzzlantz Posts: 136
    edited 2013-09-02 13:03
    JonnyMac - i wrote my own vb6 progrm to handle it
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 13:12
    Got it.

    You may want to add a bit of flexibility to your receive and parse routine -- right now it's locked into a specific array and number of servos. Simple changes let you point that code to another/different array, and work with any number of servos.
    pub rx_servos(p_dest) | c, idx, value
    
    '' Receive and parse servo positions
    '' -- p_dest is address of servo positions array (words)
    
      repeat
        c := serial.rx
        if (c == "$")
          quit
    
      idx := 0
    
      repeat
        value := 0
        repeat
          c := serial.rx
          case c
            CR:
              return
          
            "0".."9":
              value := (value * 10) + (c - "0")
    
            other:
              word[p_dest][idx++] := value
              quit
    
  • AribaAriba Posts: 2,690
    edited 2013-09-02 13:20
    zlantz wrote: »
    OMFG IT WORKS! HAHA! on to getting this thing hooked up to my helicopter!

    Thank you soo much!

    Zack





    but exactly how does that handle the parsing?? if i were to change my chars around i would have no clue were to start. (notibly i probibly wont, but would still like to know)

    Cool that it works (no clue what the F in OMFG could mean ;-)

    How the parsing works:
    First it waits until a "$" is received.
    Then it receives every numeric character and "shifts" it in as the lowest digit of the decimal number.
    If a not numerical character is received it must be the ending "|" and the decimal value is stored to the ServoData array.
    This is repeated 4 times.
    The CR is not tested (it is not necessary for the data, but it is useful if you show it on the Terminal).

    Andy
  • zlantzzlantz Posts: 136
    edited 2013-09-02 17:05
    so if i wanted to add some extra data other than servo positions, how would i be able to include it?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 19:04
    so if i wanted to add some extra data other than servo positions, how would i be able to include it?

    Any way you want! -- you wrote the PC program that's sending values.

    One thought is to use a different header character to send different groups of values. Of course, you'd have to modify the parser routine as the header character would now be used to determine the destination of values.
Sign In or Register to comment.