source: ResearchApps/PHY/WARPLAB/WARPLab7/M_Code_Reference/classes/wl_node.m

Last change on this file was 4928, checked in by welsh, 8 years ago

Increased trigger output delay for all outputs to conform to trigger manager v1.07.g.

File size: 62.9 KB
RevLine 
[4330]1%-------------------------------------------------------------------------
[4332]2% WARPLab Framework
[4330]3%
4% Copyright 2013, Mango Communications. All rights reserved.
5%           Distributed under the WARP license  (http://warpproject.org/license)
6%
7% Chris Hunter (chunter [at] mangocomm.com)
8% Patrick Murphy (murphpo [at] mangocomm.com)
9% Erik Welsh (welsh [at] mangocomm.com)
10%-------------------------------------------------------------------------
11
[1915]12classdef wl_node < handle_light
[4330]13    % The WARPLab node class represents one node in a WARPLab network
[1915]14    % wl_node is the primary interface for interacting with WARPLab nodes.
15    % This class provides methods for sending commands, exchanging samples
16    % and checking the status of WARPLab nodes.
17    % wl_node wraps the six underlying components that comprise a WARPLab
18    % node implementation: node, baseband, interface, transport, trigger
19    % setup and user extensions.
20   
21    properties (SetAccess = protected)
[4330]22        ID;                    % Unique identification for this node
23        description;           % String description of this node (auto-generated)
24        serialNumber;          % Node's serial number, read from EEPROM on hardware
25        eth_MAC_addr;          % Node's MAC address (for ETH_A on WARP v3)
26        fpgaDNA;               % Node's FPGA's unique identification (on select hardware)
27        hwVer;                 % WARP hardware version of this node
28        wlVer_major;           % WARPLab version running on this node
[1915]29        wlVer_minor;
30        wlVer_revision;
[4330]31        num_interfacesGroups;  % # of interface groups attached to node
32        num_interfaces;        % Vector of length num_interfaceGroups with
33                               %     # of interfaces per group
34        interfaceGroups;       % Node's interface group object(s)
35        interfaceIDs;          % Vector of interface identifiers
36        baseband;              % Node's baseband object
37        trigger_manager;       % Node's trigger configuration object
38        transport;             % Node's transport object
39        user;                  % Node's user extension object
[1915]40    end
[4330]41   
[1915]42    properties (SetAccess = public)
[4332]43        name;                  % User specified name for node; user scripts supply this
[1915]44    end
[4330]45   
[1948]46    properties(Hidden = true,Constant = true)
[4330]47        % Command Groups - Most Significant Byte of Command ID
[4332]48        GRPID_NODE                     = hex2dec('00');
49        GRPID_TRANS                    = hex2dec('10');
50        GRPID_IFC                      = hex2dec('20');
51        GRPID_BB                       = hex2dec('30');
52        GRPID_TRIGMNGR                 = hex2dec('40');
53        GRPID_USER                     = hex2dec('50');
[1948]54    end
[4330]55   
[1948]56    properties(Hidden = true,Constant = true)
[4330]57        % These constants define specific command IDs used by this object.
58        % Their C counterparts are found in wl_node.h
59        GRP                            = 'node';
60        CMD_INITIALIZE                 = 1;                % 0x000001
61        CMD_INFO                       = 2;                % 0x000002
62        CMD_IDENTIFY                   = 3;                % 0x000003
63        CMD_TEMPERATURE                = 4;                % 0x000004
[4784]64        CMD_NODE_CONFIG_SETUP          = 5;                % 0x000005
[4330]65        CMD_NODE_CONFIG_RESET          = 6;                % 0x000006
[4784]66       
67        CMD_MEM_RW                     = 16;               % 0x000010
[1948]68    end
[4330]69   
[1915]70    methods
[2027]71        function obj = wl_node()
[4332]72            % The constructor is intentionally blank for wl_node objects.
73            % Instead, the objects are configured via the separate applyConfiguration method.
[2027]74        end
75       
[4332]76       
[2027]77        function applyConfiguration(objVec, IDVec)
[4332]78            % Set all the node object parameters
79       
80            % Apply Configuration only operates on one object at a time
81            if ((length(objVec) > 1) || (length(IDVec) > 1)) 
[2865]82                error('applyConfiguration only operates on a single object with a single ID.  Provided parameters with lengths: %d and %d', length(objVec), length(IDVec) ); 
[2027]83            end
[1915]84
[2027]85            % Apply configuration will finish setting properties for a specific hardware node
86            obj    = objVec(1);
87            currID = IDVec(1);
88           
89            % currID can be either a structure containing node information or a number
[4332]90            switch (class(currID))
[2027]91                case 'struct'
92                    if ( ~strcmp( currID.serialNumber, '' ) )
93                        obj.serialNumber = sscanf( currID.serialNumber, 'W3-a-%d' );  % Only store the last 5 digits ( "W3-a-" is not stored )
94                    else
[2865]95                        error('Unknown argument.  Serial Number provided is blank');
[2027]96                    end
97
98                    if ( ~strcmp( currID.ID, '' ) )
99                        obj.ID           = sscanf( currID.ID, '%d');
100                    else
[2865]101                        error('Unknown argument.  Node ID provided is blank');
[2027]102                    end
[1915]103               
[2027]104                    if ( ~strcmp( currID.name, '' ) ) % Name is an optional parameter in the structure
105                        obj.name         = currID.name;
106                    end
107
108                case 'double'
109                    obj.ID = currID;                  % The node ID must match the DIP switch on the WARP board
110
111                otherwise
[2865]112                    error('Unknown argument.  IDVec is of type "%s", need "struct", or "double"', class(currID));
[2027]113            end       
114           
115
116            % Get ini configuration file
117            configFile = which('wl_config.ini');
118            if(isempty(configFile))
[2865]119                error('cannot find wl_config.ini. please run wl_setup.m'); 
[2027]120            end
[2001]121               
[4332]122            % Use Ethernet/UDP transport for all wl_nodes. The specific type of transport
123            % is specified in the user's wl_config.ini file that is created via wl_setup.m
124            readKeys      = {'network','','transport',''};
[2027]125            transportType = inifile(configFile,'read',readKeys);
126            transportType = transportType{1};
[2001]127
[2027]128            switch(transportType)
129                case 'java'
130                    obj.transport = wl_transport_eth_udp_java;
[2149]131                case 'wl_mex_udp'
[2084]132                    obj.transport = wl_transport_eth_udp_mex;
[2027]133            end
[2001]134               
[2084]135            if(isempty(obj.trigger_manager))
136                obj.wl_setTriggerManager('wl_trigger_manager_proc');
137            end
138
[2027]139            readKeys = {'network','','host_address',''};
140            IP = inifile(configFile,'read',readKeys);
141            IP = IP{1};
142            IP = sscanf(IP,'%d.%d.%d.%d');
[1915]143
[2027]144            readKeys = {'network','','host_ID',''};
145            hostID = inifile(configFile,'read',readKeys);
146            hostID = hostID{1};
147            hostID = sscanf(hostID,'%d');
[1915]148               
[2027]149            readKeys = {'network','','unicast_starting_port',''};
150            unicast_starting_port = inifile(configFile,'read',readKeys);
151            unicast_starting_port = unicast_starting_port{1};
152            unicast_starting_port = sscanf(unicast_starting_port,'%d');
[1915]153               
[2027]154            % Configure transport with settings associated with provided ID
155            obj.transport.hdr.srcID  = hostID;
156            obj.transport.hdr.destID = obj.ID;
157
158            % Determine IP address based on the input parameter
159            switch( class(currID) ) 
160                case 'struct'
161                    if ( ~strcmp( currID.ipAddress, '' ) )
[4416]162                        obj.transport.setAddress(currID.ipAddress);
[2027]163                    else
[2865]164                        error('Unknown argument.  IP Address provided is blank');
[2027]165                    end
166                case 'double'
[4416]167                    obj.transport.setAddress(sprintf('%d.%d.%d.%d', IP(1), IP(2), IP(3), (obj.ID + 1)));
[2027]168            end       
169                           
[4674]170            obj.transport.setPort(unicast_starting_port);
[1915]171               
[2027]172            obj.transport.open();
173            obj.transport.hdr.srcID  = hostID;   % ????? Redundant ????? - TBD
174            obj.transport.hdr.destID = obj.ID;   % ????? Redundant ????? - TBD
[1964]175
[2027]176            obj.wl_nodeCmd('initialize');
177            obj.wl_transportCmd('ping');              % Confirm the WARP node is online
178            obj.wl_transportCmd('payload_size_test'); % Perform a test to figure out max payload size
179           
180            obj.interfaceIDs = [];
[2009]181
[2027]182            if(isempty(obj.baseband))
[4332]183                % Instantiate baseband object
[2027]184                obj.wl_setBaseband('wl_baseband_buffers');
185            end
[2009]186               
[4332]187            % Read details from the hardware (serial number, etc) and save to local properties
[2027]188            obj.wl_nodeCmd('get_hardware_info');
[1959]189               
[2027]190            % Instantiate interfaces group.
191            if(isempty(obj.interfaceGroups))
192                obj.interfaceGroups{1} = wl_interface_group_X245(1:obj.num_interfaces, 'w3');
193            end
[1959]194
[2027]195            % Extract the interface IDs from the interface group. These IDs
196            % will be supplied to user scripts to identify individual
197            % interfaces for interface and baseband commands
198            for ifcGroupIndex = 1:length(obj.interfaceGroups)
199                obj.interfaceIDs = [obj.interfaceIDs, obj.interfaceGroups{1}.ID(:).'];
200            end
[2009]201               
[2027]202            % Populate the description property with a human-readable
203            % description of the node
204            obj.description = sprintf('WARP v%d Node - ID %d', obj.hwVer, obj.ID);
[1915]205       end
[2027]206       
[4332]207       
[2002]208       function wl_setUserExtension(obj,module)
[4332]209           % Sets the User Extension module to a user-provided object or
210           % string of that object's class name.
211           %
[2002]212           makeComparison = 1;
[4332]213           
214           if(module == 0)                                 % No module attached
[2002]215              module = 'double(0)';
216              makeComparison = 0;
[4332]217           elseif(~ischar(module))                         % Input is an actual instance of an object
[2002]218              module = class(module);               
[1948]219           end
220           
[2002]221           if(makeComparison && ~any(strcmp(superclasses(module),'wl_user_ext')))
[2865]222              error('Module is not a wl_user_ext type');
[2002]223           end
224           
[1948]225           for n = 1:length(obj)
[2002]226              obj(n).user = eval(module); 
[1948]227           end
[2002]228       end 
229       
[4332]230       
[2002]231       function wl_setBaseband(obj,module)
[4332]232           % Sets the Baseband module to a user-provided object or
233           % string of that object's class name.
234           %
[2002]235           makeComparison = 1;
[4332]236
237           if(module == 0)                                 % No module attached
[2002]238              module = 'double(0)';
239              makeComparison = 0;
[4332]240           elseif(~ischar(module))                         % Input is an actual instance of an object
[2002]241              module = class(module);               
242           end
[1948]243           
[2002]244           if(makeComparison && ~any(strcmp(superclasses(module),'wl_baseband')))
[2865]245              error('Module is not a wl_baseband type');
[2002]246           end
247           
248           for n = 1:length(obj)
249              obj(n).baseband = eval(module); 
250           end
[1948]251       end 
252       
[4332]253       
[2002]254       function wl_setTriggerManager(obj,module)
[4332]255           % Sets the Trigger Manager module to a user-provided object or
256           % string of that object's class name.
257           %
[2002]258           makeComparison = 1;
[4332]259           
260           if(module == 0)                                 % No module attached
[2002]261              module = 'double(0)';
262              makeComparison = 0;
[4332]263           elseif(~ischar(module))                         % Input is an actual instance of an object
[2002]264              module = class(module);               
265           end
266           
267           if(makeComparison && ~any(strcmp(superclasses(module),'wl_trigger_manager')))
[2865]268              error('Module is not a wl_trigger_manager type');
[2002]269           end
270           
271           for n = 1:length(obj)
272              obj(n).trigger_manager = eval(module); 
273           end
274       end 
275       
[4332]276       
[1951]277       function out = wl_basebandCmd(obj, varargin)
[4332]278            % Sends commands to the baseband object.
[1915]279            % This method is safe to call with multiple wl_node objects as
280            % its first argument. For example, let node0 and node1 be
281            % wl_node objects:
282            %
[1951]283            %   wl_basebandCmd(node0, args )
284            %   wl_basebandCmd([node0, node1], args )
285            %   node0.wl_basebandCmd( args )
[1915]286            %
287            % are all valid ways to call this method. Note, when calling
288            % this method for multiple node objects, the interpretation of
289            % other vectored arguments is left up to the underlying
290            % components.
[4332]291            %
292            nodes    = obj;
[1915]293            numNodes = numel(nodes);
294           
295            for n = numNodes:-1:1
296                currNode = nodes(n);
[2001]297                if(any(strcmp(superclasses(currNode.baseband),'wl_baseband')))
298                    out(n) = currNode.baseband.procCmd(n, currNode, varargin{:});
299                else
[2865]300                    error('Node %d does not have an attached baseband module',currNode.ID);
[2001]301                end
[1915]302            end
[4332]303
304            if((length(out) == 1) && iscell(out))
305               out = out{1};                               % Strip away the cell if it's just a single element.
[1915]306            end
307        end
308       
[4332]309       
[1915]310        function out = wl_nodeCmd(obj, varargin)
311            %Sends commands to the node object.
312            % This method is safe to call with multiple wl_node objects as
313            % its first argument. For example, let node0 and node1 be
314            % wl_node objects:
315            %
316            %   wl_nodeCmd(node0, args )
317            %   wl_nodeCmd([node0, node1], args )
318            %   node0.wl_nodeCmd( args )
319            %
320            % are all valid ways to call this method. Note, when calling
321            % this method for multiple node objects, the interpretation of
322            % other vectored arguments is left up to the underlying
323            % components.
[4332]324            %
325            nodes    = obj;
[1915]326            numNodes = numel(nodes);
327           
328            for n = numNodes:-1:1
329                currNode = nodes(n);
330                out(n) = currNode.procCmd(n, currNode, varargin{:});
331            end
332           
[4332]333            if((length(out) == 1) && iscell(out))
334               out = out{1};                               % Strip away the cell if it's just a single element.
335            end           
[1915]336        end
337       
[4332]338       
[1951]339        function out = wl_transportCmd(obj, varargin)
[4332]340            % Sends commands to the transport object.
[1915]341            % This method is safe to call with multiple wl_node objects as
342            % its first argument. For example, let node0 and node1 be
343            % wl_node objects:
344            %
[1951]345            %   wl_transportCmd(node0, args )
346            %   wl_transportCmd([node0, node1], args )
347            %   node0.wl_transportCmd( args )
[1915]348            %
349            % are all valid ways to call this method. Note, when calling
350            % this method for multiple node objects, the interpretation of
351            % other vectored arguments is left up to the underlying
352            % components.
[4332]353            %
354            nodes    = obj;
[1915]355            numNodes = numel(nodes);
356           
357            for n = numNodes:-1:1
358                currNode = nodes(n);
[2001]359                if(any(strcmp(superclasses(currNode.transport),'wl_transport')))
360                    out(n) = currNode.transport.procCmd(n, currNode, varargin{:});
361                else
[2865]362                    error('Node %d does not have an attached transport module',currNode.ID);
[2001]363                end
364               
[1915]365            end
[4332]366           
367            if((length(out) == 1) && iscell(out))
368               out = out{1};                               % Strip away the cell if it's just a single element.
[1948]369            end           
370        end
371       
[4332]372       
[2919]373        function out = wl_userExtCmd(obj, varargin)
[4332]374            % Sends commands to the user extension object.
[1948]375            % This method is safe to call with multiple wl_node objects as
376            % its first argument. For example, let node0 and node1 be
377            % wl_node objects:
378            %
379            %   wl_userExtCmd(node0, args )
380            %   wl_userExtCmd([node0, node1], args )
381            %   node0.wl_userExtCmd( args )
382            %
383            % are all valid ways to call this method. Note, when calling
384            % this method for multiple node objects, the interpretation of
385            % other vectored arguments is left up to the underlying
386            % components.
[4332]387            %
388            nodes    = obj;
[1948]389            numNodes = numel(nodes);
[1915]390           
[4332]391            for n = numNodes:-1:1
392                currNode = nodes(n);
393                if(any(strcmp(superclasses(currNode.user),'wl_user_ext')))
394                     out(n) = {currNode.user.procCmd(n, currNode, varargin{:})};
395                else
396                    error('Node %d does not have an attached user extension module',currNode.ID);
[1948]397                end
[4332]398            end
[1948]399           
[4332]400            if((length(out) == 1) && iscell(out))
401               out = out{1};                               % Strip away the cell if it's just a single element.
402            end
[1915]403        end
404       
[4332]405       
[1951]406        function out = wl_triggerManagerCmd(obj, varargin)
[4332]407            % Sends commands to the trigger manager object.
[1915]408            % This method is safe to call with multiple wl_node objects as
409            % its first argument. For example, let node0 and node1 be
410            % wl_node objects:
411            %
[1972]412            %   wl_triggerManagerCmd(node0, args )
413            %   wl_triggerManagerCmd([node0, node1], args )
414            %   node0.wl_triggerManagerCmd( args )
[1915]415            %
416            % are all valid ways to call this method. Note, when calling
417            % this method for multiple node objects, the interpretation of
418            % other vectored arguments is left up to the underlying
419            % components.
[4332]420            %
421            nodes    = obj;
[1915]422            numNodes = numel(nodes);
423           
424            for n = numNodes:-1:1
425                currNode = nodes(n);
[2001]426                if(any(strcmp(superclasses(currNode.trigger_manager),'wl_trigger_manager')))
427                    out(n) = currNode.trigger_manager.procCmd(n, currNode, varargin{:});
428                else
[2865]429                    error('Node %d does not have an attached trigger manager module',currNode.ID);
[2001]430                end
[1915]431            end
[4332]432           
433            if((length(out) == 1) && iscell(out))
434               out = out{1};                               % Strip away the cell if it's just a single element.
[1915]435            end           
436        end
437       
438       
[1951]439        function out = wl_interfaceCmd(obj, rfSel, varargin)
[4332]440            % Sends commands to the interface object.
[1915]441            % This method must be called with RF selection masks as an
442            % argument. These masks are returned by the wl_getInterfaceIDs
443            % method. The RFMASKS argument must be a scaler or vector of
444            % bit-OR'd interface IDs from a single interface group
445            %
446            % This method is safe to call with multiple wl_node objects as
447            % its first argument. For example, let node0 and node1 be
448            % wl_node objects:
449            %
[1951]450            %   wl_interfaceCmd(node0, RFMASKS, args )
451            %   wl_interfaceCmd([node0, node1], RFMASKS, args )
[1915]452            %   node0.wl_trigConfCmd(RFMASKS, args )
453            %
454            % are all valid ways to call this method. Note, when calling
455            % this method for multiple node objects, the interpretation of
456            % other vectored arguments is left up to the underlying
457            % components.
[4332]458            %
459            nodes    = obj;
[1915]460            numNodes = numel(nodes);
461           
[1959]462            ifcIndex = 1;
463            for nodeIndex = numNodes:-1:1
[2001]464                currNode = nodes(nodeIndex); 
[4687]465                if(any(strcmp(superclasses(currNode.interfaceGroups{ifcIndex}), 'wl_interface_group')))
[2001]466                    out(nodeIndex) = currNode.interfaceGroups{ifcIndex}.procCmd(nodeIndex, currNode, rfSel, varargin{:});
467                else
[2865]468                    error('Node %d does not have an attached interface group module',currNode.ID);
[2001]469                end
[1959]470            end   
[4687]471
[4330]472            if((length(out) == 1) && iscell(out))
[4332]473               out = out{1};                               % Strip away the cell if it's just a single element.
[1915]474            end
475        end
476       
[4332]477       
[1915]478        function varargout = wl_getInterfaceIDs(obj)
[4681]479            % Returns the interfaces IDs that can be used as inputs to all interface commands, some
480            % baseband commands and possibly some user extension commands.
[1972]481            %
[4681]482            % The interface IDs are returned in a structure that contains fields for individual
483            % interfaces and combinations of interfaces.  When a node only supports 2 interfaces,
484            % the fields for RFC and RFD (ie the fields specific to a 4 interface node) are not
485            % present in the structure.
[4327]486            %
[4681]487            % The fields in the structure are:
488            %     - Scalar fields:
489            %       - RF_A
490            %       - RF_B
491            %       - RF_C
492            %       - RF_D
493            %       - RF_ON_BOARD      NOTE: RF_ON_BOARD      = RF_A + RF_B
494            %       - RF_FMC           NOTE: RF_FMC           = RF_C + RF_D
495            %       - RF_ALL           NOTE: 2RF:  RF_ALL     = RF_A + RF_B
496            %                                4RF:  RF_ALL     = RF_A + RF_B + RF_C + RF_D
497            %     - Vector fields:
498            %       - RF_ON_BOARD_VEC  NOTE: RF_ON_BOARD_VEC  = [RF_A, RF_B]
499            %       - RF_FMC_VEC       NOTE: RF_FMC_VEC       = [RF_C, RF_D]
500            %       - RF_ALL_VEC       NOTE: 2RF:  RF_ALL_VEC = [RF_A, RF_B]
501            %                                4RF:  RF_ALL_VEC = [RF_A, RF_B, RF_C, RF_D]
502            %
503            % NOTE:  Due to Matlab behavior, the scalar fields for RF_A, RF_B, RF_C, and RF_D can be
504            %     used as vectors and therefore do not need separate vector fields in the structure
505            %
506            % Examples:
507            %     Get the interface ID structure (let node be a wl_node object):
508            %         ifc_ids = wl_getInterfaceIDs(node);
509            %         ifc_ids = node.wl_getInterfaceIDs();
510            %
511            %     Use the interface ID structure:
512            %         1) Enable RF_A for transmit: 
513            %                wl_interfaceCmd(node, ifc_ids.RF_A, 'tx_en');
514            %
515            %         2) Get 1000 samples of Read IQ data from all interfaces:
516            %                rx_IQ = wl_basebandCmd(node, ifc_ids.RF_ALL_VEC, 'read_IQ', 0, 1000);
517            %
518           
519            if (nargout > 1) 
520                % Legacy code for compatibility
521                %
522                % Returns a vector of interface IDs that can be used as inputs to all interface
523                % commands and some baseband or user extension commands.
524                %
525                % Let node0 be a wl_node object:
526                %   [RFA, RFB] = wl_getInterfaceIDs(node0)
527                %   [RFA, RFB] = node0.wl_getInterfaceIDs(node0)
528                %
529                % Issues a warning that this syntax will be deprecated in future releases.
530                %
531                if(nargout > obj.num_interfaces)
[4817]532                   error('Node %d has only %d interfaces. User has requested %d interface IDs', obj.ID, obj.num_interfaces, nargout); 
[4681]533                end
534               
535                varargout = num2cell(obj.interfaceIDs(1:nargout)); 
536               
537                % Print warning that this syntax will be deprecated
538                try
539                    temp = evalin('base', 'wl_get_interface_ids_did_warn');
540                catch
541                    fprintf('WARNING:   This syntax for wl_getInterfaceIDs() is being deprecated.\n');
542                    fprintf('WARNING:   Please use:  ifc_ids = wl_getInterfaceIDs(node);\n');
543                    fprintf('WARNING:       where ifc_ids is a structure that contains the interface IDs\n');
544                    fprintf('WARNING:   See WARPLab documentation for more information\n\n');
545                   
546                    assignin('base', 'wl_get_interface_ids_did_warn', 1)
547                end
548               
549            else
550                ifc_ids = struct();
551               
552                switch(obj.num_interfaces)
553               
554                    %---------------------------------------------------------
555                    case 2
556                        % Structure contains:
557                        %     Scalar variables:  RF_A, RF_B, RF_ON_BOARD, RF_ALL
558                        %     Vector variables:  RF_ON_BOARD_VEC, RF_ALL_VEC
559                        %
560                       
561                        % Scalar variables
562                        ifc_ids(1).RF_A               = obj.interfaceIDs(1);
563                        ifc_ids(1).RF_B               = obj.interfaceIDs(2);
564                       
565                        ifc_ids(1).RF_ON_BOARD        = obj.interfaceIDs(1) + obj.interfaceIDs(2);
566                       
567                        ifc_ids(1).RF_ALL             = obj.interfaceIDs(1) + obj.interfaceIDs(2);
568                       
569                        % Vector variables
570                        ifc_ids(1).RF_ON_BOARD_VEC    = [obj.interfaceIDs(1), obj.interfaceIDs(2)];
571                       
572                        ifc_ids(1).RF_ALL_VEC         = [obj.interfaceIDs(1), obj.interfaceIDs(2)];
573                       
574                    %---------------------------------------------------------
575                    case 4
576                        % Structure contains:
577                        %     Scalar variables:  RF_A, RF_B, RF_C, RF_D, RF_ON_BOARD, RF_FMC, RF_ALL
578                        %     Vector variables:  RF_ON_BOARD_VEC, RF_FMC_VEC, RF_ALL_VEC
579                        %
580               
581                        % Scalar variables
582                        ifc_ids(1).RF_A               = obj.interfaceIDs(1);
583                        ifc_ids(1).RF_B               = obj.interfaceIDs(2);
584                        ifc_ids(1).RF_C               = obj.interfaceIDs(3);
585                        ifc_ids(1).RF_D               = obj.interfaceIDs(4);
586                       
587                        ifc_ids(1).RF_ON_BOARD        = obj.interfaceIDs(1) + obj.interfaceIDs(2);
588                        ifc_ids(1).RF_FMC             = obj.interfaceIDs(3) + obj.interfaceIDs(4);
589                       
590                        ifc_ids(1).RF_ALL             = obj.interfaceIDs(1) + obj.interfaceIDs(2) + obj.interfaceIDs(3) + obj.interfaceIDs(4);
591                       
592                        % Vector variables
593                        ifc_ids(1).RF_ON_BOARD_VEC    = [obj.interfaceIDs(1), obj.interfaceIDs(2)];
594                        ifc_ids(1).RF_FMC_VEC         = [obj.interfaceIDs(3), obj.interfaceIDs(4)];
595                       
596                        ifc_ids(1).RF_ALL_VEC         = [obj.interfaceIDs(1), obj.interfaceIDs(2), obj.interfaceIDs(3), obj.interfaceIDs(4)];
597                       
598                    %---------------------------------------------------------
599                    otherwise
600                        error( 'Number of interfaces not supported.  Node reported %d interfaces, should be in [2, 4].', obj.num_interfaces);
601                end
602               
603                varargout = {ifc_ids};
[4332]604            end
[1915]605        end
[4332]606       
607       
[2007]608        function varargout = wl_getTriggerInputIDs(obj)
[4681]609            % Returns the trigger input IDs that can be used as inputs to trigger manager commands
[2007]610            %
[4681]611            % The trigger input IDs are returned in a structure that contains fields for individual
612            % triggers. 
[2007]613            %
[4681]614            % The fields in the structure are:
615            %     - Scalar fields:
616            %       - ETH_A                 - Ethernet Port A
617            %       - ETH_B                 - Ethernet Port B
618            %       - ENERGY_DET            - Energy detection (See 'energy_config_*' commands in the Trigger Manager documentation)
619            %       - AGC_DONE              - Automatic Gain Controller complete
620            %       - SW_REG                - Software register (ie Memory mapped registers that can be triggered by a CPU write)
621            %       - EXT_IN_P0             - External Input Pin 0
622            %       - EXT_IN_P1             - External Input Pin 1
623            %       - EXT_IN_P2             - External Input Pin 2
624            %       - EXT_IN_P3             - External Input Pin 3
625            %
626            % Examples:
627            %     Get the trigger input ID structure (let node be a wl_node object):
628            %         trig_in_ids = wl_getTriggerInputIDs(node);
629            %         trig_in_ids = node.wl_getTriggerInputIDs();
630            %
631            %     Use the trigger input ID structure:
632            %         1) Enable baseband and agc output triggers to be triggered on the Ethernet A input trigger: 
633            %                wl_triggerManagerCmd(nodes, 'output_config_input_selection', [trig_out_ids.BASEBAND, trig_out_ids.AGC], [trig_in_ids.ETH_A]);
634            %
635           
636            if (nargout > 1) 
637                % Legacy code for compatibility
638                %
639                % Returns a vector of trigger input IDs that can be used as inputs to trigger manager commands
640                %
641                % Let node0 be a wl_node object
642                %   [T_IN_ETH_A, T_IN_ENERGY, T_IN_AGCDONE, T_IN_REG, T_IN_D0, T_IN_D1, T_IN_D2, T_IN_D3, T_IN_ETH_B] = wl_getTriggerInputIDs(node0)
643                %   [T_IN_ETH_A, T_IN_ENERGY, T_IN_AGCDONE, T_IN_REG, T_IN_D0, T_IN_D1, T_IN_D2, T_IN_D3, T_IN_ETH_B] = node0.wl_getTriggerInputIDs(node0)
644                %
645                if(nargout > length(obj.trigger_manager.triggerInputIDs))
646                   error('Node %d has only %d trigger inputs. User has requested %d trigger input IDs',obj.ID,length(obj.trigger_manager.triggerInputIDs),nargout); 
647                end
648               
649                varargout = num2cell(obj.trigger_manager.triggerInputIDs(1:nargout));
650           
651                % Print warning that this syntax will be deprecated
652                try
653                    temp = evalin('base', 'wl_get_trigger_input_ids_did_warn');
654                catch
655                    fprintf('WARNING:   This syntax for wl_getTriggerInputIDs() is being deprecated.\n');
656                    fprintf('WARNING:   Please use:  trig_in_ids = wl_getTriggerInputIDs(node);\n');
657                    fprintf('WARNING:       where trig_in_ids is a structure that contains the trigger input IDs\n');
658                    fprintf('WARNING:   See WARPLab documentation for more information\n\n');
659                   
660                    assignin('base', 'wl_get_trigger_input_ids_did_warn', 1)
661                end
662               
663            else
664                % Structure contains:
665                %     Scalar variables:  ETH_A, ETH_B, ENERGY, AGC_DONE, SW_REG, DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3
666                %
667                trig_in_ids = struct();
668               
669                if(length(obj.trigger_manager.triggerInputIDs) ~= 9)
670                   error('Node %d has %d trigger inputs. Expected 9.', obj.ID, length(obj.trigger_manager.triggerInputIDs)); 
671                end
672               
673                % Scalar variables
674                trig_in_ids(1).ETH_A        = obj.trigger_manager.triggerInputIDs(1);
675                trig_in_ids(1).ENERGY_DET   = obj.trigger_manager.triggerInputIDs(2);
676                trig_in_ids(1).AGC_DONE     = obj.trigger_manager.triggerInputIDs(3);
677                trig_in_ids(1).SW_REG       = obj.trigger_manager.triggerInputIDs(4);
678                trig_in_ids(1).EXT_IN_P0    = obj.trigger_manager.triggerInputIDs(5);
679                trig_in_ids(1).EXT_IN_P1    = obj.trigger_manager.triggerInputIDs(6);
680                trig_in_ids(1).EXT_IN_P2    = obj.trigger_manager.triggerInputIDs(7);
681                trig_in_ids(1).EXT_IN_P3    = obj.trigger_manager.triggerInputIDs(8);
682                trig_in_ids(1).ETH_B        = obj.trigger_manager.triggerInputIDs(9);
683       
684                varargout = {trig_in_ids};
[2007]685            end
686        end
[1915]687       
[4332]688       
[2007]689        function varargout = wl_getTriggerOutputIDs(obj)
[4681]690            % Returns the trigger output IDs that can be used as inputs to trigger manager commands
[2007]691            %
[4681]692            % The trigger output IDs are returned in a structure that contains fields for individual
693            % triggers. 
[2007]694            %
[4681]695            % The fields in the structure are:
696            %     - Scalar fields:
697            %       - BASEBAND              - Baseband buffers module
698            %       - AGC                   - Automatic Gain Controller module
699            %       - EXT_OUT_P0            - External Output Pin 0
700            %       - EXT_OUT_P1            - External Output Pin 1
701            %       - EXT_OUT_P2            - External Output Pin 2
702            %       - EXT_OUT_P3            - External Output Pin 3
703            %
704            % Examples:
705            %     Get the trigger output ID structure (let node be a wl_node object):
706            %         trig_out_ids = wl_getTriggerInputIDs(node);
707            %         trig_out_ids = node.wl_getTriggerInputIDs();
708            %
709            %     Use the trigger input ID structure:
710            %         1) Enable baseband and agc output triggers to be triggered on the Ethernet A input trigger: 
711            %                wl_triggerManagerCmd(node, 'output_config_input_selection', [trig_out_ids.BASEBAND, trig_out_ids.AGC], [trig_in_ids.ETH_A]);
712            %
713            %         2) Configure output delay for the baseband:
714            %                node.wl_triggerManagerCmd('output_config_delay', [trig_out_ids.BASEBAND], 0);
715            %
716           
717            if (nargout > 1) 
718                % Legacy code for compatibility
719                %
720                % Returns a vector of trigger output IDs that can be used as inputs to trigger manager commands
721                %
722                % Let node0 be a wl_node object:
[4704]723                %   [T_OUT_BASEBAND, T_OUT_AGC, T_OUT_D0, T_OUT_D1, T_OUT_D2, T_OUT_D3] = wl_getTriggerOutputIDs(node0)
724                %   [T_OUT_BASEBAND, T_OUT_AGC, T_OUT_D0, T_OUT_D1, T_OUT_D2, T_OUT_D3] = node0.wl_getTriggerOutputIDs(node0)
[4681]725                %
726                if(nargout > length(obj.trigger_manager.triggerOutputIDs))
[4704]727                   error('Node %d has only %d trigger outputs. User has requested %d trigger output IDs',obj.ID,length(obj.trigger_manager.triggerOutputIDs),nargout); 
[4681]728                end
729               
730                varargout = num2cell(obj.trigger_manager.triggerOutputIDs(1:nargout)); 
731           
732                % Print warning that this syntax will be deprecated
733                try
734                    temp = evalin('base', 'wl_get_trigger_output_ids_did_warn');
735                catch
[4704]736                    fprintf('WARNING:   This syntax for wl_getTriggerOutputIDs() is being deprecated.\n');
[4681]737                    fprintf('WARNING:   Please use:  trig_out_ids = wl_getTriggerOutputIDs(node);\n');
738                    fprintf('WARNING:       where trig_out_ids is a structure that contains the trigger output IDs\n');
739                    fprintf('WARNING:   See WARPLab documentation for more information\n\n');
740                   
741                    assignin('base', 'wl_get_trigger_output_ids_did_warn', 1)
742                end
743               
744            else
745                % Structure contains:
746                %     Scalar variables:  BASEBAND, AGC, DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3
747                %
748                trig_out_ids = struct();
749               
750                if(length(obj.trigger_manager.triggerOutputIDs) ~= 6)
751                   error('Node %d has %d trigger outputs. Expected 6.', obj.ID, length(obj.trigger_manager.triggerOutputIDs)); 
752                end
753               
754                % Scalar variables
755                trig_out_ids(1).BASEBAND    = obj.trigger_manager.triggerOutputIDs(1);
756                trig_out_ids(1).AGC         = obj.trigger_manager.triggerOutputIDs(2);
757                trig_out_ids(1).EXT_OUT_P0  = obj.trigger_manager.triggerOutputIDs(3);
758                trig_out_ids(1).EXT_OUT_P1  = obj.trigger_manager.triggerOutputIDs(4);
759                trig_out_ids(1).EXT_OUT_P2  = obj.trigger_manager.triggerOutputIDs(5);
760                trig_out_ids(1).EXT_OUT_P3  = obj.trigger_manager.triggerOutputIDs(6);
761       
762                varargout = {trig_out_ids};
[2007]763            end
[4332]764        end
765       
766       
[2919]767        function verify_writeIQ_checksum(obj, checksum)
[4332]768            % This is a callback to verify the WriteIQ checksum in the case that WriteIQ is called by a broadcast
769            % transport.
[2919]770            if ( numel(checksum) > 1 )
771                error('Cannot verify more than one checksum at a time.')
772            end
773
774            % Get the current checksum on the node
775            node_checksum = obj.wl_basebandCmd('write_iq_checksum');
776
777            if ( node_checksum ~= checksum )
778                warning('Checksums do not match on node %d:  %d != %d', obj.ID, node_checksum, checksum)
779            end
780        end
[2007]781       
[4332]782       
[1915]783        function delete(obj)
[4332]784            % Clears the transport object to close any open socket
785            % connections in the event that the node object is deleted.
[2001]786            if(~isempty(obj.transport))
787                obj.transport.delete();
788                obj.transport = [];
789            end
[1915]790        end
791    end
792   
[1972]793   
794    methods(Static=true,Hidden=true)   
795        function command_out = calcCmd_helper(group,command)
796            % Performs the actual command calculation for calcCmd
797            command_out = uint32(bitor(bitshift(group,24),command));
798        end
799    end
[4332]800   
801   
[1915]802    methods(Hidden=true)
[4332]803        % These methods are hidden because users are not intended to call
804        % them directly from their WARPLab scripts.     
[1948]805       
806        function out = calcCmd(obj, grp, cmdID)
[1972]807            % Takes a group ID and a cmd ID to form a single
808            % uint32 command. Every WARPLab module calls this method
809            % to construct their outgoing commands.
[1948]810            switch(lower(grp))
811                case 'node'
[4332]812                    out = obj.calcCmd_helper(obj.GRPID_NODE, cmdID);
[1948]813                case 'interface'
[4332]814                    out = obj.calcCmd_helper(obj.GRPID_IFC, cmdID);
[1948]815                case 'baseband'
[4332]816                    out = obj.calcCmd_helper(obj.GRPID_BB, cmdID);
[1948]817                case 'trigger_manager'
[4332]818                    out = obj.calcCmd_helper(obj.GRPID_TRIGMNGR, cmdID);
[1948]819                case 'transport'
[4332]820                    out = obj.calcCmd_helper(obj.GRPID_TRANS, cmdID);
[1948]821                case 'user_extension'
[4332]822                    out = obj.calcCmd_helper(obj.GRPID_USER, cmdID);
[1948]823            end
[4332]824        end
825       
826       
[1972]827        function out = procCmd(obj, nodeInd, node, cmdStr, varargin)
[4332]828            % wl_node procCmd(obj, nodeInd, node, varargin)
829            %     obj:       Node object (when called using dot notation)
830            %     nodeInd:   Index of the current node, when wl_node is iterating over nodes
831            %     node:      Current node object
832            %     cmdStr:    Command string of the interface command
833            %     varargin:
834            %         [1:N}  Command arguments
835            %
836            out    = [];
837
838            cmdStr = lower(cmdStr);           
[1915]839            switch(cmdStr)
[4332]840           
841                %---------------------------------------------------------
[1915]842                case 'get_hardware_info'
843                    % Reads details from the WARP hardware and updates node object parameters
844                    %
845                    % Arguments: none
846                    % Returns: none (access updated node parameters if needed)
847                    %
[1989]848                    % Hardware support:
[4332]849                    %     All:
850                    %         WARPLab design version
851                    %         Hardware version
852                    %         Ethernet MAC Address
853                    %         Number of Interface Groups
854                    %         Number of Interfaces
[1915]855                    %
[4332]856                    %     WARP v3:
857                    %         Serial number
858                    %         Virtex-6 FPGA DNA
859                    %
860                    [MAJOR, MINOR, REVISION, XTRA] = wl_ver();
[2036]861                   
[4332]862                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_INFO));
863                    resp  = node.sendCmd(myCmd);
864                    resp  = resp.getArgs();
[2036]865                   
[4332]866                    % Response payload (all u32):
867                    %      1:   Serial number
868                    %      2:   FPGA DNA MSB
869                    %      3:   FPGA DNA LSB
870                    %      4:   MAC address bytes 5:4
871                    %      5:   MAC address bytes 3:0
872                    %      6:   [hw_version wl_ver_major wl_ver_minor wl_ver_rev]
873                    %      7:   Current txIQ Buffer Length
874                    %      8:   Current rxIQ Buffer Length
875                    %      9:   Maximum txIQ Buffer Length
876                    %     10:   Maximum rxIQ Buffer Length
877                    %     11:   [trigger manager coreID, trigger manager numOutputs, trigger manager numInputs]
878                    %     12:   number of interface groups
879                    %     13:N: interface group descriptions (one u32 per group)
[2027]880
881                    % If the serial number was provided via the network setup, then check the serial number against the HW
882                    if ( ~isempty( obj.serialNumber ) ) 
883                        if ( ~eq( obj.serialNumber, resp(1) ) )
[2865]884                            error('Serial Number provided in config, W3-a-%d, does not match HW serial number W3-a-%d ', obj.serialNumber, resp(1))         
[2027]885                        end
886                    else 
887                        obj.serialNumber = resp(1);
888                    end
[1915]889                   
890                    obj.fpgaDNA = bitshift(resp(2), 32) + resp(3);
891                   
892                    obj.eth_MAC_addr = 2^32*double(bitand(resp(4),2^16-1)) + double(resp(5));
893                   
[4332]894                    obj.hwVer          = double(bitand(bitshift(resp(6), -24), 255));
895                    obj.wlVer_major    = double(bitand(bitshift(resp(6), -16), 255));
896                    obj.wlVer_minor    = double(bitand(bitshift(resp(6), -8), 255));
[1915]897                    obj.wlVer_revision = double(bitand(resp(6), 255));
898                   
[4332]899                    if((obj.wlVer_major ~= MAJOR) || (obj.wlVer_minor ~= MINOR))
[2036]900                        myErrorMsg = sprintf('Node %d reports WARPLab version %d.%d.%d while this PC is configured with %d.%d.%d', ...
[4332]901                            obj.ID, obj.wlVer_major, obj.wlVer_minor, obj.wlVer_revision, MAJOR, MINOR, REVISION);
[2865]902                        error(myErrorMsg);
[2036]903                    end
904
905                    if(obj.wlVer_revision ~= REVISION)
906                        myWarningMsg = sprintf('Node %d reports WARPLab version %d.%d.%d while this PC is configured with %d.%d.%d', ...
[4332]907                            obj.ID, obj.wlVer_major, obj.wlVer_minor, obj.wlVer_revision, MAJOR, MINOR, REVISION);
[2865]908                        warning(myWarningMsg);
[2036]909                    end
910                   
[4320]911                    % Get the maximum supported IQ lengths                   
[4334]912                    % obj.baseband.max_txIQLen   = double(resp(7));
913                    % obj.baseband.max_rxIQLen   = double(resp(8));
914                    % obj.baseband.max_rxRSSILen = (obj.baseband.max_rxIQLen) / 4;    % RSSI is sampled at 1/4 the speed of IQ
[4320]915
916                    % Get the current supported IQ lengths                   
917                    obj.baseband.txIQLen       = double(resp(9));
918                    obj.baseband.rxIQLen       = double(resp(10));
[4334]919                    obj.baseband.rxRSSILen     = double(resp(10))/4;
[2036]920                   
[4197]921                    % Trigger Manager -- core runs at different speed depending on HW version.
[4320]922                    obj.trigger_manager.setNumInputs(double(bitand(resp(11),255)));
923                    obj.trigger_manager.setNumOutputs(double(bitand(bitshift(resp(11),-8),255)));
924                    obj.trigger_manager.coreVersion = double(bitand(bitshift(resp(11),-16),255));
[4817]925
[2011]926                    switch(obj.hwVer)
[4384]927                        %TODO: These parameters should be passed up from
928                        %the board
[2011]929                        case 1
[4332]930                            error('WARP v1 Hardware is not supported by WARPLab 7');
[4474]931                        case {2, 3}
932                            % Clock frequency of the sysgen core in the design
933                            %   NOTE:  In WARPLab 7.5.1, the WARP v2 sysgen clock was increased to 160 MHz
934                            %
[4817]935                            clock_freq   = 160e6;
936                            trig_in_ids  = obj.wl_getTriggerInputIDs();
937                            trig_out_ids = obj.wl_getTriggerOutputIDs();
[4474]938                           
939                            % Trigger output delays
[4384]940                            for k = length(obj.trigger_manager.triggerOutputIDs):-1:1
[4928]941                                % With Trigger Processor v1.07.a, all delays were increased to 65535                               
[4474]942                                obj.trigger_manager.output_delayStep_ns(k) = (1/(clock_freq))*1e9;
[4928]943                                obj.trigger_manager.output_delayMax_ns(k)  = 65535 * obj.trigger_manager.output_delayStep_ns(k);
[4474]944                            end
945                           
946                            % Trigger input delays
947                            for k = length(obj.trigger_manager.triggerInputIDs):-1:1
948                                obj.trigger_manager.input_delayStep_ns(k) = (1/(clock_freq))*1e9;
949                                obj.trigger_manager.input_delayMax_ns(k)  = 31 * obj.trigger_manager.input_delayStep_ns(k);
950                            end
[2011]951                    end
[2009]952                   
[4320]953                    obj.num_interfacesGroups = resp(12);
954                    obj.num_interfaces = resp(13);
[4332]955                   
956                    %% TODO - parse each interface descriptor and create interface group objects
957                   
958                %---------------------------------------------------------
[2003]959                case 'get_fpga_temperature'
960                    % Reads the temperature (in Celsius) from the FPGA
961                    %
962                    % Arguments: none
963                    % Returns: (double currTemp), (double minTemp), (double maxTemp)
964                    %   currTemp - current temperature of FPGA in degrees Celsius
965                    %   minTemp - minimum recorded temperature of FPGA in degrees Celsius
966                    %   maxTemp - maximum recorded temperature temperature of FPGA in degrees Celsius
[4332]967                    %                   
968                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_TEMPERATURE));
969                    resp  = node.sendCmd(myCmd);
970                    resp  = resp.getArgs();
[2003]971                   
[4332]972                    % Convert from raw temperature to Celsius
[2003]973                    out = ((double(resp)/65536.0)/0.00198421639) - 273.15;
[1915]974
[4332]975                %---------------------------------------------------------
[1915]976                case 'initialize'
977                    % Initializes the node; this must be called at least once per power cycle of the node
978                    %
979                    % Arguments: none
980                    % Returns: none
[4332]981                    %
982                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_INITIALIZE));
[1915]983                    node.sendCmd(myCmd);
[4332]984                   
985                %---------------------------------------------------------
[1915]986                case 'identify'
[1989]987                    % Blinks the user LEDs on the WARP node, to help identify MATLAB node-to-hardware node mapping
[1915]988                    %
989                    % Arguments: none
990                    % Returns: none
[4332]991                    %
992                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_IDENTIFY));
[1915]993                    node.sendCmd(myCmd);
[4332]994                   
995                %---------------------------------------------------------
[2029]996                case 'node_config_reset'
997                    % Resets the HW state of the node to accept a new node configuration
[2027]998                    %
999                    % Arguments: none
1000                    % Returns: none
[4332]1001                    %
1002                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_NODE_CONFIG_RESET));                   
1003                    myCmd.addArgs(uint32(node.serialNumber)); 
[2027]1004                    node.sendCmd(myCmd);
[4332]1005                   
1006                %---------------------------------------------------------
[4784]1007                % 'node_config_setup' is only implemented in wl_initNodes.m
1008                %
[4788]1009
[4784]1010                %---------------------------------------------------------
[4788]1011                case 'node_mem_read'
1012                    % Read memory addresses in the node
1013                    %
1014                    % Arguments:   (uint32 ADDRESS), (uint32 LENGTH)
1015                    % Returns:     Vector of uint32 values read from the node
1016                    %
1017                    % ADDRESS:     Address to start the read
1018                    %
1019                    % LENGTH:      Number of uint32 words to read from the node
1020                    %
1021                    % NOTE:  The node enforces a maximum number of words that can be transferred for a
1022                    %     given read.  This is typically on the order of 350 words.
1023                    %
[4819]1024                    % NOTE:  Please use the C code files, such as xparameters.h and other header files,
1025                    %     to understand the addresses of various registers in the system and the meaning
1026                    %     of the bits within those registers.
1027                    %
[4788]1028                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_MEM_RW));
1029                   
1030                    % Check arguments
1031                    if(length(varargin) ~= 2)
1032                        error('%s: Requires two arguments:  Address, Length (in uint32 words of the read)', cmdStr);
1033                    end
1034                   
1035                    address     = varargin{1};
1036                    read_length = varargin{2};
1037
1038                    myCmd.addArgs(myCmd.CMD_PARAM_READ_VAL);
1039                   
1040                    % Check arguments
1041                    if ((address < 0) || (address > hex2dec('FFFFFFFF')))
1042                        error('%s: Address must be in [0, 0xFFFFFFFF].\n', cmdStr);
1043                    end
1044
1045                    if ((read_length < 0) || (read_length > 350))
1046                        error('%s: Length must be in [0, 350] words.\n', cmdStr);
1047                    end
1048                   
1049                    % Send command to the node
1050                    myCmd.addArgs(address);
1051                    myCmd.addArgs(read_length);
1052                   
1053                    resp = node.sendCmd(myCmd);
1054                   
1055                    % Process response from the node.  Return arguments:
1056                    %         [1] - Status
1057                    %         [2] - Length
1058                    %     [ 3: N] - Values
1059                    %
1060                    for i = 1:numel(resp)                   % Needed for unicast node_group support
1061                        ret   = resp(i).getArgs();
1062
1063                        if (ret(1) == myCmd.CMD_PARAM_SUCCESS)
1064                            if ((ret(2) + 2) == length(ret))
1065                                if (i == 1) 
1066                                    out = ret(3:end);
1067                                else
1068                                    out(:,i) = ret(3:end);
1069                                end
1070                            else
1071                                msg = sprintf('%s: Memory read length mismatch error in node %d:  %d != %d\n', cmdStr, nodeInd, (ret(2) + 2), length(ret));
1072                                error(msg);
1073                            end
1074                        else 
1075                            msg = sprintf('%s: Memory read error in node %d.\n', cmdStr, nodeInd);
1076                            error(msg);
1077                        end
1078                    end
1079                   
1080                %---------------------------------------------------------
1081                case 'node_mem_write'
1082                    % Write memory addresses in the node
1083                    %
1084                    % Arguments: (uint32 ADDRESS), (uint32 VALUES)
1085                    % Returns: none
1086                    %
1087                    % ADDRESS:     Address to start the write
1088                    %
1089                    % VALUES:      Vector of uint32 words to write to the node
1090                    %
1091                    % NOTE:  The node enforces a maximum number of words that can be transferred for a
1092                    %     given write.  This is typically on the order of 350 words.
1093                    %
[4819]1094                    % NOTE:  Please use the C code files, such as xparameters.h and other header files,
1095                    %     to understand the addresses of various registers in the system and the meaning
1096                    %     of the bits within those registers.
1097                    %
[4788]1098                    myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_MEM_RW));
1099                   
1100                    % Check arguments
1101                    if(length(varargin) ~= 2)
1102                        error('%s: Requires two arguments:  Address, Vector of uint32 words to write', cmdStr);
1103                    end
1104                   
1105                    address     = varargin{1};
1106                    values      = varargin{2};
1107
1108                    myCmd.addArgs(myCmd.CMD_PARAM_WRITE_VAL);
1109                   
1110                    % Check arguments
1111                    if ((address < 0) || (address > hex2dec('FFFFFFFF')))
1112                        error('%s: Address must be in [0, 0xFFFFFFFF].\n', cmdStr);
1113                    end
1114
1115                    if ((length(values) < 0) || (length(values) > 350))
1116                        error('%s: Length of VALUES vector must be in [0, 350] words.\n', cmdStr);
1117                    end
1118                   
1119                    % Send command to the node
1120                    if(~isempty(values))
1121                        myCmd.addArgs(address);
1122                        myCmd.addArgs(length(values));
1123                        myCmd.addArgs(values);
1124                       
1125                        resp = node.sendCmd(myCmd);
1126
1127                        % Process response from the node.  Return arguments:
1128                        %         [1] - Status
1129                        %
1130                        for i = 1:numel(resp)                   % Needed for unicast node_group support
1131                            ret   = resp(i).getArgs();
1132
1133                            if (ret(1) ~= myCmd.CMD_PARAM_SUCCESS)
1134                                msg = sprintf('%s: Memory write error in node %d.\n', cmdStr, nodeInd);
1135                                error(msg);
1136                            end
1137                        end
1138                    end
1139                   
1140                %---------------------------------------------------------
[1915]1141                otherwise
[2865]1142                    error( 'unknown node command %s', cmdStr);
[1915]1143            end
1144           
[4332]1145            if((iscell(out) == 0) && (numel(out) ~= 1))
[1915]1146                out = {out}; 
1147            end     
1148        end
1149       
[4332]1150       
[1915]1151        function out = sendCmd(obj, cmd)
[4332]1152            % This method is responsible for serializing the command
1153            % objects provided by each of the components of WARPLab into a
1154            % vector of values that the transport object can send. This
1155            % method is used when the board must at least provide a
1156            % transport-level acknowledgement. If the response has actual
1157            % payload that needs to be provided back to the calling method,
1158            % that response is passed as an output of this method.
1159            %
[4309]1160            resp = obj.transport.send(cmd.serialize(), true);
[1923]1161           
[1915]1162            out = wl_resp(resp);
1163        end
1164       
[4332]1165       
[1915]1166        function sendCmd_noresp(obj, cmd)
[4332]1167            % This method is responsible for serializing the command
1168            % objects provided by each of the components of WARPLab into a
1169            % vector of values that the transport object can send. This
1170            % method is used when a board should not send an immediate
1171            % response. The transport object is non-blocking -- it will send
[1915]1172            % the command and then immediately return.
[4332]1173            %
[4309]1174            obj.transport.send(cmd.serialize(), false);
[1915]1175        end 
1176       
[4332]1177       
[1915]1178        function out = receiveResp(obj)
[4332]1179            % This method will return a vector of responses that are
1180            % sitting in the host's receive queue. It will empty the queue
1181            % and return them all to the calling method.
1182            %
[1915]1183            resp = obj.transport.receive();
[4332]1184           
[1915]1185            if(~isempty(resp))
[4309]1186                % Create vector of response objects if received string of bytes is a concatenation of many responses
1187                done       = false;
1188                index      = 1;
1189                resp_index = 1;
[1915]1190                while ~done
[4309]1191                    out(index)  = wl_resp(resp(resp_index:end));
1192                    currRespLen = out(index).len();
1193                   
1194                    resp_index  = resp_index + currRespLen;
1195                    index       = index + 1;
1196                   
1197                    if(resp_index >= length(resp))
[1915]1198                        done = true;
1199                    end
1200                end
1201            else
1202                out = [];
1203            end
1204        end
1205       
[4332]1206       
[4815]1207        function out = repr(obj)
1208            % Return a string representation of the wl_node
1209            out = cell(1,length(obj));
1210           
1211            for n = 1:length(obj)
1212                currObj = obj(n); 
1213               
1214                if(isempty(currObj.ID))
1215                    out(n) =  {'Node has not been initialized'};
1216                else
1217                    ID     = sprintf('%d', currObj.ID);
1218                   
1219                    if(currObj.hwVer == 3)
1220                        SN = sprintf('W3-a-%05d',currObj.serialNumber);
1221                    else
1222                        SN = 'N/A';
1223                    end
1224                   
1225                    out(n) = {sprintf('%12s (ID = %3s)', SN, ID)};
1226                end
1227            end
1228           
1229            if (length(obj) == 1) 
1230                out = out{1};
1231            end
1232        end
1233       
1234       
[1923]1235        function disp(obj)
[4332]1236            % This is a "pretty print" method to summarize details about wl_node
1237            % objects and print them in a table on Matlab's command line.
1238            %
[1948]1239            hasUserExt = 0;
[4332]1240            strLen     = 0;
1241           
[1948]1242            for n = 1:length(obj)
1243               currObj = obj(n);
1244               hasUserExt = hasUserExt || ~isempty(currObj.user); 
[4332]1245               
[1948]1246               if(~isempty(currObj.user))
[4332]1247                  strLen = max(strLen,length(class(currObj.user)) + 3);        % +3 is for surrounding spaces and the |
[1948]1248               end
1249            end
1250           
1251            extraTitle = '';
1252            extraLine = '';
1253            extraArgs = '';
1254           
1255            if(hasUserExt)
[4332]1256                extraTitle = repmat(' ', 1, strLen-1);
1257                extraLine  = repmat('-', 1, strLen-1);
1258                extraTitle = [extraTitle, '|'];
1259                extraLine  = [extraLine, '-'];
[1948]1260               
1261                newTitle = 'User Ext.';
1262                extraTitle((strLen - length(newTitle) - 1):(end - 2)) = newTitle;
1263            end
[1923]1264                    fprintf('Displaying properties of %d wl_node objects:\n',length(obj));
[4332]1265                    fprintf('|  ID |  WLVER |  HWVER |    Serial # |  Ethernet MAC Addr |          Address | %s\n', extraTitle)
1266                    fprintf('-------------------------------------------------------------------------------%s\n', extraLine)
[1923]1267            for n = 1:length(obj)
1268                currObj = obj(n); 
[1948]1269               
1270                if(~isempty(currObj.user))
1271                    myFormat = sprintf('%%%ds |',strLen-2);
[1950]1272                    extraArgs = sprintf(myFormat,class(currObj.user));
[1948]1273                elseif(hasUserExt)
1274                    extraArgs = extraLine;
1275                    extraArgs(end) = '|';
1276                end
1277               
[1923]1278                if(isempty(currObj.ID))
[4332]1279                    fprintf('|     N/A     Node object has not been initialized                            |%s\n', extraArgs)
[1923]1280                else
[4332]1281                    ID    = sprintf('%d', currObj.ID);
1282                    WLVER = sprintf('%d.%d.%d', currObj.wlVer_major, currObj.wlVer_minor, currObj.wlVer_revision);
1283                    HWVER = sprintf('%d', currObj.hwVer);
[1923]1284                   
1285                    if(currObj.hwVer == 3)
1286                        SN = sprintf('W3-a-%05d',currObj.serialNumber);
1287                    else
1288                        SN = 'N/A';
1289                    end
1290                   
[4332]1291                    temp    = dec2hex(uint64(currObj.eth_MAC_addr),12);                   
[1923]1292                    MACADDR = sprintf('%2s-%2s-%2s-%2s-%2s-%2s',...
1293                        temp(1:2),temp(3:4),temp(5:6),temp(7:8),temp(9:10),temp(11:12));
[2027]1294
[4416]1295                    if ( ~isempty( currObj.transport ) & ~isempty( currObj.transport.getAddress() ) )
1296                        ADDR = currObj.transport.getAddress();
[2027]1297                    else
1298                        ADDR = '';
1299                    end                     
1300                       
[4332]1301                    fprintf('|%4s |%7s |%7s |%12s |%19s |%17s |%s\n', ID, WLVER, HWVER, SN, MACADDR, ADDR, extraArgs);
[1923]1302                   
1303                end
[4332]1304                    fprintf('-------------------------------------------------------------------------------%s\n', extraLine)
[1923]1305            end
[1972]1306        end       
[4332]1307    end % end methods(Hidden)
1308end % end classdef
Note: See TracBrowser for help on using the repository browser.