Console CTRL-C handling when using serial port fails - vb.net

Using VB.Net I've added a CTRL-C handler:
AddHandler Console.CancelKeyPress, AddressOf QuitHandler
Which does the following:
Private Sub QuitHandler(ByVal sender As Object, ByVal args As ConsoleCancelEventArgs)
Console.WriteLine("Quitting...")
args.Cancel = True
Quit = True
End Sub
I then have a main loop which just runs until Quit=True.
This all works until I start reading from the serial port:
Private Sub port_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles Port.DataReceived
at which point the CTRL-C handler gets ignored for about 30secs at which point the console app just terminates without going through the cleanup code.
Why?

I don't know VB, but my guess would be that you're attempting to read data from the serial port that isn't there (err, the port is there, the data isn't); as a result, your program is blocking ("hanging") until the read attempt times out after 30 seconds.
If I'm correct, you need some way to poll your serial input without blocking, or (better) to get an asynchronous sub called when data actually appears.

You should make sure to understand how Timeouts work, since you are reading serial port on pooling. Your serial thread will always be running and trying to read something.
A best approuch would be to read data just when its availiable, then your serial thread would have time to breath.
You can also try to use DoEvents.

Related

TCP Client to Server communication

All I'm looking for is a simple TCPClient/Listner example on Windows Form VB.Net. I'm a newbie and Microsoft TCPClient/Listner class examples are not what I am looking for. All I am looking is for the TCPClient to send a message and for a TCPListener to get the message and to send a message back "I got your message" ?
A little help would be great. I have some codes, but is only to send message to server and not back from server to client..
Any help will be very appreciated..
TCP communication is stream-based, which means it doesn't handle any packets. Due to this, messages that you receive might be either partial or lumped together.
You could for example send:
Hello!
How are you?
But you might receive:
Hello!How are you?
or:
Hello!How ar
e you?
(or something similar)
To fix this you must apply something called "length-prefixing". Length-prefixing (or length prefixing) means that before you send a message, you put its length (amount of characters/bytes) in the beginning of it. By doing so, the endpoint will know exactly how many bytes to read for each message. Thus there will be no problems with messages being partial or lumped together.
This is not the most straightforward thing to do as a beginner, as to get it to work properly on both sides you have to structure your code just right. So I've created two classes that will take care of this for you. See the examples below on how to use them for simple text message-based communication.
Link to source: http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient.zip
Link to C# source : http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient%20CSharp.zip
EDIT (2019-11-08)
Some time ago I made an upgraded version of this with a bit better code structure and error handling. For those of you interested, the new code can be downloaded here (VB.NET only):
https://www.mydoomsite.com/sourcecodes/ExtendedTcpClient%202.0.zip
Example usage
Note that in those examples Client does not refer to the client side, but to the TcpClient.
Server side
First declare a new variable for ExtendedTcpClient, and be sure to
include WithEvents in the declaration.
Dim WithEvents Client As ExtendedTcpClient
Then you will need a TcpListener and a Timer to check for incoming connections.
Dim Listener As New TcpListener("0.0.0.0", 5555) 'Listen for any connection on port 5555.
Dim WithEvents Tmr As New System.Windows.Forms.Timer
Then you need to subscribe to the timer's Tick event.
Private Sub Tmr_Tick(sender As System.Object, e As System.EventArgs) Handles Tmr.Tick
End Sub
In there you check for incoming connections via the Listener.Pending() method. When you are to accept a connection you first declare a new
instance of the ExtendedTcpClient. The class requires to have a
form as its owner, in this application Me is the current form.
Then you use the ExtendedTcpClient.SetNewClient() method with
Listener.AcceptTcpClient() as its argument to apply the
TcpClient from the listener. Put this code in the Tmr_Tick sub:
If Listener.Pending() = True Then
Client = New ExtendedTcpClient(Me)
Client.SetNewClient(Listener.AcceptTcpClient())
End If
Now the client and server are connected to each other.
Now you need to subscribe to the PacketReceived event of the
client. Create a sub like so:
Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived
End Sub
All received data are presented in an array of bytes.
In the PacketReceived sub you can output the received packet as text into a TextBox. Just check if the packet header is PlainText and then
you can convert the received packets contents (which is an array of
bytes, accessed via e.Packet.Contents) to a string and put it in
the TextBox.
If e.Packet.Header = TcpMessagePacket.PacketHeader.PlainText Then
TextBox1.AppendText("Message recieved: " & System.Text.Encoding.Default.GetString(e.Packet.Contents) & Environment.NewLine)
End If
System.Text.Encoding.Default.GetString() will convert a byte array to normal text.
In the PacketReceived sub you can also make it send "Message received" to the client.
Dim ResponsePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes("Message received."), TcpMessagePacket.PacketHeader.PlainText)
ResponsePacket.Send(Client.Client) 'Get the ExtendedTcpClient's underlying TcpClient.
Lastly, when closing the form you just need to disconnect the client.
Private Sub ServerWindow_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If Client IsNot Nothing Then Client.Disconnect()
End Sub
And that's it for the server side.
Client side
For the client side you will do pretty much the same as the server side, though you won't be needing a TcpListener nor a Timer.
Dim WithEvents Client As New ExtendedTcpClient(Me) 'The current form as its owner.
Connect to the server via the IP and port you've given the listener.
Client.Connect("127.0.0.1", 5555) 'Connects to localhost (your computer) at port 5555.
Now if you want to send text to the server you'd do something like this (in for example a button):
Dim MessagePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes(TextBox2.Text), TcpMessagePacket.PacketHeader.PlainText)
MessagePacket.Send(Client.Client)
TextBox2 includes the text you want to send.
Lastly, you will need to subscribe to the PacketReceived event here too to check for responses from the server. In there you receive text just like the server does.
Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived
If e.Packet.Header = TcpMessagePacket.PacketHeader.PlainText Then
TextBox1.AppendText(System.Text.Encoding.Default.GetString(e.Packet.Contents) & Environment.NewLine) 'Prints for example "Message received." from the server.
End If
End Sub
And now everything should be working!
Link to a complete example project (only client-to-server): http://www.mydoomsite.com/sourcecodes/TCP%20Messaging%20System.zip
Link to C# example: http://www.mydoomsite.com/sourcecodes/CSharp%20TCP%20Messaging%20System.zip
If you want to add more headers to the class (the headers indicate to you what kind of data each packet contains), open TcpMessagePacket.vb and add more values in the PacketHeader enum (located in the region called Constants).
Hope this helps!
Screenshot from the example project
(Click the image for larger resolution)

