I will not be able to access the hardware I'm programming with sometimes or it's just not good to debug.
So that's why I thought to make my life a bit easier and work with a virtual serial port.
I chose to use com0com since it's pretty straight forward to set up and it's free.
My problem is that my UWP app does find the port but can't connect to it.
The code I'm using is:
public async Task<string> Init()
{
try
{
if (_serialPort == null)
{
var aqs = SerialDevice.GetDeviceSelector("COM7");
var devices = await DeviceInformation.FindAllAsync(aqs, null);
if (devices.Any())
{
await OpenPort(devices[0].Id);
return "found port";
}
}
else
{
return "port already configured";
}
return "whatever";
}
catch (Exception ex)
{
return ex.Message;
}
}
private async Task OpenPort(string deviceId)
{
try
{
_serialPort = await SerialDevice.FromIdAsync(deviceId);
if (_serialPort != null)
{
_serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
_serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
_serialPort.BaudRate = 19200;
_serialPort.Parity = SerialParity.None;
_serialPort.StopBits = SerialStopBitCount.One;
_serialPort.DataBits = 8;
_serialPort.Handshake = SerialHandshake.None;
}
}
catch (Exception ex)
{
throw ex;
}
}
I know the code itself is working because I use it with the hardwarelike this. The only thing I changed is that I directly search for the COM7 port.
WHen I debug my code I can see that the port is found and loaded into "device[0]"
but it is not loaded into "devices" when i run the FromIdAsync method.
Did I do something wrong or does UWP not work with virtual ports?
My problem is that my UWP app does find the port but can't connect to it.
Currently, UWP does not support virtual serial port that with out VID and PID Parameter.
For UWP, it has very limited access to serial port the file. It defines specific DeviceId scheme within AppxManifestType.xsd. When you invoke SerialDevice.FromIdAsync() method, it will match with the following scheme, if your device id does not match. the method will not return SerialDevice. So, UWP does not support visual serial port currently.
<xs:simpleType name="ST_DeviceId">
<xs:restriction base="ST_NonEmptyString">
<xs:pattern value="any"/>
<xs:pattern value="vidpid:[0-9a-fA-F]{4} [0-9a-fA-F]{4}( (usb|bluetooth))?"/>
<xs:pattern value="model:[^;]{1,512};.{1,512}"/>
</xs:restriction>
</xs:simpleType>
There are a fewer limits to access serial port in Win32 Application , you could connect to visual serial port directly.
may be this is not directly related to the problem as you asked for the virtual ports, it give a little enlighten on the serial port problem in UWP. and as #Nico Zhu said that the UWP has limited access to Serial Port.
SerialCommunication
System-internal or on-chassis serial ports may be enumerated by DeviceInformation.FindAllAsync(), but cannot be opened by SerialDevice.FromIdAsync() because they currently are not supported. However, serial ports connected over USB, such as on USB-to-Serial cables are supported.
It is possible that the DeviceInformation collection returned by DeviceInformation.FindAllAsync() may have a serial device whose DeviceInformation.Name property is set to the machine name. This is by design and may occur when enumerating an on-board serial port
Related
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
Im trying to follow this code sample from microsoft, who is a basic code for sending/receiving data over network from windows 10 computer/phone.
Im on VS2015, i have a phone on W10 and my computer also.
The problem is that my application seems to create packet and send one to establish the connection (i have seen this packet with wireshark), but i never received it on the server side.
Here is code to listen port from the actual internet connection available and wait for a connection :
public static async void StartServer()
{
try
{
StreamSocketListener listener = new StreamSocketListener();
//ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
//await listener.BindServiceNameAsync("5043", SocketProtectionLevel.PlainSocket, internetConnectionProfile.NetworkAdapter);
listener.ConnectionReceived += OnConnection;
await listener.BindServiceNameAsync("5043");
Debug.WriteLine("Server Started !");
}
catch (Exception)
{
Debug.WriteLine("Error StartServer Method !");
}
}
The method "OnConnection" is never reach cause the event "ConnectionReceived" is never called.
Here is the code to establish connection (the string ipDestination contain the internet ip address from my phone for example, that i get from checkip.dyndns.org) :
private static StreamSocket socket;
public static async void Connect(string ipDestination)
{
try
{
//Destination Ip address
HostName host = new HostName(ipDestination);
ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
socket = new StreamSocket();
socket.Control.KeepAlive = true;
await socket.ConnectAsync(host, "5043");
//EXCEPTION RAISE HERE after a moment "System.Runtime.InteropServices.COMException, cant join destination.
Debug.WriteLine("Connected !");
}
catch (Exception)
{
Debug.WriteLine("Erreur Connect Method !");
}
}
I think i should miss something but i dont know why and im block at this part since a long and can't continue my project...
I apologize for the bad english I try to make my best :)
Update from comments :
As Jay Zuo suggested, i have try to use local address on private
network and it works, i can establish connection, send and receive
data without problems... So the problem come when i use internet IP
address, and i still can't figure why...
As Kiewic suggested, i have simplify my code and commented the
precedent version.
If you want to know how to use 32feet.NET library to communicate with bluetooth devices, read the solution
I am currently trying to communicate via bluetooth between a computer and a self-built .NET Gadgeteer prototype.
The Gadgeteer prototype consists of the mainboard, a power supply and a bluetooth module. The module is in discoverable mode.
On the computer a custom bluetooth program based on 32feet .NET Bluetooth is running. The program detects all bluetooth devices in range and tries to pair with them. However, this is not done automatically at the moment, I have to enter a pairing code for the device.
How can I pair devices without entering the pairing code?
Devices are found, the problem is the pairing part. I experimented a lot, but didn't find a solution...
foreach (BluetoothDeviceInfo device in this.deviceList)
{
try
{
//BluetoothClient client = new BluetoothClient(this.CreateNewEndpoint(localAddress));
//BluetoothEndPoint ep = this.CreateNewEndpoint(device.DeviceAddress);
EventHandler<BluetoothWin32AuthenticationEventArgs> handler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(HandleRequests);
BluetoothWin32Authentication auth = new BluetoothWin32Authentication(handler);
BluetoothSecurity.PairRequest(device.DeviceAddress, null);
}
}
This code block initiates the pairing and it works, but Windows is asking me to enter the pairing code for the device. I read about the BluetoothWin32Authentication to prevent this case but I don't get it right.
private void HandleRequests(object that, BluetoothWin32AuthenticationEventArgs e)
{
e.Confirm = true;
}
This is the code of the event handler (http://32feet.codeplex.com/wikipage?title=BluetoothWin32Authentication)
If you simply want to allow the pairing to go ahead when to SSP devices are connecting then handling the callback and setting e.Confirm=True will be enough -- but that is a little insecure...
I am confused -.- The goal is that the application and the gadgeteer module can send data in both directions without any user interference.
Is it true that I can't pair devices automatically without user interaction?
Is it true that if two device were already paired they can exchange data without user interaction?
I figured out how to solve my problems and my knowledge about Bluetooth connections is a bit bigger now. If someone else has problems with that, I provide my solution. The code examples represent the C# implementation of a bluetooth controller with the 32feet Bluetooth library.
Scanning
This means that devices in range are detected. My code:
// mac is mac address of local bluetooth device
BluetoothEndPoint localEndpoint = new BluetoothEndPoint(mac, BluetoothService.SerialPort);
// client is used to manage connections
BluetoothClient localClient = new BluetoothClient(localEndpoint);
// component is used to manage device discovery
BluetoothComponent localComponent = new BluetoothComponent(localClient);
// async methods, can be done synchronously too
localComponent.DiscoverDevicesAsync(255, true, true, true, true, null);
localComponent.DiscoverDevicesProgress += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesProgress);
localComponent.DiscoverDevicesComplete += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesComplete);
private void component_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
// log and save all found devices
for (int i = 0; i < e.Devices.Length; i++)
{
if (e.Devices[i].Remembered)
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is known");
}
else
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is unknown");
}
this.deviceList.Add(e.Devices[i]);
}
}
private void component_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
{
// log some stuff
}
Pairing
This means that devices get coupled with the local bluetooth device. This needs to be done once by entering a code of both sides. Can be done via code so that the user doesn't even notice that a device was added. My code for this purpose:
// get a list of all paired devices
BluetoothDeviceInfo[] paired = localClient.DiscoverDevices(255, false, true, false, false);
// check every discovered device if it is already paired
foreach (BluetoothDeviceInfo device in this.deviceList)
{
bool isPaired = false;
for (int i = 0; i < paired.Length; i++)
{
if (device.Equals(paired[i]))
{
isPaired = true;
break;
}
}
// if the device is not paired, pair it!
if (!isPaired)
{
// replace DEVICE_PIN here, synchronous method, but fast
isPaired = BluetoothSecurity.PairRequest(device.DeviceAddress, DEVICE_PIN);
if (isPaired)
{
// now it is paired
}
else
{
// pairing failed
}
}
}
Connecting
This means establishing a connection and exchanging of data. Again some code:
// check if device is paired
if (device.Authenticated)
{
// set pin of device to connect with
localClient.SetPin(DEVICE_PIN);
// async connection method
localClient.BeginConnect(device.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), device);
}
// callback
private void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
// client is connected now :)
}
}
If you keep the order scan, pair, connect, everything should work fine. To send or receive data, use the GetStream() method of the BluetoothClient. It provides a network stream that can be manipulated.
Receiving a connection
If you want another device to connect with your device you need to listen to incoming connection requests. This only works if the device have already been paired before. My code:
BluetoothListener l = new BluetoothListener(LOCAL_MAC, BluetoothService.SerialPort);
l.Start(10);
l.BeginAcceptBluetoothClient(new AsyncCallback(AcceptConnection), l);
void AcceptConnection(IAsyncResult result){
if (result.IsCompleted){
BluetoothClient remoteDevice = ((BluetoothListener)result.AsyncState).EndAcceptBluetoothClient(result);
}
}
Replace LOCAL_MAC with a valid BluetoothAddress (e.g. by using BluetoothAddress.Parse();). After the devices are connected they can exchange messages via the underlying stream. If the connection does not work there might be authentication issues, so try setting the local device pin in the listener (l.SetPin(LOCAL_MAC, MY_PASSWORD);
I am prototyping a sort of Arduino-based docking station for a tablet, using the USB port as connector. This means I need to support to ability to plug/unplug the USB connector while the application on the tablet is running.
The tablet runs a c# application (.net 4.5 on Win7 64 bit) in which I am connecting to the Arduino Uno. When the application is launched I loop all available COM ports using:
var ports = SerialPort.GetPortNames(); // -> [COM3,COM4,COM8]
foreach (var port in ports)
{
var serial = new SerialPort(portname, baudRate);
//attempt handshake and connect to right port
}
This work fine, but if I unplug and replug the USB cable and reattempt to reconnect to the Arduino (while the application is still running), the Arduino port (COM8) is no longer listed in:
SerialPort.GetPortNames(); // -> [COM3,COM4] and no COM8
Even restarting the application (with the Arduino replugged) will result in only [COM3,COM4] being listed.
The only way to get it back to work is to unplug and replug the Arduino while the application is not running.
What confuses me is the fact that when I plug in the Arduino Uno after starting the application, the SerialClass does recognize the newly added port and allows me to connect.
The problem only occurs when I unplug and replug the device when the application is running. It seems that despite the ability to reset the COM port (in code or manually in device manager), the SerialClass (and native Win32_SerialPort - I checked this too) do not recognize this, unless I restart the application
What could be the reason for this? And how can I make sure that my application can reconnect to that port? Are there any alternatives to using the SerialPort to handle the USB connector?
I found a solution that can handle plugging and unplugging a SerialPort.
First of all, it requires the use the SafeSerialPort, which allows you to dispose the serial port properly.
SafeSerialPort serialPort;
private void Connect()
{
string portname = "COM8";
serialPort = new SafeSerialPort(portname, 9600);
serialPort.DataReceived += port_DataReceived;
serialPort.Open();
}
Second, you need to use LibUsbDotNet to detect whether a USB device is connected or disconnected. This will allow you to determine whether to connect to the device or reset the COM port.
public UsbDevice MyUsbDevice;
//Find your vendor id etc by listing all available USB devices
public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001);
public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
if (e.Object.ToString().Split('\n')[1].Contains("0x2341"))
{
if (e.EventType == EventType.DeviceArrival)
{
Connect();
}
else if(e.EventType == EventType.DeviceRemoveComplete)
{
ResetConnection();
}
}
}
Finally, disposing the SerialPort will makes sure it is registered by Windows in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM, meaning that SerialPort.GetPortNames() can re-detect the port.
private void ResetConnection()
{
try
{
//Send any data to cause an IOException
serialPort.Write("Any value");
}
catch (IOException ex)
{
//Dispose the SafeSerialPort
serialPort.Dispose();
serialPort.Close();
}
}
After this process, you can simply reconnect to the COM port when the USB device is connected without the need to restart the application.
Full code:
using LibUsbDotNet;
using LibUsbDotNet.DeviceNotify;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
SafeSerialPort serialPort;
public SerialPortTest()
{
Connect();
UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent;
}
private void Connect()
{
string portname = "COM8";
serialPort = new SafeSerialPort(portname, 9600);
serialPort.DataReceived += port_DataReceived;
serialPort.Open();
}
private void ResetConnection()
{
try
{
serialPort.Write("Any value");
}
catch (IOException ex)
{
serialPort.Dispose();
serialPort.Close();
}
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(serialPort.ReadExisting());
}
public UsbDevice MyUsbDevice;
//Vendor ID etc can be found through enumerating the USB devices
public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001);
public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
//if this is your usb device, in my case an Arduino
if (e.Object.ToString().Split('\n')[1].Contains("0x2341"))
{
if (e.EventType == EventType.DeviceArrival)
{
Connect();
}
else
{
ResetConnection();
}
}
}
So I believe this is happening because your program is caching the address of the USB the first time it is plugged in.
When someone plugs in a device, the hub detects voltage on either D+
or D- and signals the insertion to the host via this interrupt
endpoint. When the host polls this interrupt endpoint, it learns that
the new device is present. It then instructs the hub (via the default
control pipe) to reset the port where the new device was plugged in.
***This reset makes the new device assume address 0, and the host can
then interact with it directly; this interaction will result in the
host assigning a new (non-zero) address to the device.
Your best bet is to research how to programically flush the address cache of USB devices.
Reference:http://en.wikipedia.org/wiki/USB_hub
I'm about to start developing a small app (C#) that communicates with a PLC and a testing unit via Serial Ports - this is my first venture into this area.
In essence, I am going to send the PLC a signal to start an operation, and then I am going to wait for the result of that operation from the test unit (which will be independently communicating with the PLC) to return a ASCII string.
Depending on the content of that string, I may want to listen to a signal from the PLC...
It's all new to me, so at the moment, I'm just researching System.IO.Ports.SerialPort; digression: are there third part products out there than simplify interaction with the Serial Port, or are the built-in classes as good as you will get? I'm thinking of ease of use as opposed to better features.
However, it will be a few weeks before the hardware is available for development and testing, so I was wondering how I could simulate communication to/from the serial port so that I can start developing my app?
[I don't yet know how the PLC and the PC are due to communicate - I understand it will be binary rather than text, but at the moment, that is all I know.]
Abstract away your serial port comms behind an interface so that you can code your app against the interface and then test with a 'fake' implementation. When you've got the hardware for the real thing, you can code up the 'real' implementation of the interface and swap out the fake one.
So for example, you'd have an interface
public interface ISerialComms
{
void SendMessage(string message)
}
and you'd code your app against that interface using a fake implementation:
public class FakeSerialComms : ISerialComms
{
public void SendMessage(string message)
{
//some implementation
}
}
Hope that helps!
I've had some success in the past using com0com.
There are two pieces of software that I have found invaluable while doing serial port work.
Free Serial Port Monitor
http://www.serial-port-monitor.com
Despite the cheesy name, it is actually quite useful. Note that you should have it stop listening to your port if you go to unplug a USB-to-Serial converter. Otherwise it can crash (well... wait indefinitely on exit, which is annoying). It doesn't have to put itself in the middle of a serial connection to sniff data. It monitors the IO using the Win32 API.
Franson Serial Port Tools
http://franson.com/serialtools/
Or.. any loopback software really. There are lots out there. This allows you to send data and receive it within software. If you end up doing any GPS work, Franson also has a nice GPS simulator so you don't have to sit outside the whole time to debug code.
Finally, if you have had enough with the built-in serial class and its horrendous shortcomings, then you need a replacement, and going straight to the Win32 API will take forever.
CommStudio
I have found CommStudio to be absolutely rock solid. Quite frankly, after spending 5 months researching and buying other options, it is the only one that works perfectly with removable USB adapters. All of the other solutions have issues when the device is plugged back in. You can download their free "Express" version here: http://www.componentsource.com/products/commstudio/downloads.html?rv=42917
I have wrote an article on this topic using Virtual Serial Port Driver 9.0 standard using Microsoft SerialPort Class (Sytem.IO.Ports), it is of course possible to use any other comm port tool.
In the software I create 2 virtual ports COM1 and COM2.
I use COM1 to emulate as data sender.
I use COM2 to receive what ever being send from COM1.
This is helpful if you are developing Embedded or IoT solution.
Emulator (in this example as random accelerometer)
private static bool _continue;
private static SerialPort _serialPort;
public static void Main()
{
var stringComparer = StringComparer.OrdinalIgnoreCase;
var readThread = new Thread(Read);
_serialPort = new SerialPort
{
PortName = "COM1",
ReadTimeout = 500,
WriteTimeout = 500
};
_serialPort.Open();
_continue = true;
readThread.Start();
while (_continue)
{
var x = ValueGenerator();
var y = ValueGenerator();
var z = ValueGenerator();
var message = $"x:{x};y:{y};z:{z}";
if (stringComparer.Equals("quit", message))
{
_continue = false;
}
else
{
_serialPort.WriteLine(message);
Thread.Sleep(200);
}
}
readThread.Join();
_serialPort.Close();
}
public static double ValueGenerator()
{
const int range = 1;
var random = new Random();
return random.NextDouble() * range;
}
public static void Read()
{
while (_continue)
{
try
{
var message = _serialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
And my data receiver is almost similar
private static bool _continue;
private static SerialPort _serialPort;
public static void Main()
{
var stringComparer = StringComparer.OrdinalIgnoreCase;
var readThread = new Thread(Read);
_serialPort = new SerialPort
{
PortName = "COM2",
ReadTimeout = 500,
WriteTimeout = 500
};
_serialPort.Open();
_continue = true;
readThread.Start();
while (_continue)
{
var message = Console.ReadLine();
if (stringComparer.Equals("quit", message))
{
_continue = false;
}
else
{
_serialPort.WriteLine(message);
}
}
readThread.Join();
_serialPort.Close();
}
public static void Read()
{
while (_continue)
{
try
{
var message = _serialPort.ReadLine();
Console.WriteLine(message);
}
catch (TimeoutException) { }
}
}
Disclaimer: the link of this guideline refer to my personal web site.
I like David's answer above but if your looking to do integration tests and actually test your serial port communication I have used and application called ViN soft virtual serial cable in the past to basically create 2 serial ports on your machine that are connected by a virtual cable.
Also if you have a serial port on your development machine you could use it to connect to another machine that has a serial port and write an application that will basically simulate the communication of the PLC.
I would prefer to use a combination of both David's method and this method to ensure proper testing.
There is another resource out there that emulates serial ports for windows if anyone else is still looking for decent serial debugging tools.
The 32-bit version is free and seems pretty decent. It's called Virtual Serial Ports Emulator.
Very old but still might be useful to some. Instead of relying on COM interaction, just use the SerialPort.BaseStream to communicate with the port. This allows you to simply use a standard stream interface for communication, in other words, doesn't matter if you use serial ports, TCP connections, or even file streams. Perfect for simulation.