Unable to Connect to Virtual Serial Port - c#

I'm writing a .NET application running on Windows CE 6 that creates a Bluetooth Serial Port. The call to RegisterDevice() returns successfully, and SerialPort.GetPortNames() indicates the the COM port exists. However, when I attempt to open the COM port using .NET's SerialPort class, it throws an IOException, stating that the port does not exist. If I attempt to open it using CreateFile, the call fails, and GetLastError returns error 6 (INVALID_HANDLE). However, if I create a registry key under HKLM\Software\Microsoft\Bluetooth\Serial and restart the device to allow the Microsoft Bluetooth Stack to initialize the port, I can connect to the serial port without issue. I'd like to avoid making the user restart the device, if possible.
My code to create the virtual serial port:
static public IntPtr RegisterVirtualComPort(int index, long address, Guid service)
{
PORTEMUPortParams portParams = new PORTEMUPortParams();
portParams.uiportflags = RFCOMM_PORT_FLAGS.REMOTE_DCB;
portParams.flocal = false;
portParams.device = address;
portParams.uuidService = service;
IntPtr handle = RegisterDevice("COM", index, "btd.dll", ref portParams);
return handle;
}
I attempt to test the COM port via P/Invoke here:
static public bool TestComPort(int index)
{
string portName = string.Format("COM{0}:", index.ToString());
IntPtr handle = CreateFile(portName, DESIRED_ACCESS.GENERIC_READ | DESIRED_ACCESS.GENERIC_WRITE, FILE_SHARE.FILE_SHARE_NONE, IntPtr.Zero, CREATION_DISPOSITION.OPEN_EXISTING, 0, IntPtr.Zero);
bool success = handle.ToInt32() != -1;
CloseHandle(handle);
if (!success)
{
int errorCode = Marshal.GetLastWin32Error();
App.Logger.DebugFormat("TestComPort failed for \'{0}\', return error code {1}.", portName, errorCode);
}
return success;
}
Any help would appreciated.

Related

Can't access COM port greater than 99 in C#

I have a small issue with a program I am writing in Visual Studio 2022.
I have numerous devices that attach to the USB virtual com port, and because of the way that Windows enumerates the USB to serial chip in the device, I can have com ports listed as well over 100 (576 at last count). These com ports are not connected simultaneously, but one at a time, each enumerating as one higher than the previous port.
My problem is that I can access up to COM99, but when it rolls over to 100, the port will not connect. There is no error message or exception thrown.
The ComboBox will find port 100 (or greater) but the serial port will not connect. I am wondering if the System.IO.Ports Serial function is truncating my port string to "10" for instance.
I should mention that this code works flawlessly up to port 99 (on many different computers). I can see port 100 or greater in the ComboBox, but no success. This should be a simple thing but I'm baffled.
Any help or suggestions gratefully received.
I am using this code for com port connections:
private bool ScanSerial()
{
bool success = false;
//Open the serial port and get the number of the active serial port
serialPortComboBox.Items.Clear();
string[] serialPortNumbers = SerialPort.GetPortNames();
// Iterate each port and add it to the serial port drop down box
foreach (string port in serialPortNumbers)
{
if (!String.IsNullOrEmpty(port))
{
serialPortComboBox.Items.Add(port);
success = true;
}
else
{
MessageBox.Show("No available serial ports", "Serial Ports", MessageBoxButtons.OK);
serialPortInUse = null;
return false;
}
}
// default the highest numbered port as the port to use - the program will try to connect to this port
// if it doesn't find a device, user will have to override the method by selecting from the dropdown and trying again
string lastPort = serialPortNumbers.Max();
serialPortComboBox.Text = lastPort;
label10.Text = lastPort;
serialPortInUse = lastPort;
return success;
}
public bool Connect(string comPort)
{
bool success;
// Baud rate 57600, 8, N, 1 is standard
{
// Allow the user to set the appropriate properties.
_serialPort.PortName = comPort;
_serialPort.BaudRate = 57600;
_serialPort.Parity = Parity.None;
_serialPort.DataBits = 8;
_serialPort.StopBits = StopBits.One;
_serialPort.Handshake = Handshake.None;
_serialPort.Encoding = Encoding.GetEncoding(0);
_serialPort.ReadTimeout = 500;
_serialPort.WriteTimeout = 500;
}
try
{
_serialPort.Open();
success = true;
_continue = true;
}
catch (Exception ex)
{
Console.WriteLine("An exception was thrown: \n {0}", ex.ToString());
Console.WriteLine("Press enter to continue.");
Console.ReadLine();
success = false;
}
return success;
}
You can find GetPortNames() source code on github, it iterates over a registry key
https://github.com/dotnet/runtime/blob/b056b7b6a1eca5171e42f697a0b3d3c60d1fc048/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialPort.Win32.cs
There several methods to get the ports. Checkout this post.
How do I get a list of available serial ports in Win32?
Since I guess you are using some kind of vendor specific serialport virtual adapter it make sense to search the registry for a high port e.g COM255 to find a more reliable registry way. I would guess it is an USB PNP device.
Maybe somewhere in HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum

