[2027] | 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) ) |
---|
[2865] | 53 | error('Not enough arguments are provided to function call'); |
---|
[2027] | 54 | else |
---|
| 55 | % Check that the command is valid |
---|
| 56 | if ( ~strcmp(varargin{1}, 'validate') & ~strcmp(varargin{1}, 'read') & ~strcmp(varargin{1}, 'write') ) |
---|
[2865] | 57 | error('Command "%s" is not valid. Please use "validate", "read", or "write"', varargin{1}) |
---|
[2027] | 58 | end |
---|
| 59 | |
---|
| 60 | % Check that the filename is a character string |
---|
| 61 | if ( ~ischar( varargin{2} ) ) |
---|
[2865] | 62 | error('Filename is not valid') |
---|
[2027] | 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} ) ) |
---|
[2865] | 68 | error('Filename "%s" does not exist', varargin{2}) |
---|
[2027] | 69 | end |
---|
| 70 | end |
---|
| 71 | |
---|
| 72 | % Check that "write" command only has three arguments |
---|
| 73 | if ( (nargin == 2) & strcmp(varargin{1}, 'write') ) |
---|
[2865] | 74 | error('Not enough arguments are provided to "write" function call (need 3, provided 2)'); |
---|
[2027] | 75 | end |
---|
| 76 | |
---|
| 77 | % Check for optional array of nodes |
---|
| 78 | if ( (nargin == 3) ) |
---|
| 79 | if ( ~strcmp(varargin{1}, 'write') ) |
---|
[2865] | 80 | error('Too many arguments are provided to "read" or "validate" function call'); |
---|
[2027] | 81 | end |
---|
| 82 | |
---|
| 83 | if ( ~strcmp(class(varargin{3}),'wl_node') ) |
---|
[2865] | 84 | error('Argument must be an array of "wl_node". Provided "%s"', class(varargin{3})); |
---|
[2027] | 85 | end |
---|
| 86 | end |
---|
| 87 | |
---|
| 88 | % Default for other arguments |
---|
| 89 | if ( (nargin > 3) ) |
---|
[2865] | 90 | error('Too many arguments are provided to function call'); |
---|
[2027] | 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' |
---|
[2865] | 105 | error('TODO: The "write" command for wl_nodesConfig() has not been implemented yet.'); |
---|
[2027] | 106 | otherwise |
---|
[2865] | 107 | error('unknown command ''%s''',cmdStr); |
---|
[2027] | 108 | end |
---|
| 109 | |
---|
| 110 | end |
---|
| 111 | |
---|
| 112 | |
---|
| 113 | function nodeInfo = wl_nodesReadAndValidate( fid ) |
---|
| 114 | |
---|
| 115 | % Parse the input file |
---|
[2856] | 116 | inputParsing = textscan(fid,'%s', 'CollectOutput', 1, 'Delimiter', '\n\r', 'MultipleDelimsAsOne', 1); |
---|
| 117 | inputArrayTemp = inputParsing{:}; |
---|
[2027] | 118 | |
---|
[2856] | 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 | |
---|
[2027] | 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) ) |
---|
[2865] | 145 | error('Node %d has too many columns. Header specifies %d, provided %d', n, headerSize(2), rowSize(2)) |
---|
[2027] | 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') ) |
---|
[2865] | 157 | error('Does not have required fields: "serialNumber", "ID", and "ipAddress" ') |
---|
[2027] | 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 ) ) |
---|
[2865] | 174 | error('IP address of node must have form "w.x.y.z". Provided "%s" ', nodesStruct(n).ipAddress) |
---|
[2027] | 175 | end |
---|
| 176 | |
---|
| 177 | if ( (addrChars(4) == 0) | (addrChars(4) == 255) ) |
---|
[2865] | 178 | error('IP address of node %d cannot end in .0 or .255', n) |
---|
[2027] | 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 ) ) |
---|
[2865] | 191 | error('Serial Number must be unique. Nodes %d and %d have the same serial number %s', n, m, nodesStruct(n).serialNumber) |
---|
[2027] | 192 | end |
---|
| 193 | if ( strcmp( nodesStruct(n).ID, nodesStruct(m).IDUint32 ) ) |
---|
[2865] | 194 | error('Node ID must be unique. Nodes %d and %d have the same node ID %d', n, m, nodesStruct(n).ID) |
---|
[2027] | 195 | end |
---|
| 196 | if (nodesStruct(n).ipAddressUint32 == nodesStruct(m).ipAddressUint32) |
---|
[2865] | 197 | error('IP Address must be unique. Nodes %d and %d have the same IP Address %s', n, m, nodesStruct(n).ipAddress) |
---|
[2027] | 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 | |
---|