Accessing the Bluetooth COM ports in VB

S

silverfox

I have been trying to write a VB program to use Bluetooth to
communicate between a PDA running Windows CE 4.2 and another BT
device. I found this article that got me started:
http://www.devx.com/wireless/Article/11511

Using the technique in this article, I can successfully transmit data
but the receive part fails. In fact it slows the PDA to a crawl.
Does anyone have any ideas on how to modify the original program so
that the receive function will work?

BTW, I am using VS 2005 and the original program was for an earlier
version of VS. I am not sure if this is relevant.

Here is the relevant section of the source from the article:

Dim infileHandler As Long
Dim outfileHandler As Long
Dim numReadWrite As Integer
Dim t1 As System.Threading.Thread
Dim stopThread As Boolean = False

Public Sub connect()
'---port number for Bluetooth connection
Dim inPort As Short = 8
Dim outPort As Short = 6

'---Opens the port for Bluetooth
infileHandler = CreateFile("COM" & inPort & ":", _
&HC0000000, 0, 0, 3, 0, 0)
Application.DoEvents()
outfileHandler = CreateFile("COM" & outPort & ":", _
&HC0000000, 0, 0, 3, 0, 0)
Application.DoEvents()

'---invoke the thread to receive incoming messages
stopThread = False
t1 = New Threading.Thread(AddressOf receiveLoop)
t1.Start()
End Sub

Public Sub disconnect()
stopThread = True
CloseHandle(infileHandler)
CloseHandle(outfileHandler)
End Sub

<DllImport("coredll.dll")> _
Private Shared Function CreateFile(ByVal lpFileName As String, _
ByVal dwDesiredAccess As
Integer, _
ByVal dwShareMode As Integer, _
ByVal lpSecurityAttributes As
Integer, _
ByVal dwCreationDisposition As
Integer, _
ByVal dwFlagsAndAttributes As
Integer, _
ByVal hTemplateFile As Integer)
As Integer
End Function

<DllImport("coredll.dll")> _
Private Shared Function ReadFile(ByVal hFile As Integer, _
ByVal Buffer() As Byte, _
ByVal nNumberOfBytesToRead As
Integer, _
ByRef lpNumberOfBytesRead As
Integer, _
ByRef lpOverlapped As Integer) As
Integer
End Function

<DllImport("coredll.dll")> _
Private Shared Function WriteFile(ByVal hFile As Integer, _
ByVal Buffer() As Byte, _
ByVal nNumberOfBytesToWrite As
Integer, _
ByRef lpNumberOfBytesWritten As
Integer, _
ByVal lpOverlapped As Integer)
As Boolean
End Function

<DllImport("coredll.dll")> _
Private Shared Function CloseHandle(ByVal hObject As Integer) As
Integer
End Function

Public Function send(ByVal message As String) As Integer
'---send the message through the serial port
Dim value As String = message & vbCrLf
Dim retCode As Integer = WriteFile(outfileHandler, _
stringToByteArray(value), _
value.Length(), _
numReadWrite, _
0)
txtMessageLog.Text += value
Return retCode
End Function

Public Sub receiveLoop()
'---receive the message through the serial port
Dim inbuff(300) As Byte
Dim retCode As Integer = ReadFile(infileHandler, _
inbuff, _
inbuff.Length, _
numReadWrite, _
0)
Application.DoEvents()
While True
If retCode = 0 Or stopThread Then
'MsgBox("Error reading message.")
Exit While
Else
Dim updateDelegate As New _
myDelegate(AddressOf updateMessageLog)

updateDelegate.Invoke(byteArrayToString(inbuff))
ReDim inbuff(300)
retCode = ReadFile(infileHandler, _
inbuff, _
inbuff.Length, _
numReadWrite, _
0)
Application.DoEvents()
End If
End While
End Sub


Public Delegate Sub myDelegate(ByVal str As String)

Public Sub updateMessageLog(ByVal str As String)
If str.Length > 0 Then
txtMessageLog.Text += "-->" & str
End If
End Sub

The only thing I had to change was the port numbers to match the BT
COM ports on my PDA. The Text box for receiving the incoming stream
immediately becomes filled with repeated instances of -->, as
updateMessageLog is apparently called repeatedly. I hope that there
is a simple solution to this problem.
 
D

Daniel Strigl