Client Bluetooth connection with 32feet.NET fails all the time

I'm trying to get a Bluetooth socket connection up and running but for some reason my client will not connect.
More precisely I get an exception when I try to connect to the stream:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
All examples I found online didn't really solve my problem and I'm currently not really sure where the problem comes from.
The scanning and pairing works fine - I see that the Bluetooth device in question gets successfully paired.
I try to connect via first setting the Client and then call connect
Client Bluetooth name, address and pin are known:
public bool SetClient(String clientName, String btAddress, String pin)
{
bool retVal = false;
m_remoteBluetoothClient = new BluetoothDeviceInfo(BluetoothAddress.Parse(btAddress));
m_localBluetoothClient.SetPin(pin);
if (m_remoteBluetoothClient.Authenticated)
{
//m_localBluetoothClient.Authenticate = true;
retVal = true;
}
else
{
if (BluetoothSecurity.PairRequest(m_remoteBluetoothClient.DeviceAddress, pin))
{
retVal = true;
}
}
return retVal;
}
Then an async connect:
private void ClientConnectThread()
{
m_localBluetoothClient.BeginConnect(m_remoteBluetoothClient.DeviceAddress, BluetoothService.SerialPort, Connect, m_localBluetoothClient);
}
private void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
m_localBluetoothClient.EndConnect(result);
mBtStream = m_localBluetoothClient.GetStream();
}
}
The locals m_localBluetoothEndpoint and m_localBluetoothClient are created like this although the Endpoint is more or less new (before I used BluetoothCLient without parameter):
m_localBluetoothEndpoint = new BluetoothEndPoint(BluetoothRadio.PrimaryRadio.LocalAddress, BluetoothService.SerialPort);
m_localBluetoothClient = new BluetoothClient(m_localBluetoothEndpoint);
I also tried to work with a Listener in case the remote devices wants to connect but the callback gets never called:
public void SetupListener()
{
var listener = new BluetoothListener(BluetoothService.SerialPort);
listener.Start();
listener.BeginAcceptBluetoothClient(this.BluetoothListenerAcceptClientCallbackTwo, listener);
}
Can anyone tell me if there is anything wrong with my connection approach above and how I can figure out why I get the exception mentioned above?
The exception gets thrown here:
m_localBluetoothClient.EndConnect(result);
A thing I also don't understand is that the SupportedServices call to the remoteCLient returned 0 guids - so the device did not list any Bluetooth services.
m_remoteBluetoothClient.InstalledServices()
Thank you

Communication with HID device hangs on read/write (AS3992 RFID reader)

