This file is indexed.

/usr/share/psychtoolbox-3/PsychHardware/FindSerialPort.m is in psychtoolbox-3-common 3.0.11.20131230.dfsg1-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
function PortNumber = FindSerialPort(PortString, forIOPort, dontFail)
% Syntax: PortNumber = FindSerialPort([PortString][, forIOPort=0][, dontFail=0])
%
% Purpose: Find serial port number/name associated with a particular input string.
%
% If the optional parameter 'PortString' is omitted, the routine will use a
% built-in list of default serial port names to search for. Otherwise it
% will try to find a serial port with a name matching 'PortString'.
%
% If the optional flag 'forIOPort' is zero or left out, the routine will return
% a 'PortNumber' compatible with use of the SerialComm() serial port driver
% for MacOS/X with Matlab. If 'forIOPort' is non-zero, it will return a
% serial port device string in 'PortNumber', suitable for use with the new
% IOPort serial port driver which works on all operating systems and
% runtime environments.
%
% By default, the function will abort with an error message if it doesn't
% find a matching useable port, or if it finds multiple matches, ie. if the
% mapping is ambiguous. If you set the optional flag 'dontFail' to 1, it
% will continue in such cases without any error message: It will simply
% return an empty [] PortNumber if no matching port can be found, or the
% 1st detected matching port, if multiple matches exist.
%
% Please note that support of SerialComm for OS/X is a legacy, only left
% for backwards compatibility! New code should only use the new IOPort
% driver and therefore set the 'forIOPort' flag to 1.
%
% For intersting in-depths comments on the use of this function with PR-650
% style photometers, read the source code of this file.
%

%
% History: 11/21/07   mpr   listed to port
%           1/16/08   mpr   added support for keyspan adapter
%           2/07/09   mk    Add code for use with IOPort instead of SerialComm.
%           4/05/09   mk    Add additional support for 'dontFail' = 1 flag.
%                           Add additional default 'PortString's.
%                           Add proper port detection/enumeration code for
%                           the MS-Windows operating systems. The Win32
%                           enumeration code is directly derived (with
%                           minimal modifications) from sample code donated
%                           by Xiangrui Li. Thanks!
%           6/14/09   mk    Remove redundant special case code for Octave.
%          12/04/12   zlb   Removed usa19* from PortDB since Keyserial1 is
%                           an alias for the first port anyway.
%           3/11/13   mk    Add /dev/ttyACM* devices to Linux enumeration.

% Comments from mpr:
%
% Function is slightly more general than name suggests because name reflects the
% origin of this function for finding the usb to serial port used for driving a
% device like the PR650 spectroradiometer I wrote this for.  NameOfIDString
% defaults to 'usbserial'.  I think any USB to RS-232 adapter that makes
% use of the 2303 chip (which seems to cover all of them on the market
% right now) will have the device name usbserial.  But if I'm wrong, then
% someone else will probably find out before I do.  -- mpr
%
%
% When I started writing this function I knew about PR650init, and I wanted
% to be able to use that function without knowing the port number.  I also
% found that calling that function directly leads to inconsistent
% (generally ineffective) behavior.  For some reason wrapping CMCheckInit
% solves the inconsistent/ineffective problem.  The place where I put the
% call to this function in CMCheckInit is inside a condition testing that
% user is on a machine using OS X, so the error checking here isn't
% necessary.   I also didn't know about IsOSX, IsWin, and IsOS9 when I
% wrote this -- I used the checks in DownloadPsychToolbox as my guide, and
% obviously that function can't make use of PsychToolbox functions...  So
% this could be improved even without making it work for other OSs, but I
% don't have an incentive to make improvements. -- mpr 11/21/07
%
%

if ~nargin || isempty(PortString)	
	% List of serial port devices to look for. These should all be lower case:
    if IsOSX
        PortDB = { lower('keyserial1'), lower('usbmodem'), lower('usbserial') };
    end
    
    if IsLinux
        PortDB = { lower('USB'), lower('ACM') };
    end
    
    if IsWin
        PortDB = { 'com1', 'com2', 'com3', 'com4', 'com5' };
    end
    selectionType = 'default';
else	
	% Make the port string lowercase for easier string comparison later.
	PortDB = {lower(PortString)};
	selectionType = 'requested';
end

if nargin < 2 || isempty(forIOPort)
    forIOPort = 0;
end

if nargin < 3 || isempty(dontFail)
    dontFail = 0;
end

% Init to all-empty return arguments:
PortNumber = [];