silverfox said:
Public Sub receiveLoop()
'---receive the message through the serial port
Dim inbuff(300) As Byte
Dim retCode As Integer = ReadFile(infileHandler, _
inbuff, _
inbuff.Length, _
numReadWrite, _
0)
Application.DoEvents()
While True
If retCode = 0 Or stopThread Then
'MsgBox("Error reading message.")
Exit While
Else
Dim updateDelegate As New _
myDelegate(AddressOf updateMessageLog)

updateDelegate.Invoke(byteArrayToString(inbuff))
ReDim inbuff(300)
retCode = ReadFile(infileHandler, _
inbuff, _
inbuff.Length, _
numReadWrite, _
0)
Application.DoEvents()
End If
End While
End Sub


Public Delegate Sub myDelegate(ByVal str As String)

Public Sub updateMessageLog(ByVal str As String)
If str.Length > 0 Then
txtMessageLog.Text += "-->" & str
End If
End Sub

Why do you invoke your "updateMessageLog" method before you read the
data from the port?

Try to move the invoke after the "ReadFile" part.
 
D

Dick Grier

Hi,

Since you are using VS2005, why not use the built-in SerialPort object (data
are read in a background thread)? In general, you will not need
Application.DoEvents when using a thread, which will give you good overall
performance -- and (IMO), you should buffer a reasonable amount of data
before you log it.

I have a more complete source code example, that a number of people are
using on Windows CE 4.2 systems in my book. I show two different methods
for reading data using a threaded model. See below.

Dick

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
See www.hardandsoftware.net for details and contact information.
 
S

silverfox

silverfox schrieb:







Why do you invoke your "updateMessageLog" method before you read the
data from the port?

Try to move the invoke after the "ReadFile" part.

Well first, this is the code in the article, not mine. But if you look
at the code you see that he precedes the loop with a read, so there is
always a read preceding every call to updateMessageLog.
 
S

silverfox

Hi,

Since you are using VS2005, why not use the built-in SerialPort object (data
are read in a background thread)? In general, you will not need
Application.DoEvents when using a thread, which will give you good overall
performance -- and (IMO), you should buffer a reasonable amount of data
before you log it.

I have a more complete source code example, that a number of people are
using on Windows CE 4.2 systems in my book. I show two different methods
for reading data using a threaded model. See below.

Dick

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
Seewww.hardandsoftware.netfor details and contact information.

Thanks, Dick. I guess I should buy your book!
 
S

silverfox

Hi,

Since you are using VS2005, why not use the built-in SerialPort object (data
are read in a background thread)? In general, you will not need
Application.DoEvents when using a thread, which will give you good overall
performance -- and (IMO), you should buffer a reasonable amount of data
before you log it.

I have a more complete source code example, that a number of people are
using on Windows CE 4.2 systems in my book. I show two different methods
for reading data using a threaded model. See below.

Dick

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
Seewww.hardandsoftware.netfor details and contact information.

Well, I haven't purchased your book yet, but in my first experiment
using a SerialPort object, I got an error on opening the output port.
The stack trace showed an IOException thrown at
SerialPort.open():SerialStream.setBufferSizes():SerialStream.checkResult():WinIOError()

The relevant code executed (in my prog) consists of only the following
two lines:

System.IO.Ports.SerialPort serialOutputPort = New
System.IO.Ports.SerialPort("COM8")
serialOutputPort.open()

-- don
 
S

silverfox

Well, I haven't purchased your book yet, but in my first experiment
using a SerialPort object, I got an error on opening the output port.
The stack trace showed an IOException thrown at
SerialPort.open():SerialStream.setBufferSizes():SerialStream.checkResult():WinIOError()

The relevant code executed (in my prog) consists of only the following
two lines:

System.IO.Ports.SerialPort serialOutputPort = New
System.IO.Ports.SerialPort("COM8")
serialOutputPort.open()

-- don
Another interesting thing about this little exception is that the
program that caused it cannot be stopped. Quit doesn't work and going
to Settings:System:Memory:Running Programs:Stop doesn't stop it
either. Only a reset killed that program. And this is when it is
sitting at the error display page! This has to be a Microsoft bug.
 
G

Guest

I doubt it's a Microsoft bug. It's pretty certain that MS tested such a
simple scenario before releasing, and it's equally certain that the many
people using the serial libraries would have found and reported this before
you.