I'm trying to communicate with UHF RFID reader based on AS3992 chip.
This device is detected by Windows as standard HID and it works with 3rd party app (I found some UHF RFID Reader GUI by LinkSprite which works, but it seems like some older C++ application).
So I'm trying to integrate this device support into my .NET application. After some research I tried HidLibrary, but when I'm trying to write something to this device (initial sequence in this sample), it hangs on "write".
Does anybody know what I'm doing wrong?
Thank you!
My OS is Win 8.1 x64.
Here's the sample application:
using HidLibrary;
namespace HidTest2
{
class Program
{
static void Main(string[] args)
{
var devices = HidDevices.Enumerate(0x1325);
var rfid = devices.First();
rfid.OpenDevice();
rfid.Write(new byte[] { 0x31, 0x03, 0x01 }); // Application hangs here
while (true) // I can't get here
{
Thread.Sleep(50);
var result = rfid.Read();
Console.Write(result.Data);
}
}
}
}
PS: I also tried HidSharp, but I got same result. HID device detected, but I can't write into it.
PSS: This is the device: Link to ebay
I can't find a datasheet for the AS3229 chip that you mentioned, so I'm guessing here...
The device is probably presenting as a USB keyboard, so you would typically only be able to write LED status bits to it (Caps lock, Num lock, Shift). Is that what you are trying to write to it?
Try removing the write and just wait for the scanned RFID string to come in.
Edit: It looks like this device is presenting as a serial device over USB...I found a description closely matching it here:
https://s3.amazonaws.com/linksprite/cuttonwood/datasheet.pdf
If it's the same device you are testing then I would try communicating to it over a COM port API rather than using the relatively lower level HID APIs you have been using.
Because time by time I get an email how and if I solved this issue, here's an answer:
I had to replace original firmware for HID communication by firmware for serial communication (search for "as399x uart 115200 hex" or "as399x uart 9600 hex" on the internet) and then it worked like a sharm. Of course you need proper programmer for C8051Fxxx (about 20$ from China), USB-Serial converter and be familiar with some soldering (You'll have to solder pins on board for JTAG and Serial port).
As mentioned above, the device may not actually be a Hid device. Have you tried enumerating through USB devices instead of Hid devices? Here is some code to enumerate USB or Hid devices. The code is here.
For Hid devices use a ClassGuid of : 4D1E55B2-F16F-11CF-88CB-001111000030
and for Win USB devices use: dee824ef-729b-4a0e-9c14-b7117d33a817
https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Device.Net/Windows/WindowsDeviceConstants.cs
public async Task<IEnumerable<DeviceDefinition>> GetConnectedDeviceDefinitions(uint? vendorId, uint? productId)
{
return await Task.Run<IEnumerable<DeviceDefinition>>(() =>
{
var deviceDefinitions = new Collection<DeviceDefinition>();
var spDeviceInterfaceData = new SpDeviceInterfaceData();
var spDeviceInfoData = new SpDeviceInfoData();
var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData();
spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData);
spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData);
var guidString = ClassGuid.ToString();
var copyOfClassGuid = new Guid(guidString);
var i = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, APICalls.DigcfDeviceinterface | APICalls.DigcfPresent);
if (IntPtr.Size == 8)
{
spDeviceInterfaceDetailData.CbSize = 8;
}
else
{
spDeviceInterfaceDetailData.CbSize = 4 + Marshal.SystemDefaultCharSize;
}
var x = -1;
var productIdHex = GetHex(productId);
var vendorHex = GetHex(vendorId);
while (true)
{
x++;
var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(i, IntPtr.Zero, ref copyOfClassGuid, (uint)x, ref spDeviceInterfaceData);
if (!isSuccess)
{
var errorCode = Marshal.GetLastWin32Error();
if (errorCode == APICalls.ERROR_NO_MORE_ITEMS)
{
break;
}
throw new Exception($"Could not enumerate devices. Error code: {errorCode}");
}
isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(i, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData);
WindowsDeviceBase.HandleError(isSuccess, "Could not get device interface detail");
//Note this is a bit nasty but we can filter Vid and Pid this way I think...
if (vendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex)) continue;
if (productId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex)) continue;
deviceDefinitions.Add(GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath));
}
APICalls.SetupDiDestroyDeviceInfoList(i);
return deviceDefinitions;
});
}

How to know whether I'm connected to a network or not?