Catch Timeout in DownloadFileAsync

I am having a problem with timeouts in my DownloadFileAsync function. I am using VB.NET. According to multiple sources the "DownloadFileCompleted" event should be raised when the connection to the server while downloading is lost and the error flag should be set. Nothing of this is happening. I am trying this through starting the download and then simply stopping my internet connection through disabling WLAN.
Private Sub DownloadMod_DownloadFileCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs) Handles DownloadMod.DownloadFileCompleted
MsgBox("Test1")
If e.Error IsNot Nothing Then
MsgBox("Test2")
End If
End Sub
Neither the test1 nor the test2 message box is appearing after loosing connection. I read that the standard timeout is 100 s, so I always waited 2 minutes to make sure, but nothing is happening.
This is how I start the download:
DownloadMod.DownloadFileAsync(New System.Uri("http://linktothefile.com/downloadfile.txt"), System.AppDomain.CurrentDomain.BaseDirectory & "Downloads\downloadfile.txt", Stopwatch.StartNew)
The stopwatch is in there for calculation of the download speed.
Downloadmod is defined like this:
Private WithEvents DownloadMod As New Net.WebClient
I would appreciate if someone could help me with this problem.
Turin

Setting a manual timeout in VB.NET

I have a vb.net application that interfaces with some external hardware - an array of motor controllers. To do this, I'm using a CANOpen library provided by the hardware supplier. However, the timeouts built into the library are frankly excessive, and cause the application to hang painfully under specific conditions. I'd prefer not to need to edit the library if possible.
What's the most sensible way to design in another, shorter timeout within vb.net? The function in question is a blocking function, so presumably in-thread timers won't help. Is there an elegant solution here?
Give this a try, it's is the best I could come up with so far. I've used background workers just because they are easy to use.
Basically it's a thread within a thread which will at least keep your UI responsive, judging by what you've said you should probably use threading for all the drive comms functions anyway in case a drive loses comms for any reason while the app is running.
This ain't pretty, but it will at least allow you to exit out early before the CAN function itself times out.
Private connected As Boolean
Private Sub bwTryConnect_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwTryConnect.DoWork
Dim timeout As Boolean
Dim timeoutCount As Integer
Dim timeoutValue As Integer = 5 ' timeout value
bwConnect.RunWorkerAsync() ' start worker to try connection
While bwConnect.IsBusy And Not timeout
Thread.Sleep(1000) ' wait a second
timeoutCount += 1 ' increment timeout value
If timeoutCount = timeoutValue Then timeout = True ' connection timed out
End While
' connected will be true if the try connection worker completed (connection to drive ok) before the timeout flag was set, otherwise false
connected = Not timeout
End Sub
Private Sub bwConnect_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwConnect.DoWork
' use your CAN library function here - either a simple connect command or just try reading an arbitary value from the drive
' if you want to test this, uncomment one of the following lines:
'Thread.Sleep(20000) ' simulate timeout
'Thread.Sleep(2000) ' simulate connect
End Sub
Obviously you then call with bwTryConnect.RunWorkerAsync().