if IsWin
    % MS - Windows:
    
    % List of all candidates COM1 to COM256
    ports = strtrim(cellstr(num2str((1:256)', 'COM%i')));
    
    % For OS/X and Linux, it is easy to get all existing ports, while for
    % Windows, there seems no way to get the list. So we try all possible ports
    % one by one. Fortunately, it won't take much time if a port doesn't exist.
    
    % Start with empty cell arrays:
    availPorts={}; busyPorts={};
    
    % Disable output of IOPort during probe-run:
    oldverbosity=IOPort('Verbosity', 0);
    
    % Test each port for existence:
    for i=1:length(ports)
        
        % Try to open:
        [h, errmsg] = IOPort('OpenSerialPort', ports{i});

        % Open succeeded?
        if h>=0
            % Yes, this is an existing and available port. Close it again:
            IOPort('Close', h);
            
            % Add to list of available ports:
            availPorts{end+1} = ports{i}; %#ok<AGROW>
        elseif isempty(strfind(errmsg, 'ENOENT'))
            % Failed to open port, because it is busy, but port exists. Add
            % to list of busy ports:
            busyPorts{end+1} = ports{i}; %#ok<AGROW>
        end
        
        % Scan next COM port...
    end

    % Restore output of IOPort after probe-run:
    IOPort('Verbosity', oldverbosity);

    % Concatenate busy and ready ports into one list:
    TheTemp = [ availPorts ; busyPorts ];
    for i=1:length(TheTemp)
        ThePortDevices(i).name = char(TheTemp(i)); %#ok<AGROW>
    end

    % Done with enumeration on Windows.
else
    % Either Linux, OS/X or (hopefully) some other compatible Posix OS:

    % Get a list of any serial devices attached to the computer.
    if IsOSX
        % OS/X: Enumerate cu* devices - they correspond to serial ports:
        ThePortDevices = dir('/dev/cu*');
    else
        % Linux or some other Posix OS. Use search patterns for Linux, both
        % for USB serial converters/adaptors, and standard native serial ports:
        ThePortDevices = dir('/dev/ttyUSB*');
        ThePortDevices = [ dir('/dev/ttyACM*'); ThePortDevices];
        ThePortDevices = [ dir('/dev/ttyS*'); ThePortDevices];
    end
end

% Check to see if any serial devices were found.
if isempty(ThePortDevices) && (dontFail == 0)
	error('\n%s\n%s\n', ...
		'No serial devices were found.  Make sure the serial device is plugged', ...
		'in and the drivers installed.');
end

% For each serial type in the PortDB cell array, see if any attached serial
% devices match.
FoundIndices = [];
for i = 1:length(PortDB)
	for j = 1:length(ThePortDevices)
		if ~isempty(strfind(lower(ThePortDevices(j).name), PortDB{i}))
			FoundIndices(end+1) = j; %#ok<AGROW>
		end
	end
end
numPortsFound = length(FoundIndices);

if dontFail == 0
    if numPortsFound == 0 % No port matches.
        error('\n%s%s%s\n%s\n%s\n%s\n%s', ...
            'No ports found that match following ', selectionType, ' types(s)', ...
            makeDesiredPortTypesString(PortDB), ...
            'This is a list of the port(s) found:', ...
            makeFoundDevicesString(ThePortDevices), ...
            'Is your RS-232 adapter connected to your computer?');
    elseif numPortsFound > 1 % Too many port matches.
        error('\n%s%s%s\n%s\n\n%s\n%s', ...
            'More than one port name matched the ', selectionType, ' type(s)', ...
            makeDesiredPortTypesString(PortDB), ...
            'A more specific port type is required.', ...
            'This is a list of the port(s) found:', ...
            makeFoundDevicesString(ThePortDevices)); %#ok<SPERR>
    end
end

% Bit of a hack. If we get here and have more than 1 matching devices, we
% simply discard all but the 1st one:
if numPortsFound > 0
    % Cap to 1st entry:
    FoundIndices = FoundIndices(1);
else
    % No ports found, but not allowed to fail. We simply return, so
    % PortNumber will be an empty return argument:
    return;
end

if ~forIOPort
    % Old-Style, using SerialComm:
    % Convert the port name into a port number.

    if ~IsOSX
        error('This routine is not supported for use with SerialComm under other systems than Mac OS/X. Use with forIOPort=1 flag instead!');
    end

    if IsOctave
        error('This routine is not supported for use with SerialComm under Octave. Use with forIOPort=1 flag instead!');
    end

    if numPortsFound > 0
        portString = sprintf('/dev/%s', ThePortDevices(FoundIndices(1)).name);
        PortNumber = SerialComm('name2number', portString);
    end
else
    % New-Style: Path name of port itself for use with IOPort:
    if ~IsWin
        % Unix systems: Absolute device file path needed:
        PortNumber = sprintf('/dev/%s', ThePortDevices(FoundIndices).name);
    else
        % Windows: Pass "as is":
        PortNumber = upper(sprintf('%s', ThePortDevices(FoundIndices).name));
    end
end

return;

function s = makeDesiredPortTypesString(PortDB)
s = [];
for i = 1:length(PortDB)
	s = [char(s) sprintf('\t\t%s\n', PortDB{i})]; %#ok<AGROW>
end

function s = makeFoundDevicesString(ThePortDevices)
s = [];

if ~IsWin
    % Unices...
    if IsOSX
        prefix = 'cu.';
    else
        prefix = 'tty';
    end

    prefix = [prefix '%s'];

    for k = 1:length(ThePortDevices)
        ThisDevice = sscanf(ThePortDevices(k).name,prefix);
        s = [char(s) sprintf('\t\t%s\n',ThisDevice)]; %#ok<AGROW>
    end
else
    % MS-Windows:
    for k = 1:length(ThePortDevices)
        ThisDevice = sscanf(ThePortDevices(k).name, '%s');
        s = [char(s) sprintf('\t\t%s\n', ThisDevice)]; %#ok<AGROW>
    end    
end