wiki:802.11/wlan_exp/HowToAddCommand

Version 2 (modified by welsh, 8 years ago) (diff)

--

WLAN Exp: How to add a Command

This tutorial will explain how to add a new command to the WLAN Exp framework. This will allow a user to create a custom command that can be called via the WLAN Experiments Framework.

802.11 Reference Design v1.3 and prior

Overview:

  1. Edit wlan_exp/cmds.py with:
    • Create new non-overlapping CMDID_ value
    • Create new message.Cmd subclass, probably by copy/paste of existing simple command
    • Add new subclass to all
  2. Edit wlan_exp/node.py (or a subclass) with new command-specific node method
  3. Add new CMDID_ value to wlan_mac_high_framework/include/wlan_exp_node.h
  4. Edit wlan_mac_high_framework/wlan_exp_node.c with new case in giant node_processCmd() switch statement
  5. Possibly edit wlan_mac_[ap,sta,ibss].[c,h] for any MAC-specific responses to the new command

Edit wlan_exp/cmds.py:

Add a new Command ID (CMDID_) value that does not overlap with any existing Command ID value. For example, we can add "CMDID_NODE_USER_CMD" to the file:

CMDID_NODE_WLAN_MAC_ADDR                         = 0x001018
CMDID_NODE_LOW_PARAM                             = 0x001020
CMDID_NODE_USER_INFO_CMD                         = 0x001030

CMD_PARAM_WRITE                                  = 0x00000000
CMD_PARAM_READ                                   = 0x00000001

Create a new message.Cmd sub-class. For example, this new class will take in an array of values and send them to the node. It will also take any values returned by the node and return them to the user:

class NodeUserInfoCommand(message.Cmd):
    """Command to pass user information to/from the node
    
    Attributes:
        values    -- Scalar or list of u32 values to pass to the node

    """
    def __init__(self, values=None):
        super(NodeUserCommand, self).__init__()        
        
        self.command    = _CMD_GROUP_NODE + CMDID_NDOE_USER_INFO_CMD

        # Caluculate the size in words of the values argument
        size = 0
        
        if values is not None:
            size += len(values)

        # Add the size in words of the values arguments to the message
        self.add_args(size)

        # Add the values to the message
        if values is not None:
            try:
                for v in values:
                    self.add_args(v)
            except TypeError:
                self.add_args(values)
            
    def process_resp(self, resp):
        """ Message format:
                respArgs32[0]   Status
                respArgs32[1]   Size in words of return values
                respArgs32[2:N] Values
        """
        # Create a hash of all possible error codes with respective error messages
        error_code_base         = CMD_PARAM_ERROR

        status_errors = { error_code_base      : "Error Processing User Command" }

        # Get the arguments from the response
        args = resp.get_args()
        
        # If the response is valid, then return the size and any values from the node
        if resp.resp_is_valid(num_args=(args[1] + 2), status_errors=status_errors, name='from User Command command'):
            return args[1:]
        else:
            return None

# End Class

Add new subclass to all:

__all__ = [# Log command classes
           'LogGetEvents', 'LogConfigure', 'LogGetStatus', 'LogGetCapacity', 'LogAddExpInfoEntry', 
           'LogAddCountsTxRx',
           # Counts command classes
           'CountsConfigure', 'CountsGetTxRx', 
           # LTG classes
           'LTGConfigure', 'LTGStart', 'LTGStop', 'LTGRemove', 'LTGStatus',
           # Node command classes
           'NodeResetState', 'NodeConfigure', 'NodeProcWLANMACAddr', 'NodeProcTime', 
           'NodeSetLowToHighFilter', 'NodeProcChannel', 'NodeProcRandomSeed', 'NodeLowParam', 'NodeUserInfoCommand', 
...

Edit wlan_exp/node.py (or a subclass)

Add new command specific method to the node (or a subclass):

    def send_user_cmd(self, values=None):
        """Send information to / Receive information from a node
 
        Args:
            values (list of int): Value(s) to send to the node
            
        Returns:
            values (list of int): Value(s) received from the node
        """
        if values is not None:
            try:
                v0 = values[0]
            except TypeError:
                v0 = values
            
            if ((type(v0) is not int) and (type(v0) is not long)) or (v0 >= 2**32):
                raise Exception('ERROR: values must be scalar or iterable of ints in [0,2^32-1]!')  
                
        try:
            vals = list(values)
        except TypeError:
            vals = [values]

        return self.send_cmd(cmds.NodeUserInfoCommand(values=vals))

Edit wlan_mac_high_framework/include/wlan_exp_node.h

Add new Command ID (CMDID_) value to the C code. This value should be the same as the CMDID_ value defined in the Python code:

#define CMDID_NODE_WLAN_MAC_ADDR                           0x001018
#define CMDID_NODE_LOW_PARAM                               0x001020
#define CMDID_NODE_USER_INFO_CMD                           0x001030

#define CMD_PARAM_WRITE_VAL                                0x00000000
#define CMD_PARAM_READ_VAL                                 0x00000001

Edit wlan_mac_high_framework/wlan_exp_node.c

Add command implementation with new case in the node_processCmd() switch statement:

        //---------------------------------------------------------------------
        case CMDID_NODE_USER_INFO_CMD:
            // Receive information from user / Send information to user
            //
            // Message format:
            //     cmd_args_32[0]    Size in words of received values
            //     cmd_args_32[1:N]  Values
            //
            // Response format:
            //     resp_args_32[0]    Status
            //     resp_args_32[1]    Size in words of values to send
            //     resp_args_32[3:M]  Values
            //
            status  = CMD_PARAM_SUCCESS;
            size    = Xil_Ntohl(cmd_args_32[0]);
            temp    = 0;

            // Byte swap all the value words in the message (in place)
            for (i = 1; i < (size + 1); i++) {
                cmd_args_32[i] = Xil_Ntohl(cmd_args_32[i]);
            }


            //
            // ADD PROCESSING FOR COMMAND VALUES
            //
            // NOTE:  The user can define any message structure needed.  Modify the 'status' variable
            //     if there is an error (use CMD_PARAM_ERROR or any additional error codes the user adds).
            //     Modify the 'temp' variable to indicate the number of return values.  Additional
            //     variables can be declared at the beginning of the function.
            //

            // In this example, the command merely echos the values sent to the node.
            //
            // NOTE:  Need to make sure the indexing is correct since the response values start at a different
            //     word than the received values.
            //
            for (i = 1; i < (size + 1); i++) {
                resp_args_32[i+1] = cmd_args_32[i];
            }


            // Send response
            resp_args_32[0] = Xil_Htonl(status);
            resp_args_32[1] = Xil_Htonl(temp);

            // Byte swap all the value words in the return message (in place)
            for (i = 2; i < (temp + 2); i++) {
                resp_args_32[i] = Xil_Htonl(resp_args_32[i]);
            }

            resp_index        += temp + 2;        // Number of return values + 2

            resp_hdr->length  += (resp_index * sizeof(resp_args_32));
            resp_hdr->num_args = resp_index;
        break;