How can I identify COM port devices on Windows

184 views (last 30 days)
I am working on several projects that involve using Arduinos and other serial connected devices with a MATLAB GUI. I have a solution for identifying the devices that opens all the COM ports one at a time and queries them. By checking the responses I can identify which devices are connected to which COM ports. This only works if the devices have unique responses to the query sent. I am currently using *IDN? as my query because it seems to be fairly standard. Of course, to interact with the Arduinos, I have to make sure they respond to this query in a predictable way.
My problem is that this process is fairly slow and a little error prone. In Windows Device Manager, each Port is identified by name and COM number. Is there any way to get these names inside of MATLAB? I want to be able to ID the ports without having to open connections to them all.

Accepted Answer

Benjamin Avants
Benjamin Avants on 7 Jan 2014
OK, after a lot of research I found a solution. It will only work on Windows (7 for sure but maybe not others). I use DOS commands to query the registry in two places to identify which COM ports are connected and then check the USB section of the CurrentContrlSet to match up friendly names.
My code my not be completely optimized but it runs in about .1 seconds so it suits my purposes.
The result is a cell array with friendly names and COM number pairs for each connected USB-serial device that has a friendly name.
Code posted below:
Skey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM';
% Find connected serial devices and clean up the output
[~, list] = dos(['REG QUERY ' Skey]);
list = strread(list,'%s','delimiter',' ');
coms = 0;
for i = 1:numel(list)
if strcmp(list{i}(1:3),'COM')
if ~iscell(coms)
coms = list(i);
else
coms{end+1} = list{i};
end
end
end
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\';
% Find all installed USB devices entries and clean up the output
[~, vals] = dos(['REG QUERY ' key ' /s /f "FriendlyName" /t "REG_SZ"']);
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
out = 0;
% Find all friendly name property entries
for i = 1:numel(vals)
if strcmp(vals{i}(1:min(12,end)),'FriendlyName')
if ~iscell(out)
out = vals(i);
else
out{end+1} = vals{i};
end
end
end
% Compare friendly name entries with connected ports and generate output
for i = 1:numel(coms)
match = strfind(out,[coms{i},')']);
ind = 0;
for j = 1:numel(match)
if ~isempty(match{j})
ind = j;
end
end
if ind ~= 0
com = str2double(coms{i}(4:end));
% Trim the trailing ' (COM##)' from the friendly name - works on ports from 1 to 99
if com > 9
length = 8;
else
length = 7;
end
devs{i,1} = out{ind}(27:end-length);
devs{i,2} = com;
end
end
  2 Comments
dpb
dpb on 8 Jan 2014
I hadn't seen your earlier comment/query until now.
My answer, however, would have been that the best I would know would be to find where in the registry the stuff is stored 'cuz to best of my knowledge that's where the Device Manager finds it--but I couldn't have told you precisely where w/o searching MSDN or the like...which it appears you've already done. :)
Jim Hokanson
Jim Hokanson on 4 Aug 2017
One thing to note about this answer is that it assumes USB based serial port devices.

Sign in to comment.

More Answers (4)

dpb
dpb on 19 Dec 2013
Edited: dpb on 20 Dec 2013
Probably easiest is
[~,res]=system('mode');
ix=strfind(res,'COM')
Will return starting location in the results string for the COM ports found. mode does stroke each port, however.
There are Win API entry points to write DLL code; probably could find something on the 'net or a utility. But, for quick 'n dirty, I'd think parsing the output as above would be about as sweet as it gets...
ADDENDUM:
Came to me depending on what you want the result to be, specifically, regexp can be your friend...to find the names COMnn:, say...
>> regexp(res,'COM\d+:','match')'
ans =
'COM3:'
'COM4:'
>>
Wrap in a function and you've got a handy little utility itself that hides the ugly stuff and extraneous output...
function ports = findserial()
% returns cell array of found serial ports under Win
% uses CLI MODE command internally
[~,res]=system('mode');
ports=regexp(res,'COM\d+:','match')';
  2 Comments
Benjamin Avants
Benjamin Avants on 6 Jan 2014
Thanks dpb,
This is probably better than what I'm doing now, but it still doesn't give me the name associated with the device on the port as it shows up in Device Manager.
ie. Arduino Mega 2560 (COM5)
I'm not that familiar with DLL code, so any advice on tackling the problem that way would be appreciated.

Sign in to comment.


Vitaly Gavrilyuk
Vitaly Gavrilyuk on 6 Nov 2015
I've solved similar problem in Matlab this way:
dev_name = 'Silicon Labs CP210x USB to UART Bridge';
[~,res]=system('wmic path Win32_SerialPort');
ind = strfind(res,dev_name);
if (~isempty(ind))
port_name = res(ind(1)+length(dev_name)+2:ind(1)+length(dev_name)+5);
fprintf('COM-port is %s\n',port_name);
try
port_obj = serial(port_name);
fopen(port_obj);
fprintf('%s is opened\n',port_name);
catch err
fprintf('%s\n%s\n',err.identifier,err.message);
end
else
fprintf('COM-port is not find\n');
end

Ben
Ben on 15 Jun 2015
I have been working with several devices connected and need to identify their COM ports by the communication settings and this is what I came up with:
function [GPS_port_num, AHRS_port_num, LIDAR_port_num] = findCOMports
%%FINDCOMPORTS Finds which COM ports devices are connected to.
% [GPS, AHRS, LIDAR] = findCOMports detects devices connected to system
% COM ports and returns the port number for each device. Windows only?
% Get the information using a system command
[~,res]=system('mode');
% Check some device is connected
try
% Find the index of matching strings
index(1,:) = strfind(res, 'COM');
index(2,:) = strfind(res, 'Baud:');
index(3,:) = strfind(res, 'Data Bits:');
index(4,:) = strfind(res, 'Stop Bits:');
catch
warning('No devices connected!');
return;
end
% Put values for port numbers, baud rates, data bits and stop bits in
% an array, with each column containing the values for each device.
% Number of columns is therefore the number of connected devices.
ports = zeros(4,size(index,2)); %Preallocate array
for i=1:size(index,2)
ports(1,i) = sscanf(res(index(1,i) + length('COM'):end), '%g', 1);
ports(2,i) = sscanf(res(index(2,i) + length('Baud:'):end), '%g', 1);
ports(3,i) = sscanf(res(index(3,i) + length('Data Bits:'):end), '%g', 1);
ports(4,i) = sscanf(res(index(4,i) + length('Stop Bits:'):end), '%g', 1);
end
% Find indexes of matching data
[~,ahrs] = find(ports == 115200);
[~,gps] = find(ports == 1200);
[~,lidar] = find(ports == 11500000);
% Store port number for matched devices
AHRS_port_num = ports(1,ahrs);
GPS_port_num = ports(1,gps);
LIDAR_port_num = ports(1,lidar);
% Inform the user if any expected devices aren't connected
if isempty(AHRS_port_num); warning('AHRS is not connected'); end
if isempty(GPS_port_num); warning('GPS is not connected'); end
if isempty(LIDAR_port_num); warning('LIDAR is not connected'); end
end
Obviously it's highly specific to my project, but it might be helpful to someone else in a similar situation.

Andrei
Andrei on 12 Jan 2018
As of MATLAB R2017a you can use seriallist. This will return the list of available serial ports, but not the Windows port descriptions from Device Manager.

Categories

Find more on Labeling, Segmentation, and Detection in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!