1 | %============================================================================== |
---|
2 | % Function: wl_nodesConfig |
---|
3 | % |
---|
4 | % Inputs: |
---|
5 | % 'Command' - Command for the script to perform |
---|
6 | % 'Filename' - File to either read, write, or validate |
---|
7 | % NodeArray - Optional argument when trying to write the nodes configuration |
---|
8 | % |
---|
9 | % Commands: |
---|
10 | % 'validate' - Will validate the input file and return 1 if valid or generate an error message |
---|
11 | % 'read' - Will read the input file and return the structure of nodes |
---|
12 | % 'write' - Will take the array of nodes and write to the specified file and return 1 if successful |
---|
13 | % |
---|
14 | % File Format: |
---|
15 | % serialNumber,ID,ipAddress,(opt 1),(opt 2), ...,(opt N) |
---|
16 | % |
---|
17 | % NOTE: The ',' and '\t' are reserved characters and will be interpreted as the next field; |
---|
18 | % All spaces, ' ', are valid and are not removed from the field |
---|
19 | % If you add in a optional field, then you have to put the correct number of delimiters, ie ',', |
---|
20 | % to indicate fields are not used |
---|
21 | % There should be no spaces in the field names in the header row |
---|
22 | % |
---|
23 | % Example: |
---|
24 | % serialNumber, ID, ipAddress, name, opt_1 |
---|
25 | % W3-a-00006, 0, 10.0.0.0, Node 0, primary |
---|
26 | % W3-a-00007, 0, 10.0.0.1, |
---|
27 | % W3-a-00008, 1, 10.0.0.200, Node X |
---|
28 | % |
---|
29 | % This is ok due to the fact that the opt_1 field is used in a row that has the correct number of delimiters |
---|
30 | % |
---|
31 | % In this example, the opt_1 field is not used and the node names are "Node 0" and "primary": |
---|
32 | % |
---|
33 | % serialNumber, ID, ipAddress, name, opt_1 |
---|
34 | % W3-a-00006, 0, 10.0.0.0, Node 0 |
---|
35 | % W3-a-00007, 0, 10.0.0.1, primary <-- Issue: Not enough delimiters to use opt_1 field |
---|
36 | % |
---|
37 | % To use the opt_1 field, you would need to add another delimiter: |
---|
38 | % |
---|
39 | % serialNumber, ID, ipAddress, name, opt_1 |
---|
40 | % W3-a-00006, 0, 10.0.0.0, Node 0 |
---|
41 | % W3-a-00007, 0, 10.0.0.1,, primary |
---|
42 | % |
---|
43 | % in order to use the opt_1 field and leave a blank name for the node in the second row. |
---|
44 | % |
---|
45 | % |
---|
46 | %============================================================================== |
---|
47 | |
---|
48 | function nodesInfo = wl_nodesConfig(varargin) |
---|
49 | |
---|
50 | % Validate input parameters |
---|
51 | |
---|
52 | if ( (nargin == 0) | (nargin == 1) ) |
---|
53 | error('Not enough arguments are provided to function call'); |
---|
54 | else |
---|
55 | % Check that the command is valid |
---|
56 | if ( ~strcmp(varargin{1}, 'validate') & ~strcmp(varargin{1}, 'read') & ~strcmp(varargin{1}, 'write') ) |
---|
57 | error('Command "%s" is not valid. Please use "validate", "read", or "write"', varargin{1}) |
---|
58 | end |
---|
59 | |
---|
60 | % Check that the filename is a character string |
---|
61 | if ( ~ischar( varargin{2} ) ) |
---|
62 | error('Filename is not valid') |
---|
63 | end |
---|
64 | |
---|
65 | % Check the filename exists if the command is "read" or "validate" |
---|
66 | if ( strcmp(varargin{1}, 'validate') | strcmp(varargin{1}, 'read') ) |
---|
67 | if ( ~exist( varargin{2} ) ) |
---|
68 | error('Filename "%s" does not exist', varargin{2}) |
---|
69 | end |
---|
70 | end |
---|
71 | |
---|
72 | % Check that "write" command only has three arguments |
---|
73 | if ( (nargin == 2) & strcmp(varargin{1}, 'write') ) |
---|
74 | error('Not enough arguments are provided to "write" function call (need 3, provided 2)'); |
---|
75 | end |
---|
76 | |
---|
77 | % Check for optional array of nodes |
---|
78 | if ( (nargin == 3) ) |
---|
79 | if ( ~strcmp(varargin{1}, 'write') ) |
---|
80 | error('Too many arguments are provided to "read" or "validate" function call'); |
---|
81 | end |
---|
82 | |
---|
83 | if ( ~strcmp(class(varargin{3}),'wl_node') ) |
---|
84 | error('Argument must be an array of "wl_node". Provided "%s"', class(varargin{3})); |
---|
85 | end |
---|
86 | end |
---|
87 | |
---|
88 | % Default for other arguments |
---|
89 | if ( (nargin > 3) ) |
---|
90 | error('Too many arguments are provided to function call'); |
---|
91 | end |
---|
92 | end |
---|
93 | |
---|
94 | % Process the command |
---|
95 | |
---|
96 | fileID = fopen(varargin{2}); |
---|
97 | |
---|
98 | switch( varargin{1} ) |
---|
99 | case 'validate' |
---|
100 | wl_nodesReadAndValidate( fileID ); |
---|
101 | nodesInfo = 1; |
---|
102 | case 'read' |
---|
103 | nodesInfo = wl_nodesReadAndValidate( fileID ); |
---|
104 | case 'write' |
---|
105 | error('TODO: The "write" command for wl_nodesConfig() has not been implemented yet.'); |
---|
106 | otherwise |
---|
107 | error('unknown command ''%s''',cmdStr); |
---|
108 | end |
---|
109 | |
---|
110 | end |
---|
111 | |
---|
112 | |
---|
113 | function nodeInfo = wl_nodesReadAndValidate( fid ) |
---|
114 | |
---|
115 | % Parse the input file |
---|
116 | inputParsing = textscan(fid,'%s', 'CollectOutput', 1, 'Delimiter', '\n\r', 'MultipleDelimsAsOne', 1); |
---|
117 | inputArrayTemp = inputParsing{:}; |
---|
118 | |
---|
119 | % Remove any commented lines |
---|
120 | input_index = 0; |
---|
121 | inputArray = cell(1, 1); |
---|
122 | for n = 1:size(inputArrayTemp) |
---|
123 | if ( isempty( regexp(inputArrayTemp{n}, '#', 'start' ) ) ) |
---|
124 | input_index = input_index + 1; |
---|
125 | inputArray{input_index, 1} = inputArrayTemp{n}; |
---|
126 | end |
---|
127 | end |
---|
128 | |
---|
129 | % Convert cells to character arrays and break apart on ',' or '\t' |
---|
130 | removeTabs = regexprep( inputArray, '[\t]', '' ); |
---|
131 | fieldsArray = regexp( removeTabs, '[,]', 'split' ); |
---|
132 | |
---|
133 | % Remove spaces from the header row |
---|
134 | headerRow = regexprep( fieldsArray{1}, '[ ]', '' ); |
---|
135 | |
---|
136 | % Determine size of the matrices |
---|
137 | headerSize = size(headerRow); % Number of Columns |
---|
138 | fieldSize = size(fieldsArray); % Number of Rows (Nodes) |
---|
139 | |
---|
140 | % Pad columns in cell array |
---|
141 | % Create structure from cell array |
---|
142 | for n = 1:(fieldSize(1) - 1) |
---|
143 | rowSize = size( fieldsArray{n+1} ); |
---|
144 | if ( rowSize(2) > headerSize(2) ) |
---|
145 | error('Node %d has too many columns. Header specifies %d, provided %d', n, headerSize(2), rowSize(2)) |
---|
146 | end |
---|
147 | if ( rowSize(2) < headerSize(2) ) |
---|
148 | for m = (rowSize(2) + 1):headerSize(2) |
---|
149 | fieldsArray{n+1}{m} = ''; |
---|
150 | end |
---|
151 | end |
---|
152 | nodesStruct(n) = cell2struct( fieldsArray{n + 1}, headerRow, 2); |
---|
153 | end |
---|
154 | |
---|
155 | % Determine if array has correct required fields |
---|
156 | if ( ~isfield(nodesStruct, 'serialNumber') | ~isfield(nodesStruct, 'ID') | ~isfield(nodesStruct, 'ipAddress') ) |
---|
157 | error('Does not have required fields: "serialNumber", "ID", and "ipAddress" ') |
---|
158 | end |
---|
159 | |
---|
160 | % Convert to unit32 for serialNumber, ID, and ipAddress |
---|
161 | nodeSize = size(nodesStruct); |
---|
162 | |
---|
163 | for n = 1:(nodeSize(2)) |
---|
164 | inputString = [nodesStruct(n).serialNumber,0]; %null-terminate |
---|
165 | padLength = mod(-length(inputString),4); |
---|
166 | inputByte = [uint8(inputString),zeros(1,padLength)]; |
---|
167 | nodesStruct(n).serialNumberUint32 = typecast(inputByte,'uint32'); |
---|
168 | |
---|
169 | nodesStruct(n).IDUint32 = uint32( str2num( nodesStruct(n).ID ) ); |
---|
170 | |
---|
171 | addrChars = sscanf(nodesStruct(n).ipAddress,'%d.%d.%d.%d'); |
---|
172 | |
---|
173 | if ( ~eq( length( addrChars ), 4 ) ) |
---|
174 | error('IP address of node must have form "w.x.y.z". Provided "%s" ', nodesStruct(n).ipAddress) |
---|
175 | end |
---|
176 | |
---|
177 | if ( (addrChars(4) == 0) | (addrChars(4) == 255) ) |
---|
178 | error('IP address of node %d cannot end in .0 or .255', n) |
---|
179 | end |
---|
180 | nodesStruct(n).ipAddressUint32 = uint32( 2^0 * addrChars(4) + 2^8 * addrChars(3) + 2^16 * addrChars(2) + 2^24 * addrChars(1) ); |
---|
181 | end |
---|
182 | |
---|
183 | % Determine if each input row is valid |
---|
184 | % - All serial numbers must be unique |
---|
185 | % - All UIDs must be unique |
---|
186 | % - All IP Addresses must be unique |
---|
187 | |
---|
188 | for n = 1:(nodeSize(2) - 1) |
---|
189 | for m = n+1:(nodeSize(2)) |
---|
190 | if ( strcmp( nodesStruct(n).serialNumber, nodesStruct(m).serialNumber ) ) |
---|
191 | error('Serial Number must be unique. Nodes %d and %d have the same serial number %s', n, m, nodesStruct(n).serialNumber) |
---|
192 | end |
---|
193 | if ( strcmp( nodesStruct(n).ID, nodesStruct(m).IDUint32 ) ) |
---|
194 | error('Node ID must be unique. Nodes %d and %d have the same node ID %d', n, m, nodesStruct(n).ID) |
---|
195 | end |
---|
196 | if (nodesStruct(n).ipAddressUint32 == nodesStruct(m).ipAddressUint32) |
---|
197 | error('IP Address must be unique. Nodes %d and %d have the same IP Address %s', n, m, nodesStruct(n).ipAddress) |
---|
198 | end |
---|
199 | end |
---|
200 | end |
---|
201 | |
---|
202 | % Uncomment Section to Display final node contents |
---|
203 | % for n = 1:(nodeSize(2)) |
---|
204 | % disp(nodesStruct(n)) |
---|
205 | % end |
---|
206 | |
---|
207 | nodeInfo = nodesStruct; |
---|
208 | end |
---|
209 | |
---|
210 | |
---|
211 | |
---|
212 | |
---|
213 | |
---|
214 | |
---|