vb.net check if process I started is done

I have started a process:
Dim getUdpate as Process
getUpdate = New Process
getUpdate.StartInfo.FileName = "C:\UTIL\GETBTCH.BAT"
getUpdate.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
getUpdate.StartInfo.UseShellExecute = False
getUpdate.StartInfo.WorkingDirectory = "C:\UTIL\"
getUpdate.Start()
getUpdate.Close()
Then, I want to Run another process but I want to check first if the getUpdate process is already finished.
How do I check if the process is already finished?
I already tried to look at the processes ID, but it only display cmd.exe and there are a lot of cmd.exe as the processes ID so I can't just go and stop all of those.
You can check the HasExited property of the process. It will return true if the process has ended, and false if it is still running.
You will need to check this before you call Close() on your getUpdate Process object. So getProcess will have to remain open until the procsses has exited.
Try:
getUpdate.WaitForExit(); instead of
getUpdate.Close()
If you are making a WinForms application or similarly interactive UI I suggest hooking a function into the object's Exited event instead of polling HasExited.
(You may already know this but) if you use WaitForExit or poll HasExited your UI is hanging exactly because your code is actually waiting for the process to end.
Your UI only has one thread and cannot "multitask". That's why these "processing" type of actions should be done in a different thread (or, as is the case here, a different process) and report back to the UI when they finish.
Example:
' Handle Exited event and display process information.
Private Sub myProcess_Exited(ByVal sender As Object, ByVal e As System.EventArgs)
'Do something in your UI
End Sub
and in your starting code:
getUpdate.EnableRaisingEvents = True
AddHandler getUpdate.Exited, AddressOf myProcess_Exited

Serial port in code, Visual Basic 2010

I got an Arduino hooked up to the PC and would like to read the serial port of it.
I read the serial port in Visual Basic with com.Readline, but it won't read everything.
It looses around 2-3 lines that were sent over the serial port to the Visual Basic code.
They get "lost".
If I go even with higher Baud rates (57600) it loses even more lines...
I use this to read:
Private Sub com9_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles com.DataReceived
Dim returnStr As String
returnStr = com.ReadLine
ReceiveSerialData(returnStr)
End Sub
Is the program too slow to get all data or what is the problem?
SerialPort.DataReceived Event has an interesting comment which may point you in the right direction:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
Note that the page(s) also mention the fact that the buffering behavior complicates things...