MATLABはappでシリアルポートをスキャンし、ドロップダウンメニューに表示する
MATLABはappでシリアルポートをスキャンし、ドロップダウンメニューに表示する
更新
コメントによると、R 2019には既存のAPI https://ww2.mathworks.cn/help/matlab/ref/serialportlist.html
がある.
バックグラウンドストーリー
MATLABのAppでどのシリアルポートがあるかを動的に認識するには、ドロップダウンメニューに置いてユーザーに選択させる.
シリアルポートスキャンの実装
これはネット上で探したコードです:同じディレクトリに置いて、1つを作成します.mファイル:IdentifySerialComs.m
.function devices = IdentifySerialComs()
devices = [];
Skey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM';
[~, list] = dos(['REG QUERY ' Skey]);
if ischar(list) && strcmp('ERROR',list(1:5)) %% strcmp 1
disp('Error: EnumSerialComs - No SERIALCOMM registry entry')
return;
end
list = strread(list,'%s','delimiter',' '); %#ok requires strread()
coms = 0;
for i = 1:numel(list) %%numel
if strcmp(list{i}(1:3),'COM')
if ~iscell(coms)
coms = list(i);
else
coms{end+1} = list{i}; %#ok Loop size is always small
end
end
end
out = 0;
outK = 0;
for j=1:2
switch j
case 1
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\';
case 2
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\';
end
[~, vals] = dos(['REG QUERY ' key ' /s /f "FriendlyName" /t "REG_SZ"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
disp('Error: EnumSerialComs - No Enumerated USB registry entry')
return;
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
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}; %#ok Loop size is always small
end
if ~iscell(outK)
outK = vals(i-1);
else
outK{end+1} = vals{i-1}; %#ok Loop size is always small
end
end
end
end
i_dev=1;Sservices=[];
for i = 1:numel(coms)
match = strfind(out,[coms{i},')']);
ind = 0;
for j = 1:numel(match)
if ~isempty(match{j})
ind = j;
[~, sers] = dos(['REG QUERY "' outK{ind} '" /f "Service" /t "REG_SZ"']);
sers = textscan(sers,'%s','delimiter','\t');
sers = cat(1,sers{:});
if (numel(sers)>1)
sers=strread(sers{2},'%s','delimiter',' ');
Sservices{i_dev} = sers{3};
i_dev=i_dev+1;
end
end
end
end
Sservices=unique(Sservices);
i_dev=1;
for ss=1:numel(Sservices)
key = ['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\' Sservices{ss} '\Enum'];
[~, vals] = dos(['REG QUERY ' key ' /f "Count"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
% disp('Error: EnumSerialComs - No Enumerated services USB registry entry')
% return
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
if (numel(vals)>1)
vals=strread(vals{2},'%s','delimiter',' ');
Count=hex2dec(vals{3}(3:end));
if Count>0
[~, vals] = dos(['REG QUERY ' key]);
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
out=0;
j=0;
for i = 1:numel(vals)
Enums=strread(vals{i},'%s','delimiter',' ');
try nums=hex2dec(Enums{1});
catch
nums=-1;
end
if(nums==j)
out=['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' Enums{3}];
[~, listC] = dos(['REG QUERY "' out '" /s /f "PortName" /t "REG_SZ"']);
listC = textscan(listC,'%s','delimiter','\t');
listC = cat(1,listC{:});
if (numel(listC)>1)
listC=strread(listC{2},'%s','delimiter',' ');
for i = 1:numel(coms)
if strcmp(listC{3},coms{i})
[~, NameF] = dos(['REG QUERY "' out '" /s /f "FriendlyName" /t "REG_SZ"']);
NameF = textscan(NameF,'%s','delimiter','\t');
NameF = cat(1,NameF{:});
com = str2double(coms{i}(4:end));
if com > 9
length = 8;
else
length = 7;
end
devices{i_dev,1} = NameF{2}(27:end-length); %#ok
devices{i_dev,2} = com; %#ok Loop size is always small
i_dev=i_dev+1;
end
end
end
j=j+1;
end
end
end
end
end
end
Appでの操作
2つのプライベート属性の変数を追加します.properties (Access = private)
scan_coms; %
com_num; %
end
適切な位置にドロップダウンボックスとボタンを挿入し、ボタンのコールバック関数を追加します.内容は以下の通りです.% Button pushed function: Button
function ButtonPushed(app, event)
app.scan_coms = IdentifySerialComs;
%app.DropDown.Items = '';
app.com_num = size(app.scan_coms);
for ii = 1: app.com_num(1)
app.DropDown.Items(ii) = strcat(app.scan_coms(ii, 1),'@COM', num2str(cell2mat(app.scan_coms(ii, 2))));
end
end
これにより、ボタンをクリックする後のリストの内容がシリアルポートに従って変化することが実現する.
MATLABのAppでどのシリアルポートがあるかを動的に認識するには、ドロップダウンメニューに置いてユーザーに選択させる.
シリアルポートスキャンの実装
これはネット上で探したコードです:同じディレクトリに置いて、1つを作成します.mファイル:IdentifySerialComs.m
.function devices = IdentifySerialComs()
devices = [];
Skey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM';
[~, list] = dos(['REG QUERY ' Skey]);
if ischar(list) && strcmp('ERROR',list(1:5)) %% strcmp 1
disp('Error: EnumSerialComs - No SERIALCOMM registry entry')
return;
end
list = strread(list,'%s','delimiter',' '); %#ok requires strread()
coms = 0;
for i = 1:numel(list) %%numel
if strcmp(list{i}(1:3),'COM')
if ~iscell(coms)
coms = list(i);
else
coms{end+1} = list{i}; %#ok Loop size is always small
end
end
end
out = 0;
outK = 0;
for j=1:2
switch j
case 1
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\';
case 2
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\';
end
[~, vals] = dos(['REG QUERY ' key ' /s /f "FriendlyName" /t "REG_SZ"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
disp('Error: EnumSerialComs - No Enumerated USB registry entry')
return;
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
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}; %#ok Loop size is always small
end
if ~iscell(outK)
outK = vals(i-1);
else
outK{end+1} = vals{i-1}; %#ok Loop size is always small
end
end
end
end
i_dev=1;Sservices=[];
for i = 1:numel(coms)
match = strfind(out,[coms{i},')']);
ind = 0;
for j = 1:numel(match)
if ~isempty(match{j})
ind = j;
[~, sers] = dos(['REG QUERY "' outK{ind} '" /f "Service" /t "REG_SZ"']);
sers = textscan(sers,'%s','delimiter','\t');
sers = cat(1,sers{:});
if (numel(sers)>1)
sers=strread(sers{2},'%s','delimiter',' ');
Sservices{i_dev} = sers{3};
i_dev=i_dev+1;
end
end
end
end
Sservices=unique(Sservices);
i_dev=1;
for ss=1:numel(Sservices)
key = ['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\' Sservices{ss} '\Enum'];
[~, vals] = dos(['REG QUERY ' key ' /f "Count"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
% disp('Error: EnumSerialComs - No Enumerated services USB registry entry')
% return
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
if (numel(vals)>1)
vals=strread(vals{2},'%s','delimiter',' ');
Count=hex2dec(vals{3}(3:end));
if Count>0
[~, vals] = dos(['REG QUERY ' key]);
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
out=0;
j=0;
for i = 1:numel(vals)
Enums=strread(vals{i},'%s','delimiter',' ');
try nums=hex2dec(Enums{1});
catch
nums=-1;
end
if(nums==j)
out=['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' Enums{3}];
[~, listC] = dos(['REG QUERY "' out '" /s /f "PortName" /t "REG_SZ"']);
listC = textscan(listC,'%s','delimiter','\t');
listC = cat(1,listC{:});
if (numel(listC)>1)
listC=strread(listC{2},'%s','delimiter',' ');
for i = 1:numel(coms)
if strcmp(listC{3},coms{i})
[~, NameF] = dos(['REG QUERY "' out '" /s /f "FriendlyName" /t "REG_SZ"']);
NameF = textscan(NameF,'%s','delimiter','\t');
NameF = cat(1,NameF{:});
com = str2double(coms{i}(4:end));
if com > 9
length = 8;
else
length = 7;
end
devices{i_dev,1} = NameF{2}(27:end-length); %#ok
devices{i_dev,2} = com; %#ok Loop size is always small
i_dev=i_dev+1;
end
end
end
j=j+1;
end
end
end
end
end
end
Appでの操作
2つのプライベート属性の変数を追加します.properties (Access = private)
scan_coms; %
com_num; %
end
適切な位置にドロップダウンボックスとボタンを挿入し、ボタンのコールバック関数を追加します.内容は以下の通りです.% Button pushed function: Button
function ButtonPushed(app, event)
app.scan_coms = IdentifySerialComs;
%app.DropDown.Items = '';
app.com_num = size(app.scan_coms);
for ii = 1: app.com_num(1)
app.DropDown.Items(ii) = strcat(app.scan_coms(ii, 1),'@COM', num2str(cell2mat(app.scan_coms(ii, 2))));
end
end
これにより、ボタンをクリックする後のリストの内容がシリアルポートに従って変化することが実現する.
function devices = IdentifySerialComs()
devices = [];
Skey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM';
[~, list] = dos(['REG QUERY ' Skey]);
if ischar(list) && strcmp('ERROR',list(1:5)) %% strcmp 1
disp('Error: EnumSerialComs - No SERIALCOMM registry entry')
return;
end
list = strread(list,'%s','delimiter',' '); %#ok requires strread()
coms = 0;
for i = 1:numel(list) %%numel
if strcmp(list{i}(1:3),'COM')
if ~iscell(coms)
coms = list(i);
else
coms{end+1} = list{i}; %#ok Loop size is always small
end
end
end
out = 0;
outK = 0;
for j=1:2
switch j
case 1
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\';
case 2
key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\';
end
[~, vals] = dos(['REG QUERY ' key ' /s /f "FriendlyName" /t "REG_SZ"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
disp('Error: EnumSerialComs - No Enumerated USB registry entry')
return;
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
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}; %#ok Loop size is always small
end
if ~iscell(outK)
outK = vals(i-1);
else
outK{end+1} = vals{i-1}; %#ok Loop size is always small
end
end
end
end
i_dev=1;Sservices=[];
for i = 1:numel(coms)
match = strfind(out,[coms{i},')']);
ind = 0;
for j = 1:numel(match)
if ~isempty(match{j})
ind = j;
[~, sers] = dos(['REG QUERY "' outK{ind} '" /f "Service" /t "REG_SZ"']);
sers = textscan(sers,'%s','delimiter','\t');
sers = cat(1,sers{:});
if (numel(sers)>1)
sers=strread(sers{2},'%s','delimiter',' ');
Sservices{i_dev} = sers{3};
i_dev=i_dev+1;
end
end
end
end
Sservices=unique(Sservices);
i_dev=1;
for ss=1:numel(Sservices)
key = ['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\' Sservices{ss} '\Enum'];
[~, vals] = dos(['REG QUERY ' key ' /f "Count"']);
if ischar(vals) && strcmp('ERROR',vals(1:5))
% disp('Error: EnumSerialComs - No Enumerated services USB registry entry')
% return
end
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
if (numel(vals)>1)
vals=strread(vals{2},'%s','delimiter',' ');
Count=hex2dec(vals{3}(3:end));
if Count>0
[~, vals] = dos(['REG QUERY ' key]);
vals = textscan(vals,'%s','delimiter','\t');
vals = cat(1,vals{:});
out=0;
j=0;
for i = 1:numel(vals)
Enums=strread(vals{i},'%s','delimiter',' ');
try nums=hex2dec(Enums{1});
catch
nums=-1;
end
if(nums==j)
out=['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' Enums{3}];
[~, listC] = dos(['REG QUERY "' out '" /s /f "PortName" /t "REG_SZ"']);
listC = textscan(listC,'%s','delimiter','\t');
listC = cat(1,listC{:});
if (numel(listC)>1)
listC=strread(listC{2},'%s','delimiter',' ');
for i = 1:numel(coms)
if strcmp(listC{3},coms{i})
[~, NameF] = dos(['REG QUERY "' out '" /s /f "FriendlyName" /t "REG_SZ"']);
NameF = textscan(NameF,'%s','delimiter','\t');
NameF = cat(1,NameF{:});
com = str2double(coms{i}(4:end));
if com > 9
length = 8;
else
length = 7;
end
devices{i_dev,1} = NameF{2}(27:end-length); %#ok
devices{i_dev,2} = com; %#ok Loop size is always small
i_dev=i_dev+1;
end
end
end
j=j+1;
end
end
end
end
end
end
2つのプライベート属性の変数を追加します.
properties (Access = private)
scan_coms; %
com_num; %
end
適切な位置にドロップダウンボックスとボタンを挿入し、ボタンのコールバック関数を追加します.内容は以下の通りです.
% Button pushed function: Button
function ButtonPushed(app, event)
app.scan_coms = IdentifySerialComs;
%app.DropDown.Items = '';
app.com_num = size(app.scan_coms);
for ii = 1: app.com_num(1)
app.DropDown.Items(ii) = strcat(app.scan_coms(ii, 1),'@COM', num2str(cell2mat(app.scan_coms(ii, 2))));
end
end
これにより、ボタンをクリックする後のリストの内容がシリアルポートに従って変化することが実現する.