My bet is that it's a problem with the device's bluetooth driver. It didn't
implement something (or didn't implement it right) that the serial classes
are trying to initialize. The fact that your original test with what one
would expect to be known-working code also exhibited strange behavior also
points to this same thing.

Personally I'd try to set up a really simple C++ app that opens the driver
and dumps incoming data to the console just to see if that works, thereby
removing all managed code questions from the equation. If that's not an
option, then using classes that you have source for all the way down to the
P/Invoke would be useful so you could trace it to the driver interface
boundary, again removing the possibility that it's your code (or the managed
port class) causing the issue.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
S

silverfox

I doubt it's a Microsoft bug. It's pretty certain that MS tested such a
simple scenario before releasing, and it's equally certain that the many
people using the serial libraries would have found and reported this before
you.

My bet is that it's a problem with the device's bluetooth driver. It didn't
implement something (or didn't implement it right) that the serial classes
are trying to initialize. The fact that your original test with what one
would expect to be known-working code also exhibited strange behavior also
points to this same thing.

Personally I'd try to set up a really simple C++ app that opens the driver
and dumps incoming data to the console just to see if that works, thereby
removing all managed code questions from the equation. If that's not an
option, then using classes that you have source for all the way down to the
P/Invoke would be useful so you could trace it to the driver interface
boundary, again removing the possibility that it's your code (or the managed
port class) causing the issue.

--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded Worldwww.OpenNETCF.com

I haven't had a chance to do what you suggest and it will be more than
a short gentle curve for me to figure out how. But are you saying
that you think that the problem is with the Widcomm stack that HP
ships with all its iPAQs? Isn't that equally unlikely?
 
G

Guest

I haven't had a chance to do what you suggest and it will be more than
a short gentle curve for me to figure out how. But are you saying
that you think that the problem is with the Widcomm stack that HP
ships with all its iPAQs? Isn't that equally unlikely?

Since I know how OEMs tend to test, it's not as unlikely no. It's also
possible that how they tested the ports differs from how you're trying to
use them (I can pretty much guarantee they used native code to test). My
guess is that the serial classes are trying to set up some parameter that
makes sense in a real serial connection, but HP didn't implement or
implemented incorrectly that same parameter and never bothered to test what
happens when you try to change it. Good examples might be baud rate, flow
control, parity, stop bits, timeouts, etc.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
D

Dick Grier

I agree with Chris. I haven't seen this on my units.

So... I suspect a driver problem. These things are imposible for us as
developers (from the outside looking in) to fiddle. Does the SerialPort
object in CF2 suffer the same problem?

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
See www.hardandsoftware.net for details and contact information.
 
S

silverfox

I agree with Chris. I haven't seen this on my units.

So... I suspect a driver problem. These things are imposible for us as
developers (from the outside looking in) to fiddle. Does the SerialPort
object in CF2 suffer the same problem?

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
Seewww.hardandsoftware.netfor details and contact information.

I am sorry, Richard, I don't know what you mean by the SerialPort
object in CF2. This is my first development project using Visual
Studio and the first for a Pocket PC so I am a little behind the
curve. I searched the Object Browser for SerialPort and used the only
one I found, which is System.IO.Ports.SerialPort.
 
S

silverfox

Since I know how OEMs tend to test, it's not as unlikely no. It's also
possible that how they tested the ports differs from how you're trying to
use them (I can pretty much guarantee they used native code to test). My
guess is that the serial classes are trying to set up some parameter that
makes sense in a real serial connection, but HP didn't implement or
implemented incorrectly that same parameter and never bothered to test what
happens when you try to change it. Good examples might be baud rate, flow
control, parity, stop bits, timeouts, etc.

--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded Worldwww.OpenNETCF.com

Actually, I was originally referring to the inability to stop the
program once the OS caught an IOException and reported the problem. I
would have thought that the Quit button on the OS-generated dialog box
would have worked at that point regardless of any problem with the
driver. And barring that, the STOP running program in the
System>Memory Running Programs dialog should work regardless of a
problem with a third party driver. And when both of those things fail
that seems like a bug in the OS to me. But maybe that's just me.

So, is it your opinion that HP is at fault here for including a
BlueTooth stack that is incompatible with Windows CE, at least with
the SerialPort API? The Widcomm stack is VERY widely used on PDAs
running Windows CE, by the way, and I would be surprised to find that
such an obvious application as serial communications was not tested at
least to the point to see that the Open method didn't fail every
time. But again, maybe that's just me.
 
P

Paul G. Tobey [eMVP]

