Flushing serial port buffer

I’m doing a quick back and forth communication with my serial port where my app sends a password, checks it and if OK sends a command. My problem is that the response to the password doesn’t clear out of the buffer (as far as I can tell) before the next response comes in. I thought the serial.readall would flush the buffer but it doesn’t. I’ve tried serial.flush. But if I look at what is returned to a MsgBox after decoding the second response, the first response is still part of the string.

How do I clear out he buffer after I’ve read it?

Make sure you have the full response before continuing. The DataAvailable event can fire many times per response. Have a look at http://blog.xojo.com/2015/03/23/guest_post_serial_communications_with_xojo/

Thanks Wayne–I did take a look at that.

I’m sure the first response is returned in full–I check the CRC of the response to the password sent, and then, if the CRC is correct, I send the command. But, for reasons I don’t understand (other than that I’m new to this), when I send the command and get a response back, if I look at what is in the buffer, the first response to the password is still there, as well as the response to the command. So what I’m surmising is that I need to manually clear the buffer after the response to the password. But I can’t figure out how to do that.

Why don’t you post the dataavailable code for us to look at.

To clear the buffer after a read, use .ReadAll instead of .Result.

Here’s what I have in DataAvailable:

If q = 0 Then //Data arrived, start a timer and wait…

Timer3.Mode = timer.ModeSingle

Else
If Pass = 1Then
Timer2.Mode = timer.ModeSingle
Else
Timer1.Mode = timer.ModeSingle
End If
End If

//Then depending on some conditions one of 3 timers fires. The password timer is Timer2:

//data arrived, and we wait for the message to complete.

TimerTimeout.Mode = timer.ModeOff ’ Data arrived turn off timeout timer
dim MyString as String
MyString=serial1.ReadAll() ’ fetch all the data
'Serial1.Flush //<—This is where I tried flush
if IsValidCrc(MyString) then ’ chec if CRC is correct
txtReceived1.text=EncodeHex(MyString,true) 'OK correct show data
If txtReceived1.text = “05 41 05 91 92” Then
pbSend.Push //Hit the Send button again
Else
txtReceived1.text = “Password Error”
End If
else
txtReceived1.text = “Error in CRC5” //Not Correct show Warning
end if

//Then DataAvailable sends us to Timer1:

  MyString=serial1.ReadAll() ' fetch all the data
  'txtReceived.text=EncodeHex(MyString,False)  //<---I uncomment these 2 lines to look at what the CRC code is trying to evaluate
  'MsgBox (txtReceived.text)
  if IsValidCrc(MyString) then ' chec if CRC is correct
    Dim r as String
    Dim s As Integer
    txtReceived.text=EncodeHex(MyString,False) 'OK correct show data
    s = Val(Mid(txtReceived.text,6,1))
    r = Mid(txtReceived.text,7,2*s)
    txtReceivedASCII.text = Str(CLong("&h" + r))
  else
    txtReceived.text = "Error in CRC4"  // Not Correct show Warning
  end if

Thanks for the reply Tim–

As you can see from the code, I do use ReadAll. Any other ideas?

What’s in pbSend.Action? What you report is consistent with a DoEvents call (which is a no-no of course ).

Thanks Tim–Since I’m fairly new to this, I’m not sure what you mean that a DoEvents call is a no-no. Please elaborate.

pbSend.Action first opens the serial port, then, if the password hasn’t been sent, calls SendPass which looks like this:

dim Message as ModbusPoll3
Message.DeviceID = val(txtDevID.text) ’ Device address
Message.FunctionCode= 65 ’ function
Message.FirstAddr = val(txtToSend2.Text)
Message.Crc = AddCrc(Message.StringValue(false))
dim writebuffer as String
writebuffer = Message.StringValue(False)
txtToSend3.Text = encodehex(writebuffer,true) ’ Show data
Serial1.Write(writebuffer) ’ send data
TimerTimeout.Mode = timer.ModeSingle

Timer2 does a pbSend.Push and since the password has been sent, pbSend code that gets executed looks typically like this:

  If PopupMenu3.ListIndex = 42 Then //Write Pulse Ratio 1
    SendPass
    Sleep 500
    CommandType = 2
    TxtFunction.Text = "16"  '10
    txtMsg1stAddr.Text = "1501"
    txtNumReg.Text = "1"
    TxtBytes.Text = "2"
    TxtValues.Text = txtToSend1.Text 'Last 2 Bytes
  End If

  If CommandType = 2 Then //Write 2 Byte command
    dim Message as ModbusPoll1
    //Build Message
    Message.DeviceID = val(txtDevID.text) ' Device address
    Message.FunctionCode= Val(txtFunction.Text) ' function
    Message.FirstAddr = val(txtMsg1stAddr.text) ' get number of registers to read
    Message.NumOfRegisters = val(txtNumReg.text) ' number of registers to read
    Message.ByteCntValues = Val(txtBytes.Text)
    Message.Values = Val(txtValues.Text)   'Val("&h" + (txtValues.Text))
    Message.Crc = AddCrc(Message.StringValue(false))
    dim writebuffer as String
    writebuffer = Message.StringValue(False)  
    txtToSend.Text = encodehex(writebuffer,true) ' Show data
    Serial1.Write(writebuffer) ' send data
    TimerTimeout.Mode = timer.ModeSingle ' start TimeOut Timer
  End If

Tim–I went and did some reading about DoEvents, and no, I’m not using a DoEvents in my code.

I sure could use some help though on figuring out why the serial buffer doesn’t clear out after a ReadAll, and how to force it to clear.

The problem may be that you’re opening the serial port in the middle of DataAvailable processing. I’m not sure what state that would leave the port in, as DataAvailable surely makes some assumptions about the port and probably isn’t expecting it to be opened during its processing. Try opening the port outside of the button action. Or pull some code out of the button into a method that both the button and DataAvailable can call.

I figured out what was going on. I was inadvertently calling my pb.Send an extra time. Thanks for the suggestions!

Doug