I'm using .Net 4.0 in VS 2010.
I can retreive the IP Address of my machine as
string hostname = Dns.getHostName();
IPHostEntry host = Dns.getHostEntry(hostname);
Now host.AddressList is an array of IPAddresses.
I noticed that AddressList[0] contains nothing, AddressList[1] the loopback address. I'm not sure about other indices.
If I have created a server on one machine and it wants to populate its IP to client (may be the machine only), then which IP (among host.AddressList) shall I populate? Which index to use?
How do I know whether I'm connected to a LAN or the internet, or not connected at all?
Please clarify.
There are several ways to do that (I think you may use a combination of [2] and [3]).
Solution 1
If you include a reference to Microsoft.VisualBasic you can use Microsoft.VisualBasic.Devices.Network.IsAvailable property to check if a network connection is available (and related events to be notified when this condition changes).
Solution 2
Import the API function to check it:
[Flags]
enum InternetConnectionState : int
{
INTERNET_CONNECTION_MODEM = 0x1,
INTERNET_CONNECTION_LAN = 0x2,
INTERNET_CONNECTION_PROXY = 0x4,
INTERNET_RAS_INSTALLED = 0x10,
INTERNET_CONNECTION_OFFLINE = 0x20,
INTERNET_CONNECTION_CONFIGURED = 0x40
}
[DllImport("WININET", CharSet=CharSet.Auto)]
static extern bool InternetGetConnectedState(ref InternetConnectionState lpdwFlags, int dwReserved);
Or simply use the System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() function (better solution, the only drawback is that it's supported in the Client Profile only from 4.0).
Solution 3
Ping a known host name like Google or Microsoft (this will check DNS too).
Example
Use a combination of above techniques (in this example I use the imported API but you may prefer the other one).
static class NetworkHelpers
{
public static bool IsNetworkConnectionAvailable()
{
InternetConnectionState state = InternetConnectionState.INTERNET_CONNECTION_OFFLINE;
if (!InternetGetConnectedState(ref state, 0))
return false;
if (state == InternetConnectionState.INTERNET_CONNECTION_OFFLINE)
return false;
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
System.Net.NetworkInformation.PingReply reply = ping.Send(KnownHostName, PingTimeout);
return reply.Status == System.Net.NetworkInformation.IPStatus.Success;
}
catch (System.Net.NetworkInformation.PingException)
{
return false;
}
}
private const string KnownHostName = "http://www.microsoft.com";
private const int PingTimeout = 5000; // milliseconds
[Flags]
private enum InternetConnectionState : int
{
INTERNET_CONNECTION_MODEM = 0x1,
INTERNET_CONNECTION_LAN = 0x2,
INTERNET_CONNECTION_PROXY = 0x4,
INTERNET_RAS_INSTALLED = 0x10,
INTERNET_CONNECTION_OFFLINE = 0x20,
INTERNET_CONNECTION_CONFIGURED = 0x40
}
[System.Runtime.InteropServices.DllImport("WININET", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool InternetGetConnectedState(ref InternetConnectionState lpdwFlags, int dwReserved);
}
This might be a possible duplicate of this question.
Don't assume you're connected to the internet (or any other network) just due to having a valid dns server or multiple IPs. Local PCs or routers might act as the active DNS and could be available even without some internet connection or any other machines on the same network. For possible solutions, have a look at the question/answers I linked above. There are also one or two examples just to detect the presence of an active network connection.
As for detecting an active internet connection, I'd always just try to request some page on the server I want to connect to (could be combined with some update check or news display), because it might be important to be able to connect to some specific server (and not just a general internet connection).
The status of the internet connection can be easily found using this:
[DllImport("wininet.dll", Charset = Charset.auto)]
private static extern bool InternetGetConnectedSate(ref InternetConnectionState_e lpdwFlags, int dwReserved);
and then for example:
if(InternetConnectionState_e.INTERNET_CONNECTION_PROXY) != 0)
{
// do your internet stuff
}

.NETCF Async TCP socket graceful shutdown issue

I have a TCP client/server app to communicate with a Windows CE device over an ActiveSync connection. Both the client and server utilize Asynchronous sockets (i.e. the Socket.Begin* and Socket.End* functions). When both the client and server are running on my desktop everything functions exactly as expected, but when the client is running on the Windows CE device that's connected over ActiveSync, I always get a SocketException on the ReceiveCallback after calling Socket.Shutdown (when the device is initiating the disconnect). The full exception is:
System.Net.Sockets.SocketException: An error message cannot be displayed because an optional resource assembly containing it cannot be found
at System.Net.Sockets.Socket.ReceiveNoCheck()
at ReceiveAsyncRequest.doRequest()
at AsyncRequest.handleRequest()
at WorkerThread.doWork()
at WorkerThread.doWorkI()
at WorkItem.doWork()
at System.Threading.Timer.ring()
Everything also seems to work correctly if the server (running on the desktop) initiates the disconnect. I have a couple ideas on how to avoid this, including disallowing device initiated disconnects and ignoring all exceptions after initiating a disconnect. However, I'd like to know why this is happening and if there's a better way of handling it.
The Disconnect and ReceiveCallbacks (operationally identical on both the server and client) are:
public bool Disconnect(StateObject state)
{
try{
if(state.isDisconnecting) return false;
state.isDisconnecting = true;
state.sock.Shutdown(SocketShutdown.Both);
//Wait for sending and receiving to complete, but don't wait more than 10 seconds
for(int i=0; i<100 && (state.isSending || state.isReceiving); i++){
System.Threading.Thread.Sleep(100);
}
/* Log the disconnect */
state.sock.Close();
return true;
} catch (Exception e){
/* Log the exception */
return false;
}
}
private void ReceiveCallback(IAsyncResult iar)
{
StateObject state = (StateObject)iar.AsyncState;
try{
//handle the new bytes in the buffer.
int recv = state.sock.EndReceive(iar);
//Handle the buffer, storing it somewhere and verifying complete messages.
if(recv > 0){
//start listening for the next message
state.sock.BeginReceive(state.recvBuffer, 0, StateObject.BUFFER_SIZE, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
} else {
state.isReceiving = false;
Disconnect(state);
}
} catch (Exception e){
/* Log the exception */
}
}
//For reference, A StateObject looks kinda like this:
public class StateObject
{
public const int BUFFER_SIZE = 1024;
public Socket sock = null;
public bool isSending = false;
public bool isReceiving = false;
public bool isDisconnecting = false;
public byte[] recvBuffer = new byte[BUFFER_SIZE];
public byte[] sendBuffer = new byte[BUFFER_SIZE];
//Other stuff that helps handle the buffers and ensure complete messages,
// even when TCP breaks up packets.
}
It in order to get the actual exception maybe try figure out which library it needs and deploy it?
If a message connot be shown on your device, because the message is not installed on your device. You have to install a netcf.messages.cab. You will find it here:
C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics
After installing this CAB-File, run your application again and post the new error you get.

Categories