You don't know much about operating systems. What if the application isn't
running application code at the time of the "stop"? What if it's in the
middle of a driver call? Is the driver left in a bad state? Can the OS
terminate the driver, too? What if another application is also in the
middle of a call to that driver? What if the driver is for the display?
It's not so simple to 'just' terminate an application.

The most-likely place for the bug is your code. I'm not convinced yet that
you are the source of the problem. The second most-likely is in the .NET
CF, hence the suggestion that you take that out of the loop by using native
code. The third most-likely is the Bluetooth stack, as it was probably only
tested for the standard communication tasks: headset, ActiveSync and maybe
Bluetooth serial for GPS. The lest-likely is the operating system itself.
It's certainly not bug-free, but it gets used in a lot more different
scenarios than any individual program, driver, or framework.

Paul T.
 
G

Guest

I am sorry, Richard, I don't know what you mean by the SerialPort
object in CF2. This is my first development project using Visual
Studio and the first for a Pocket PC so I am a little behind the
curve. I searched the Object Browser for SerialPort and used the only
one I found, which is System.IO.Ports.SerialPort.

Yes, that means you are using the CF 2.0 Serial Port object (CF 1.0 didn't
have one, so that leads us to the conclusion you're using CF 2.0 and the
namespace highly indicates you're using Microsoft's library, not one of the
many otehrs available like the one from Dick, OpenNETCF, Franson, etc).


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
G

Guest

Actually, I was originally referring to the inability to stop the
program once the OS caught an IOException and reported the problem. I
would have thought that the Quit button on the OS-generated dialog box
would have worked at that point regardless of any problem with the
driver. And barring that, the STOP running program in the
System>Memory Running Programs dialog should work regardless of a
problem with a third party driver. And when both of those things fail
that seems like a bug in the OS to me. But maybe that's just me.

Yes, it's just you. In the first case it's quite possible that a thread is
blocking in a system call (like maybe a serial read thread stuck on
WaitCommEvent) and that thread cannot be terminated. When the parent pukes,
it becomes a zombie, not owned by really anything but preventing the process
from being cleaned up.

The Running Programs dialog only sends a WM_CLOSE to the window, so it's
rarely going to shut down anything that isn't in a known, well-behaved state
and that has a nice main window that's non-modal and that cleans up all of
its threads when that window is closed. Basically that means it's pretty
useless for a developer.
So, is it your opinion that HP is at fault here for including a
BlueTooth stack that is incompatible with Windows CE, at least with
the SerialPort API? The Widcomm stack is VERY widely used on PDAs
running Windows CE, by the way, and I would be surprised to find that
such an obvious application as serial communications was not tested at
least to the point to see that the Open method didn't fail every
time. But again, maybe that's just me.

