Shop OBEX P1 Docs P2 Docs Learn Events
Prop Communicating with VB2010 — Parallax Forums

Prop Communicating with VB2010

eagletalontimeagletalontim Posts: 1,399
edited 2013-11-24 18:13 in Propeller 1
Good Evening! I am working on some communication issues with a VB10 program I am using to communicate with the Prop. Right now, I have run into a strange problem and maybe I am going about it the wrong way. What I am attempting to do is to send a string from the Prop to the VB program and visa versa. Right now, I am just trying to read from prop which is working, but is not constant. Sometimes the "string is empty". I was thinking it was because I am sending each string via Ser.tx("x") instead of using Ser.str(string("stuff to send")).

The problem with using Ser.str() is that I cannot add variable values to this string. Example (x = 20, y = 50) : Ser.str(string("The value of x =" : x : " and the value of y = " : y)) This is only an example and is not what the string consists of. I was also thinking of sticking with the Ser.tx() and just send a "start character" like "^" and an end character like "#". The VB program will just store any value after the "^" and then display the info once the "#" is received which determines the end of line.

So what I am trying to determine is how to send a string to VB from the prop as quickly as possible without losing data.
«1

Comments

  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-08 05:54
    Hi, one of the faster methods is to transmit an array of bytes
    Repeat 10
    	Ser.tx(mybyte[i])
    	i ++
    

    If the data length varies you might include the data length in the first byte rather than transmit a fixed length array, you may also want to include a checksum.

    Other things to take into consideration are the type of data, how much data and how it's handled by your Visual Basic application.

    Can you give an example of the data to be transmitted.

    Parallax also have an application note on Prop + Vb communications, I dont remember the AN number off hand.

    Jeff T.
  • Mike GMike G Posts: 2,702
    edited 2013-11-08 08:10
    I have to assume you are using the serial port object, Win Form, and datareceived event... Missing data in this setup is usually due to making assumptions on the number of bytes received. If you're polling the port, logic error are usually in the framing logic.

    Post your code!
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-08 16:26
    I am using the Serial port instead of the old MScomm since it is much more updated and seems to work pretty good right now. Here is part of the code right now :

    Prop (Just the code that is processed to send information to the VB program) :
      repeat
        Ser.tx("^")
        Ser.dec(Time_Count_Hours)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds)
        Ser.tx(":")
        Ser.dec(Time_Count_Minutes)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds + Time_Count_Seconds)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds + Time_Count_Minutes)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds + Time_Count_Seconds + Time_Count_Minutes)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds * Time_Count_Seconds)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds * Time_Count_Minutes)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds * (Time_Count_Seconds + Time_Count_Minutes))
        Ser.tx("#")
        'repeat until Ser.rx == "#"
    
          waitcnt(clkfreq / 100 * 5 + cnt)
    
        Ser.rxflush
    

    Then the VB Receiving and processing code :
        Public Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            Dim inbound As String
            Dim StartChar As String = "^"
            Dim EndChar As String = "#"
            Dim TestStartPos As Integer
            Dim TestEndPos As Integer
            Dim Parsed_String As String
    
            inbound = SerialPort1.ReadExisting
            If inbound <> Nothing Then
                incoming_string += inbound
            End If
    
            TestStartPos = InStr(incoming_string, StartChar)
            TestEndPos = InStr(incoming_string, EndChar)
    
            If TestStartPos <> 0 And TestEndPos <> 0 Then
                Parsed_String = Mid(incoming_string, TestStartPos, TestEndPos)
                SetText(incoming_txt, incoming_string)
                incoming_string = String.Empty
            End If
        End Sub
    

    The VB code above is receiving data and putting the characters it into a string. As soon as the Beginning character "^" is found and the End character "#" is found in the string, everything before the string is stripped and the string is parsed as only usable data. This appears to be working great for me so far. If there is a better way, please let me know!
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-08 20:07
    If it's working ok then go with it. Your transmitted data could have the transmit time reduced by 2/3 if you only sent the hours, seconds and minutes once and calculated the remaining values in your VB application
    repeat
        Ser.tx("^")
        Ser.dec(Time_Count_Hours)
        Ser.tx(":")
        Ser.dec(Time_Count_Seconds)
        Ser.tx(":")
        Ser.dec(Time_Count_Minutes)
        Ser.tx("#")
    

    Jeff T.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-08 20:12
    I only sent the extra data to see how much I could send and how fast I could send it. Just trying to send non-equal data so I could test it. The time stuff is just for testing right now. It is not actual data that will be transmitted between the prop and the computer. The final code will probably be sending over 50 different variables and they must all be sent without losing any information. Here soon, I will be attempting to send information from VB to the prop to store specific information into the upper 32k of the EEPROM in dedicated addresses unless there is an easier / faster way to store variables into the EEPROM. I am still learning about storing to it, but I think I can learn it pretty quickly.
  • ozpropdevozpropdev Posts: 2,792
    edited 2013-11-08 20:37
    I've had VB10 reading data at 1M baud fine, so speed should be Ok.
    Be aware of the encoding property when you want to send/receive the full range of bytes (0 to 255).
    If the encoding is not set, it will only process ascii characters. Other codes are ignored.
            SerialPort1.Encoding = System.Text.Encoding.GetEncoding("windows-1252")
    
  • Mike GMike G Posts: 2,702
    edited 2013-11-09 05:37
    The DataReceived logic assumes incoming_string is one packet; starts with a ^ and ends with #. Depending on system resources and the speed at which the prop sends data there could be more than one packet in incoming_string. In this case, the logic will drop packets.

    If it were me, I'd stay away from converting to ASCII and send actual values. 1) It's less processing 2) The value byte lengths (data type) within the packet are always the same.
  • localrogerlocalroger Posts: 3,451
    edited 2013-11-09 12:24
    I've been doing this for many years, since VB3 and 4. Mike G is right, your logic will drop packets.

    Pseudocode for what you should be doing:
    BufferStr += all available incoming data
      While instr(startchr)>0 and instr(endchr)>instr(startchr)
        BufferStr = right$(BufferStr, instr(BufferStr, startchr))
        MSG = left$(BufferStr, instr(BufferStr, endchr)
        BufferStr = right$(BufferStr, len(BufferStr) - len(MSG)
    

    This way if you get half a message or two messages in one read attempt, you parse and process them all.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-09 12:57
    I was trying to prevent a "While" loop, but I am not quite following what the above is doing.
    BufferStr += all available incoming data  ' VB Code : inbound = SerialPort1.ReadLine / .ReadByte / .Read ?
      While instr(startchr)>0 and instr(endchr)>instr(startchr)  ' If the "end" character got lost in transit, this while loop would hang the program.
        BufferStr = right$(BufferStr, instr(BufferStr, startchr))  '  I am guessing this reads all characters after the "start character"
        MSG = left$(BufferStr, instr(BufferStr, endchr)  ' this turns the variable MSG into all characters before the "end character"
        BufferStr = right$(BufferStr, len(BufferStr) - len(MSG) ' Not sure what this is doing.
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-09 13:40
    Ok, here is my VB code so far.... It is only returning the # of the string and nothing else.
            inbound = SerialPort1.ReadExisting
            If inbound <> Nothing Then
                BufferStr += inbound
            End If
    
            While InStr(BufferStr, StartChar) > 0 And InStr(BufferStr, EndChar) > InStr(BufferStr, StartChar)
                BufferStr = Microsoft.VisualBasic.Right(BufferStr, InStr(BufferStr, StartChar))
                Parsed_String = Microsoft.VisualBasic.Left(BufferStr, InStr(BufferStr, EndChar))
                SetText(inbound_txt, Parsed_String)
                BufferStr = Microsoft.VisualBasic.Right(BufferStr, Microsoft.VisualBasic.Len(BufferStr) - Microsoft.VisualBasic.Len(Parsed_String))
            End While
    
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-09 14:42
    Hi, Mike G is absolutely right, transmitting and receiving binary data is much faster than ASCII string data.

    With regard to receiving ASCII from the Prop, if you are still interested in examining how this performs, I have a few ideas you might find helpful. There is more than one way to do this so what I write is my own personal opinion for this situation.

    Firstly I have never been a fan of ReadExisting, I prefer ReadLine when reading ASCII strings. ReadLine reads a string that is terminated with a NewLine character (decimal 10) so already the need for the hash/pound character is eliminated. Using the carat as a start character and decimal 10 as the termination value we can force the DataReceived event handler to "block" until all the string has arrived.
    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
    
            SerialPort1.ReadTimeout = 200
            Dim indata As String = String.Empty
    
            Try
    
                indata  = SerialPort1.ReadLine
    
                If indata.Substring(0, 1) = "^" Then  'check the value of the first character
    
                    indata = indata.Substring(1, indata.Length - 1) 'assign the string except the first character to indata
    
                    'do what you need to do with indata
    
                End If
    
            Catch ex As Exception
    
            End Try
    
        End Sub
    

    The only modification your Prop code needs is to replace Ser.tx("#") with Ser.tx(10)

    Jeff T.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-09 15:29
    That seems to work pretty well. I tested different wait speeds on the prop to see how fast I could send data reliably and I found I could send a little faster, but it crashed the program if I tried to send too fast. I am going to let it run for an hour or so to see if it crashes with the current speed.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-09 16:15
    Hi, when you say crashed I'm guessing you mean the VB application.

    If the Prop is transmitting data faster than the methods in VB are able to handle it the serial port buffer will over run and your app will hang or crash, if there is a predetermined amount of data to transmit you might possibly get away with just increasing the SerialPort1.ReadBufferSize, (worth trying to see the effect), the second option is to improve the methods VB is using to handle the data, such as creating separate threads.

    Jeff T.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-11 17:43
    Well, I got the prop to send data to the PC, but now I am having troubles sending data from the PC to the Prop :(

    Here is some code I am trying :
    ' This is running in a COG
    PUB readData
        repeat
          var2 := Ser.rxcheck ' check for any incoming data
          if var2 > -1 ' if any data, proceed
            var1 := 1 ' disable Live Data sending loop in previous code
            Ser.tx(var2) ' send what was sent from the PC back to the PC to see any communication
            
          else
            waitcnt(clkfreq / 100 * 100 + cnt) ' wait long enough to visibly see change on PC
            var1 := 0 ' then start or keep alive Live Data loop
            
          waitcnt(clkfreq / 100 * 7 + cnt) ' Send data this fast.
    

    VB Code :
    ' Sub that does something when data is received :
                indata = SerialPort1.ReadLine
                'SetText(Label19, indata)
    '........
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            SerialPort1.WriteLine("#thisisonlyatest")
        End Sub
    

    Any ideas on why "Label19" is empty most of the time. On first start, some of the data is sent, but is mostly lost.
  • Mike GMike G Posts: 2,702
    edited 2013-11-12 04:22
    I'm guessing there are logic errors elsewhere in your code base. Can't help troubleshoot logic we can't see.

    Attached is an echo demo. Make sure to set the port and baud.

    Spin
    CON
      _clkmode = xtal1 + pll16x     
      _xinfreq = 5_000_000
    
    OBJ
      serial        : "FullDuplexSerial"
    
    PUB Main | char
      serial.Start(31, 30, %0000, 115_200)  
      waitcnt(cnt + (1 * clkfreq))
      'serial.str(string("Echo Test", 13))                          
    
      repeat
        if not (char := serial.rxcheck) == -1
          serial.tx(char)
    

    VB.Net console
    Imports System.IO.Ports
    Imports System.Threading
    
    Module Module1
        Dim sp As SerialPort
    
        Sub Main()
            'Initialize the serial port
            sp = New SerialPort()
            sp.PortName = "COM6"
            sp.BaudRate = 115200
            sp.ReadTimeout = 500
            sp.WriteTimeout = 500
            AddHandler sp.DataReceived, AddressOf DataReceivedHandler
    
            sp.Open()
            While (True)
                sp.WriteLine("Hello World")
            End While
    
        End Sub
    
        Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
            Dim bytes = sp.BytesToRead
            Dim buff(bytes) As Byte
    
            'Write buffered bytes tothe console
            Dim len = sp.Read(buff, 0, bytes)
            Console.Write(System.Text.Encoding.ASCII.GetString(buff))
        End Sub
    
    End Module
    

    See... I posted all the code. That's not so hard, right?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-17 12:50
    Well this is getting frustrating.... I can send and receive data from the prop....most of the time.... Getting all of the data to the "EndChar" is a hit or miss for some reason. I have a button that I press on my VB program that send the character "R" to the Prop which is then supposed to tell the prop to send all "User_Setting" Variables to the PC for editing. Most of the time, all the variables are sent, but some times, the very end is lost so ALL variables are not sent. I need this to be "fail safe" so that all data will be sent all the time. Please note, I am using VB10 since I am still using Windows XP.
    VAR
      LONG serial_stack[100]
    
    OBJ
      eeprom : "Propeller_Eeprom" 
      serial : "FullDuplexSerial" 
    
    DAT
    
    User_Setting1           LONG    3                      
    User_Setting2           LONG    1500                  
    User_Setting3           LONG    1                      
    User_Setting4           LONG    1                      
    User_Setting5           LONG    3                       
    User_Setting6           LONG    3                       
    User_Setting7           LONG    370                    
    User_Setting8           LONG    30                      
    User_Setting9           LONG    255            
    User_Setting10          LONG    750             
    User_Setting11          LONG    50            
    User_Setting12          LONG    1
    User_Setting13          LONG    1 
    User_Setting14          LONG    0                      
    User_Setting15          LONG    1                     
    User_Setting16          LONG    0                     
    User_Setting17          LONG    0                     
    User_Setting18          LONG    1                     
    User_Setting19          LONG    0                    
       
    End_User_Settings
    
    PUB Main
    
      eeprom.VarRestore(@User_Setting1,@End_User_Settings)
    
      cognew(Handle_USB, @serial_stack)
    
    PUB Handle_USB | char, log
      serial.Start(31, 30, %0000, 115_200)  
      pause(10)
      log := 0
      repeat
        if not (char := serial.rxcheck) == -1
          if char == "R"  ' Load User_Setting Values to PC
            repeat until (char := serial.rxcheck) == "Y"   ' Ensure data was received by PC successfully.
              serial.tx("^")
              serial.dec(User_Setting1)
              serial.tx(":")
              serial.dec(User_Setting2)
              serial.tx(":")
              serial.dec(User_Setting3)
              serial.tx(":")
              serial.dec(User_Setting4)
              serial.tx(":")
              serial.dec(User_Setting5)
              serial.tx(":")
              serial.dec(User_Setting6)
              serial.tx(":")
              serial.dec(User_Setting7)
              serial.tx(":")
              serial.dec(User_Setting8)
              serial.tx(":")
              serial.dec(User_Setting9)
              serial.tx(":")
              serial.dec(User_Setting10)
              serial.tx(":")
              serial.dec(User_Setting11)
              serial.tx(":")
              serial.dec(User_Setting12)
              serial.tx(":")
              serial.dec(User_Setting13)
              serial.tx(":")
              serial.dec(User_Setting14)
              serial.tx(":")
              serial.dec(User_Setting15)
              serial.tx(":")
              serial.dec(User_Setting16)
              serial.tx(":")
              serial.dec(User_Setting17)
              serial.tx(":")
              serial.dec(User_Setting18)
              serial.tx(":")
              serial.dec(User_Setting19)
              serial.tx("~")
              'pause(50)
    
          if char == "L"  ' Start Live Log
            log := 1
    
          if char == "S"  ' Stop Live Log
            log := 0
    
          if char == "W"  ' Save User_Settings Values from PC
            repeat until char == "~"
              char := serial.rxcheck
              ' not finished yet.....
            eeprom.VarBackup(@User_Setting1,@End_User_Settings)
            serial.tx("Y") ' Save Completed
    
        else
          if log == 1
            serial.tx("^")
            serial.dec(Live_Data1)
            serial.tx(":")
            serial.dec(Live_Data2)
            serial.tx(":")
            serial.dec(Live_Data3)
            serial.tx(":")
            serial.dec(Live_Data4)
            serial.tx(":")
            serial.dec(ina[upbutton])
            serial.tx(":")
            serial.dec(ina[downbutton])
            serial.tx(":")
            serial.dec(1500) ' for testing purposes
            serial.tx("~")
            pause(10)
    
    PRI pause(Duration)  
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    

    And the VB Code :
        Public Sub DataReceivedHandler(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            SerialPort1.ReadTimeout = 500
            Dim indata As String
            Dim values() As String
            Dim first As Integer
            Dim last As Integer
            Try
                Dim bytes = SerialPort1.BytesToRead
                Dim buff(bytes) As Byte
                Dim len = SerialPort1.Read(buff, 0, bytes)
    
                indata = System.Text.Encoding.ASCII.GetString(buff)
                'unprocessed_string = System.Text.Encoding.ASCII.GetString(buff)
    
                SetText(Label20, indata) ' ------------------------------------------------------------------------------------ this is what shows incoming data.  This is always bits and pieces of data
                If InStr(indata, StartChar) And InStr(indata, EndChar) Then
                    first = InStr(indata, StartChar)
                    Parsed_String = indata.Substring(first, indata.Length - first)
                    last = InStr(Parsed_String, EndChar)
                    Parsed_String = Parsed_String.Substring(0, last)
                    Parsed_String.Trim()
                End If
    
                If Parsed_String <> String.Empty Then
                    Parsed_String.Trim()
                    SetText(Label21, Parsed_String) '----------------------------------------------------------------------This is the "final" string to be processed.  Sometimes it is all the data, sometimes it is not.
                    Parsed_String = Parsed_String.Substring(0, Parsed_String.Length - 1)
                    If Parsed_String <> String.Empty Then
                        values = Parsed_String.Split(":")
    
                        If task = 2 Then
                            If values.Length > 2 Then
                                ' do stuff with data
                                Parsed_String = String.Empty
                            End If
                        ElseIf task = 1 Then
                            status_txt.Text = values(0) & ":" & values(1) & ":" & values(2) & ":" & values(3) & ":"
                            SerialPort1.WriteLine("Y")  ' All data received and updated to PC
                        Else
                            task = 0
                            SerialPort1.WriteLine("S")
                        End If
                    End If
                End If
    
                SetText(Label19, System.Text.Encoding.ASCII.GetString(buff).Length)
    
            Catch ex As Exception
    
                SetText(Label20, ex.Message & ex.StackTrace)
            End Try
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            task = 0
            SerialPort1.WriteLine("S")  ' Stop "Live Data"
            task = 1
            SerialPort1.WriteLine("R")  ' Read User Settings from Prop
        End Sub
    
  • Mike GMike G Posts: 2,702
    edited 2013-11-18 04:26
    Sorry you're frustrated... I am too. The code drops packets because the logic is written to truncate data larger than one packet and discard packets smaller than one packet The same sort of issue as post 3.

    The serial port demo in post 16 is designed to help understand the DataReceived event and what to expect. As well as, provide a light weight unit test. I'm guessing you did not try the demo?

    Suggestion, create a packet protocol and send word sized data as opposed to ASCII characters. [Start][Start][PacketLength][Command][Data(0).Highbyte][Data(0).LowByte][Data(1...n)][Checksum]

    Create code in Spin and VB that understands how to parse the packet. Do NOT put this code in the DataReceived event!

    Test your code!!! If you do it right you will able to test the code without having to send serial data.

    IMO, the DataReceivedHandler code is doing too much and needs to be abstracted to a class or classed or methods. All DataReceivedHandler should be doing is getting the serial port buffered data and passing the bytes to another code block preferably a class. The class will contain all the logic to parse the bytes and alert subscribers. The same goes for the Spin logic, create methods or an object to deal with the serial packets.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-18 17:41
    I believe I got it working good now. I did have to move the "data processing" into another thread and change back to ReadLine instead of BytesToRead. I just end each "line" with "~" and chr(10) and check for the "~" at the end of the string before processing the data. It seems to be working as well as I need it.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-20 20:18
    Instead of starting a new thread, I figured I would continue this one since it is still under the same topic...

    Now that I have the VB program talking to the Prop and visa versa, I have run into yet another issue. This time, I am attempting to send a bunch of variables to the Prop from the VB program, then the Prop will put these values into an array and then set a specified "User_Setting" with that index value. The problem is, the variables must all be LONG when assigned to the "User_Setting" variable.
    VAR
      LONG array[255] 
    
    PUB Handle_USB
          ......Do Stuff Here and loop for incoming data (char)
    
          if char == "W"  ' Save User_Settings Values from PC
            pointer := 0
            repeat until char == "~"
              array[pointer] := char
              pointer++
              char := serial.rx
    
            if pointer == 20 ' One higher than User_Settings
              User_Setting1 := array[1]
              User_Setting2 := array[2]
              User_Setting3 := array[3]
              User_Setting4 := array[4]
              User_Setting5 := array[5]
              User_Setting6 := array[6]
              User_Setting7 := array[7]
              User_Setting8 := array[8]
              User_Setting9 := array[9]
              User_Setting10 := array[10]
              User_Setting11 := array[11]
              User_Setting12 := array[12]
              User_Setting13 := array[13]
              User_Setting14 := array[14]
              User_Setting15 := array[15]
              User_Setting16 := array[16]
              User_Setting17 := array[17]
              User_Setting18 := array[18]
              User_Setting19 := array[19]
              eeprom.VarBackup(@User_Setting1,@End_User_Settings)
              serial.tx("^")
              serial.tx("G")
              serial.tx(":")
              serial.dec(array[2])
              serial.tx("~")
              serial.tx(10)
            else
              serial.tx("^")
              serial.dec(pointer)
              serial.tx(":")
              serial.dec(array[2])
              serial.tx("~")
              serial.tx(10)
    

    and the VB code is sent like this :
                    SerialPort1.WriteLine("W")
                    SerialPort1.WriteLine(setting1.SelectedItem)
                    SerialPort1.WriteLine(setting2.SelectedItem)
                    SerialPort1.WriteLine(Int(setting3.Checked))
                    SerialPort1.WriteLine(Int(setting4.Checked))
                    SerialPort1.WriteLine(setting5.SelectedIndex)
                    SerialPort1.WriteLine(setting6.SelectedItem)
                    SerialPort1.WriteLine("~")
    

    What is sent back is the "failed" message which shows the pointer variable to be 51 and the array[2] to equal 58 when it should be 1500. Any ideas on how I can fix this?
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-21 09:39
    Hi, the GetBytes method of the .Net class BitConverter can read a 64 bit integer and return it as a four byte array.

    If you use the Uint64 data type for your values in VB .Net and use the "BitConverter.GetBytes(value)" method then every value you send from VB will be transmitted as the four consecutive bytes of a Long.

    Using this method it does not matter what the value is it will always be transmitted as a long. This may not be what your looking for but it is certainly worth reading about as it works very nicely in the kind of application you are designing.

    Jeff T.
  • Mike GMike G Posts: 2,702
    edited 2013-11-21 10:31
    Agreed Jeff T. I suggested a binary packet over ASCII twice for the exact issue the OP is now struggling to solve. Frankly, I give up.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2013-11-21 13:20
    The serial protocol is byte oriented, so if you need to send LONG values from the Propeller to the VB application then you must do it one BYTE at a time. The same goes for sending data the other way. On the Propeller side you can fairly easily accomplish this by shifting the LONG and using a mask to extract the data you want or merge it with new data (both directions work opposite).

    Edit: oops, didn't see the replies on the next page...:innocent:
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-21 17:57
    Honestly, I don't understand binary packets or binary except 0 is no / off and 1 is yes / on. I am worried about losing packets going TO the prop, not from the prop. The data coming from the prop is just showing a log of what is going on inside the code and is not used for any critical data. This is working 100% with no issues at all. The problem now is sending data from the VB application to the Prop. Converting a value of 0 to binary then sending it to the Prop would be different than converting a value of 12345 to binary and sending it to the prop then on the prop, convert the binary back to a usable number for my program. Trying to keep up with "if x == 010001_010100_010101_000000" would be one heck of a task for me. If someone is willing to help me understand this binary data concept, I am willing to try to learn. I have always learned by finding some code that is close to what I need and convert it to what works for my application. After some time, I start to fully understand the code and then am able to write the code from scratch. This is how I learned QBasic, PHP, Javascript, and many other languages. Spin is kind of new to me, and so is VB 2010. I used to know quite a bit of VB 2006, but that was years ago...7 years to be exact :p
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-21 19:48
    Ok, I have been all over the web trying to figure out how to send LONGs (4 bytes) through VB's serialport using UInt64 and have been completely unsuccessful. I did find this thread to receive bytes on the Prop and am attempting to figure it out. I am lost at the code in bold below :
    l_myReceivedByte := pst.RxCheck
           
          if l_myReceivedByte <> -1
            b_waitingToBeParsed[b_byteMoveIndex++] := l_myReceivedByte
           
            ' pst.str(@b_waitingToBeParsed)
            ' pst.str(string(pst#NL))
           
            if l_myReceivedByte == 13
              DelimiterFinder(@b_waitingToBeParsed)
              ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
              b_byteMoveIndex := 0
    
    PUB DelimiterFinder(RxStringAddr) : idx | localCount, localIndex, pstDelimiterFinder                                            
    
      ' Initialize variables here
      localIndex := 0
      pstDelimiterFinder := 0
    
    [B]repeat
        ifnot localCount := byte[RxStringAddr][idx++]                ' ifnot c, itterate to the next byte in byte[RxStringAddr] ?
        
          printAt( 1,12, String("No delimiter, aborted"))
          return -1
    
        charAt(1+idx,13,localCount)
        ' pst.dec(localCount)
        ' pst.str(string(pst#NL))  
      until localCount == b_delimiter'localCount == "="
     
      bytemove(@b_prefix, RxStringAddr, --idx)              ' idx points to the character after the delimiter, copy prefix
      b_prefix[idx] := 0                                    ' add terminator  
      RxStringAddr += idx + 1                               ' advance pointer, skip delimiter (+1)                                                 
      bytemove(@b_suffix, RxStringAddr, strsize(RxStringAddr) +1)                   ' copy tail including the existing terminator (+1)
      variableUpdator(@b_prefix, @b_suffix)[/B]
    
    [B]PUB variableUpdator(preAddr, sufAddr) ' variableUpdator(@prefix, @suffix)
    
      if strcomp(preAddr, l_var1) 'strcomp(@prefix, var1)
    {3}    
    {4} l_var1value := n.FromStr(sufAddr, %000_000_000_0_0_000000_01010) ' n.FromStr(@suffix, %000_000_000_0_0_000000_01010)    ' converts from a string to a dec
           
      else
        return -1[/B]
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-21 20:23
    So.... lets start from the very beginning shall we...

    1) How do you send a LONG from the Prop to VB in 4 Bytes?
    serial.tx(User_Setting2)  ' this equals 15000
    

    2) How do you read these 4 bytes and convert them to a readable "LONG" in VB?
    Public Sub DataReceivedHandler(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            Dim bytes = SerialPort1.BytesToRead
            Dim buff(bytes) As Byte
            Try
                Dim len = SerialPort1.Read(buff, 0, bytes)
                [B]status_txt.Text = buff(0).ToString[/B]
            Catch ex As Exception
                SetText(Label20, ex.Message & ex.StackTrace)
            End Try
        End Sub
    

    3) How do you send a numerical value of a combobox selection (Selected value of 15000) to the prop in 4 bytes?


    4) How do you receive this data on the Prop and save the value to a LONG?
    repeat
       ReceivedByte := serial.rxcheck
           
          if ReceivedByte <> -1
            ToBeParsed[byteMoveIndex++] :=ReceivedByte
           
            if ReceivedByte == 13
              ProcessData(@ToBeParsed) ' go do something with the data (Should set a specific LONG with the new data)
              ByteFill(@ToBeParsed, 0, strsize(@ToBeParsed)) ' clear old data and start fresh
              b_byteMoveIndex := 0 ' reset pointer
    
    SUB ProcessData(unParsedBytes)
     ' not sure what to do here
    
    
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-22 06:23
    Hi, I'll try and explain if I can.

    Lets take the first four byte locations of the Props EEPROM, 0,1,2 and 3.

    If I want to put a long value of 12345678 into the EEPROM it would fit in the first four byte locations like this

    location 0 = value 0 (HEX 0)
    location 1 = value 188 (HEX BC)
    location 2 = value 97 (HEX 61)
    location 3 = value 78 (HEX 4E)

    12345678 converted to HEX is 00BC614E, providing you write your EEPROM a byte at a time into four consecutive bytes you can also read them a byte at a time , a word at a time or a long at a time it does not matter it's your preference.

    You probably know that already so your thinking how do I write this data from VB. This is where the BitConverter class becomes so useful, it splits a long into four bytes for you, the values I have given come straight from the MSDN example at this link http://msdn.microsoft.com/en-us/library/system.bitconverter(v=vs.110).aspx

    The two lines of interest are
    Dim value As Integer = 12345678
          Dim bytes() As Byte = BitConverter.GetBytes(value)
    

    this code fills four bytes of the array called "bytes" with the long value 12345678, there is no other calculation required. So all you have to do to transmit this long (which fills locations 0-3) is
    serialPort1.Write(bytes,0,4)
    

    and just keep repeating the above in a loop, incrementing the EEPROM address by 4 each time, until all your longs are sent.

    Don't get discouraged, it might seem like greek but when you play around with it you will see just how simple it is and because it is simple you are able to understand whats going on and modify it to suit your own use.

    I do actually have some code on the Parallax forums that does a similar job, I'll post the link when I find it.

    Jeff T.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-11-22 06:48
    I am very new at the data stuff including saving the information to the eeprom. I am just using the Propeller_EEPROM object with varBackup and varRestore method to load the eeprom or program with the variables. The variables are predefined on first boot by setting the variables like this :
    DAT
       User_Setting LONG 3 
       User_Setting2 LONG 123456
       .........
    

    I am not sure how it is stored in the eeprom. I just know it works :) So, converting the "User_Setting" to 4 bytes to send through via the FullDuplexSerial so the VB program reads the 4 bytes and then converts it back to a readable string / integer is what I am trying to figure out.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-11-22 07:49
    Hi, because we are using serial transmission we have to look at our longs as four consecutive bytes, even the value of 3 is stored,written and read as four bytes, HEX 00 00 00 03, the value of 123456 would be HEX 00 01 E2 40.

    I use hex notation here for explanation purposes only.

    I found a couple of threads where the BitConverter is used, I'll name the post # but you will probably want to read the whole thread.

    These threads contain Visual Basic examples and Spin files to test the VB application, please build the apps and see how they work.

    Post #15 of the following

    http://forums.parallax.com/showthread.php/145187-VB.net-to-Prop-communication

    Post #18 of the following

    http://forums.parallax.com/showthread.php/122891-Help-with-a-EEPROM-boot-loader

    These programs will lead you away from using ASCII strings for your data but when you think about it your taking a numeric value and converting it to a string transmitting the string and then converting it back to a numeric value, doing it this way eliminates the conversions.

    Jeff T.
  • ratronicratronic Posts: 1,451
    edited 2013-11-22 09:28
    As far as the VB side it's been too long for my help but on the Propeller side I am using this reading 3 longs from another device and they are sent most significate byte first from the device for each long.
    'receive 3 longs most significate byte first for each long
    
    repeat i from 0 to 2                          
      a := dbg.rx                                 
      b := dbg.rx                                 
      c := dbg.rx                                 
      d := dbg.rx                                 
                                                  
      case i                                      
        0 : h := a << 24 | b << 16 | c << 8 | d   
        1 : j := a << 24 | b << 16 | c << 8 | d   
        2 : k := a << 24 | b << 16 | c << 8 | d
    

    For transmitting 3 longs on a Propeller this is untested but this is probably how I would go about it. This sends the most significate byte first. You will have to declare a small array to hold the 3 longs and assign your values to each long.
    Var
    
      long variable[3]
    
    'transmit 3 longs high byte of long first
    
    repeat i from 0 to 2
    
      g := variable[i]
    
      dbg.tx(g >> 24)
      dbg.tx(g >> 16)
      dbg.tx(g >> 8)
      dbg.tx(g)
    
  • ozpropdevozpropdev Posts: 2,792
    edited 2013-11-22 16:13
    Here is a simple transfer protocol that allows easy transfer of data to any of your registers.
    var
    
      long  user_settings[20]
      long  val[2]
      long  myindex
    
    pub prop_rx|rxb
    
        repeat
    
          rxb := getbyte  'get a byte from the receiver
    
          case rxb
    
             "0".."9":  val[myindex] *= 10
                        val[myindex] += rxb - "0"
    
             "$":  myindex~
                   val[0]~
                   val[1]~
    
             ",":  myindex++
    
             "=":  user_settings[val[0]] := val[1]
    
    
    
    

    To send the value 123 to user_seetings[15], VB just sends the following string
    $15,123=
    To send the value 15000 to user_seetings[3], VB just sends the following string
    $3,15000=

    This makes it simple from the VB end as well.
Sign In or Register to comment.