I'm not placing blame yet. Based on the evidence I do suspect it's the
bluetooth serial driver interface (not the stack, I'd like to point out).
The fact it's widely used by people, who mostly use it for things like
audio, doesn't hold much sway with me. What percentage of devices have that
stack? Maybe 10%? What percentage of users with that device use it for
serial comms? Maybe 10%? What percentage of those are using the managed
class to access it? Maybe 30%? If my junior high math is still correct 0.1
* 0.1 * 0.3 is a pretty small number.

I wouldn't consider it "obvious" by any stretch. I'm somewhat familiar with
what an OEM might do for testing. I'm also vaguely familiar with the
pressures they're under to ship a device, and how even if BT serial failed
but all otehr tests passed how they still might be very highly inclined to
ship due to that really small number above.

But maybe that's just me.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com
 
S

silverfox

Yes, it's just you. In the first case it's quite possible that a thread is
blocking in a system call (like maybe a serial read thread stuck on
WaitCommEvent) and that thread cannot be terminated. When the parent pukes,
it becomes a zombie, not owned by really anything but preventing the process
from being cleaned up.

The Running Programs dialog only sends a WM_CLOSE to the window, so it's
rarely going to shut down anything that isn't in a known, well-behaved state
and that has a nice main window that's non-modal and that cleans up all of
its threads when that window is closed. Basically that means it's pretty
useless for a developer.


I'm not placing blame yet. Based on the evidence I do suspect it's the
bluetooth serial driver interface (not the stack, I'd like to point out).
The fact it's widely used by people, who mostly use it for things like
audio, doesn't hold much sway with me. What percentage of devices have that
stack? Maybe 10%? What percentage of users with that device use it for
serial comms? Maybe 10%? What percentage of those are using the managed
class to access it? Maybe 30%? If my junior high math is still correct 0.1
* 0.1 * 0.3 is a pretty small number.

I wouldn't consider it "obvious" by any stretch. I'm somewhat familiar with
what an OEM might do for testing. I'm also vaguely familiar with the
pressures they're under to ship a device, and how even if BT serial failed
but all otehr tests passed how they still might be very highly inclined to
ship due to that really small number above.

But maybe that's just me.

--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded Worldwww.OpenNETCF.com

Ok, you convinced me. I should not have come off sounding so haughty
when I am such a newbie at this. Thanks for you feedback!

As to the percentage of devices using the Widcomm stack, I was under
the impression that it was the majority of the Smart Devices out
there, but I can't find the reference right now. And yes, bundled BT
software on a PDA probably uses the Widcomm API to control the
BlueTooth device rather than either of the two ways I tried.

So, all that aside, can you think of a solution to my problem? (Other
than buying the Widcomm development kit, which costs $1495.)
 
G

Guest

As to the percentage of devices using the Widcomm stack, I was under
the impression that it was the majority of the Smart Devices out
there, but I can't find the reference right now. And yes, bundled BT
software on a PDA probably uses the Widcomm API to control the
BlueTooth device rather than either of the two ways I tried.

Widcomm is used by a lot, so is Microsoft (and if you count Symbol, there's
a third stack floating out there too).
So, all that aside, can you think of a solution to my problem? (Other
than buying the Widcomm development kit, which costs $1495.)

I doubt their SDK will be of much use (there's anotehr SDK that I can't
recall the name of offhand that supports both the MS and Widcomm stuff, so
if you end ep buying something, I'd get that instead). The first thing you
need to do is try to see if that truly is where the problem lies. Either a
native app or a managed app (the free OpenNETCF Serial stuff[1] has an
identical interface, so the code swap should be trivial) but where you can
run all the way to the API calls in the debugger would be very useful.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Managed Code in an Embedded World
www.OpenNETCF.com


[1]
http://www.opennetcf.com/FreeSoftware/OpenNETCFIOSerial/tabid/252/Default.aspx
 
S

silverfox

I agree with Chris. I haven't seen this on my units.

So... I suspect a driver problem. These things are imposible for us as
developers (from the outside looking in) to fiddle. Does the SerialPort
object in CF2 suffer the same problem?

--
Richard Grier, MVP
Hard & Software
Author of Visual Basic Programmer's Guide to Serial Communications, Fourth
Edition,
ISBN 1-890422-28-2 (391 pages, includes CD-ROM). July 2004, Revised March
2006.
Seewww.hardandsoftware.netfor details and contact information.

The original problem WAS with the CF2 SerialPort object. I just
upgraded to CF2 SP2 and see some incremental progress. Now I get past
the open() but it hangs on Write(). I don't know what the correct
baud rate is supposed to be but I have tried 9600 (the default),
19,200, and 38,400 and 57,600. I attempted 115,200 but got an error
message saying that 64K was the max allowable. I think the defaults
are probably correct for data bits, stop bits, parity but I don't know
how to find out what is correct.
 
S

silverfox

You don't know much about operating systems. What if the application isn't
running application code at the time of the "stop"? What if it's in the
middle of a driver call? Is the driver left in a bad state? Can the OS
terminate the driver, too? What if another application is also in the
middle of a call to that driver? What if the driver is for the display?
It's not so simple to 'just' terminate an application.

The most-likely place for the bug is your code. I'm not convinced yet that
you are the source of the problem. The second most-likely is in the .NET
CF, hence the suggestion that you take that out of the loop by using native
code. The third most-likely is theBluetoothstack, as it was probably only
tested for the standard communication tasks: headset, ActiveSync and maybeBluetoothserial for GPS. The lest-likely is the operating system itself.
It's certainly not bug-free, but it gets used in a lot more different
scenarios than any individual program, driver, or framework.

Paul T.

Ok, I admit it.

I don't really see how the problem can be in my code, however, since
it consists of only the following two lines:

System.IO.Ports.SerialPort serialOutputPort = New
System.IO.Ports.SerialPort("COM8")
serialOutputPort.Open()

Upgrading to CF2 SP2 got past this problem, however, and as I mention
in another post, it now hangs on the following line:

serialPort.Write(msg)

I
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top