Changes between Version 15 and Version 16 of 802.11/wlan_exp/Extending
- Timestamp:
- Dec 16, 2015, 10:51:40 PM (8 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
802.11/wlan_exp/Extending
v15 v16 9 9 The 802.11 Reference Design Experiments Framework provides a variety of commands to control and observe WARP v3 nodes in real time. However many experiments will require additional commands, especially when users extend the reference code with new behaviors. 10 10 11 Starting in 802.11 Reference Design v1.4 we have greatly simplified the process of implementing extensions to the experiments framework. Adding wlan_exp commands was more complicated in previous versions; refer to the archived [wiki:../HowToAddCommand HowToAddCommand] page for details on adding commands to versions before v1.4.11 Starting in 802.11 Reference Design v1.4, we have greatly simplified the process of implementing extensions to the experiments framework. Adding wlan_exp commands was more complicated in previous versions; refer to the archived [wiki:../HowToAddCommand HowToAddCommand] page for details on adding commands to versions before v1.4. 12 12 13 13 There are two kinds of framework extensions: … … 24 24 * Command arguments: an optional list of {{{u32}}} arguments supplied by the Python code that is passed to the C code handler 25 25 26 The command ID is used by the C code to select which code block should process the command payload. The Python and C code must use matching lists of command IDs. All user command IDs must be 24-bit integers (i.e. in [0, 2^24^ -1]). The framework does not reserve any command ID values in this range .26 The command ID is used by the C code to select which code block should process the command payload. The Python and C code must use matching lists of command IDs. All user command IDs must be 24-bit integers (i.e. in [0, 2^24^ -1]). The framework does not reserve any command ID values in this range for user commands. 27 27 28 28 The command arguments are an optional payload supplied by the Python script. The wlan_exp framework sends this payload to the node with no modifications. The arguments must be constructed as a list of unsigned 32-bit integers ({{{u32}}} values). The Python and C code must implement complementary argument construction/parsing functions. The argument list may be omitted if a command requires no payload. … … 33 33 34 34 {{{#!python 35 # No command arguments, no response payload35 # No command arguments, no response payload 36 36 my_node.send_user_command(CMDID_USER_MYCMD, args=None) 37 37 38 # 3 arguments, no response payload38 # 3 arguments, no response payload 39 39 my_node.send_user_command(CMDID_USER_MYCMD, args=[ARG0 ARG1 ARG2]) 40 40 41 # 2 arguments, with response payload41 # 2 arguments, with response payload 42 42 cmd_resp = my_node.send_user_command(CMDID_USER_MYCMD, args=[ARG0 ARG1]) 43 43 }}} … … 49 49 The 802.11 MAC code running on the WARP node handles user commands at two levels. 50 50 51 * '''Framework''': if the command behavior is common to all MAC applications, the command is handled in the {{{process_user_cmd()}}} function in {{{wlan_exp_user.c}}}. You should modify {{{process_user_cmd()}}} to handle any new framework-level commands required for your application. Any command IDs not handled in {{{process_user_cmd()}}} will be passed through to the MAC application.52 53 * '''MAC Application''': if a command behavior depends on the upper-level MAC application, the command is handled in the {{{wlan_exp_process_user_cmd()}}} callback function in the top-level MAC. You should modify the {{{wlan_exp_process_user_cmd()}}} function in the {{{wlan_mac_ap.c}}}, {{{wlan_mac_sta.c}}} and {{{wlan_mac_ibss.c}}} files to implement any MAC-specific command behaviors.51 * '''Framework''': If the command behavior is common to all MAC applications, the command is handled in the {{{process_user_cmd()}}} function in {{{wlan_exp_user.c}}}. You should modify {{{process_user_cmd()}}} to handle any new framework-level commands required for your application. Any command IDs not handled in {{{process_user_cmd()}}} will be passed through to the MAC application. 52 53 * '''MAC Application''': If a command behavior depends on the upper-level MAC application, the command is handled in the {{{wlan_exp_process_user_cmd()}}} callback function in the top-level MAC. You should modify the {{{wlan_exp_process_user_cmd()}}} function in the {{{wlan_mac_ap.c}}}, {{{wlan_mac_sta.c}}} and {{{wlan_mac_ibss.c}}} files to implement any MAC-specific command behaviors. 54 54 55 55 Command handlers in these functions share a common structure: 56 56 * Examine the command ID and determine which code block ({{{case}}}) should handle the command 57 * Implement the required command behavior 58 * If a response payload is required, populate the response values into the {{{resp onse->args}}} array57 * Implement the required command behavior using any supplied arguments in the {{{cmd_args_32}}} array 58 * If a response payload is required, populate the response values into the {{{resp_args_32}}} array 59 59 * Update the response header fields for response length ({{{resp_hdr->length}}}) and number of response arguments ({{{resp_hdr->num_args}}}) 60 60 61 The wlan_exp framework will encapsulate the command response payload in an Ethernet f ame and return it to the calling Python script for processing.61 The wlan_exp framework will encapsulate the command response payload in an Ethernet frame and return it to the calling Python script for processing. One thing to note is that a command response payload is limited to {{{max_resp_len}}} values. 62 62 63 63 '''Interrupt Safety'''[[BR]] … … 71 71 interrupt_state_t curr_interrupt_state; 72 72 73 // Record the current interrupt enable state, then disable all interrupts73 // Record the current interrupt enable state, then disable all interrupts 74 74 curr_interrupt_state = wlan_mac_high_interrupt_stop(); 75 75 76 76 /* 77 * Do any interrupt-sensitive processing here78 */79 80 // Restore the interrupt enable state77 * Do any interrupt-sensitive processing here 78 */ 79 80 // Restore the interrupt enable state 81 81 wlan_mac_high_interrupt_restore_state(curr_interrupt_state); 82 82 }}} 83 83 84 85 86 87 '''TODO:''' 88 * Endianness 84 '''Endianness'''[[BR]] 85 86 Both the C code on the node and the Python code on the host operate on little-endian data. However, the wlan_exp transport requires command and response arguments to be big-endian for transfer within the Ethernet frame. Xilinx provides two functions to assist in converting data between big-endian and little-endian: 87 * {{{Xil_Ntohl()}}} - "Network to Host" conversion (i.e. converts big-endian to little-endian) 88 * {{{Xil_Htonl()}}} - "Host to Network" conversion (i.e. converts little-endian to big-endian) 89 90 Therefore, in order to use command arguments within your C code, you must convert each argument from big-endian to little-endian: 91 92 {{{#!c 93 arg_0 = Xil_Ntohl(cmd_args_32[0]); // Swap endianness of command argument 94 }}} 95 96 Similarly, in order to send response arguments to the host, you must convert each argument from little-endian to big-endian: 97 98 {{{#!c 99 resp_args_32[resp_index++] = Xil_Htonl(status); // Swap endianness of response arguments 100 }}} 89 101 90 102 === Example Command: Reading Tx Queue Status === 91 103 92 This example shows how to implement a custom wlan_exp command, including the required Python and C code. The example command retrieves the status of the Txqueues from the WARP node. The upper-level MAC responds to the command with the number of packets currently enqueued in each Tx queue. Because each upper-level MAC (AP, STA, IBSS) handles Tx queues differently the command handler is implemented in the {{{wlan_exp_user_ap_process_cmd()}}} function of the top-level MAC.104 This example shows how to implement a custom wlan_exp command, including the required Python and C code. The example command retrieves the status of the transmit (Tx) queues from the WARP node. The upper-level MAC responds to the command with the number of packets currently enqueued in each Tx queue. Because each upper-level MAC (AP, STA, IBSS) handles Tx queues differently the command handler is implemented in the {{{wlan_exp_user_ap_process_cmd()}}} function of the top-level MAC. 93 105 94 106 '''Python Code'''[[BR]] … … 98 110 {{{#!python 99 111 100 # Define a command ID (must be 24-bit integer)112 # Define a command ID (must be 24-bit integer) 101 113 CMDID_USER_TX_QUEUE_STATUS = 100 102 114 103 # Define method for sending command and processing the response115 # Define method for sending command and processing the response 104 116 def get_tx_queue_status(node, queue_id=None): 105 117 106 118 if(queue_id is not None): 107 # Arguments must be a list of ints - listify/cast the scaler queue_id119 # Arguments must be a list of ints - listify/cast the scaler queue_id 108 120 args = [int(queue_id)] 109 121 else: … … 112 124 resp = node.send_user_command(CMDID_USER_TX_QUEUE_STATUS, args) 113 125 114 # Response should be list of ints with 2 values per queue115 # Each pair of response values is (queue_id, queue_occupancy)116 # Sanity check the response, then convert to a list of 2-tuples and return126 # Response should be list of ints with 2 values per queue 127 # - Each pair of response values is (queue_id, queue_occupancy) 128 # - Sanity check the response, then convert to a list of 2-tuples and return 117 129 if(len(resp) % 2 != 0): 118 130 print('ERROR: Tx Queue Status command response lenth ({0} values) was not even!'.format(len(resp))) 119 131 return 120 132 else: 121 # Group each pair of response values into 2-tuple and return list of 2-tuples133 # Group each pair of response values into 2-tuple and return list of 2-tuples 122 134 ret = zip(*[iter(resp)]*2) 123 135 … … 131 143 '''C Code'''[[BR]] 132 144 133 Each upper-level MAC application implements its own callback function for handling application-specific user commands. By default these functions are empty. You must modify the C code to implement the behaviors required for your custom command. 134 135 Modify the {{{wlan_exp_user_ap_process_cmd()}}} function in {{{wlan_mac_ap.c}}}. Start by defining some local variables at the top of the function: 136 137 {{{#!c 138 145 Each upper-level MAC application implements its own callback function for handling application-specific user commands. By default these functions are empty. You must modify the C code to implement the behaviors required for your custom command. The code below is for the AP. It is left to the user to implement similar functionality the other MAC applications so that the command works on all types of nodes. 146 147 Modify the {{{wlan_exp_user_ap_process_cmd()}}} function in {{{wlan_mac_ap.c}}}. Start by defining the command ID before the function: 148 149 {{{#!c 139 150 #define CMDID_USER_TX_QUEUE_STATUS 100 140 int i;141 u32 req_queue_id;142 u32 q_id, q_occ;143 dl_entry* curr_station_info_entry;144 station_info* curr_station_info;145 151 }}} 146 152 … … 149 155 150 156 {{{#!c 151 case CMDID_USER_TX_QUEUE_STATUS: 157 case CMDID_USER_TX_QUEUE_STATUS: { 158 int iter; 159 u32 req_queue_id; 160 u32 q_id, q_occ; 161 dl_entry * curr_station_info_entry; 162 station_info * curr_station_info; 163 152 164 xil_printf("Got Tx queue status cmd\n"); 153 165 … … 162 174 xil_printf("No queue ID requested - returning status of all queues\n"); 163 175 164 // Gather status of all Tx queues:165 // Multicast queue (MCAST_QID)166 // Managment queue (MANAGEMENT_QID)167 // Queue per AID176 // Gather status of all Tx queues: 177 // Multicast queue (MCAST_QID) 178 // Managment queue (MANAGEMENT_QID) 179 // Queue per AID 168 180 resp_args_32[resp_index++] = Xil_Htonl(MCAST_QID); 169 181 resp_args_32[resp_index++] = Xil_Htonl(queue_num_queued(MCAST_QID)); … … 172 184 173 185 if(my_bss_info->associated_stations.length > 0) { 174 curr_station_info_entry = NULL; 175 176 //Iterating over the dl_list is potentially dangerous, as the list itself might change 186 iter = my_bss_info->associated_stations.length; 187 curr_station_info_entry = my_bss_info->associated_stations.first; 188 189 // Iterating over the dl_list is potentially dangerous, as the list itself might change 177 190 // if this function is interrupted. We protect against this by iterating over (at most) 178 // the number of entries in the list at the time this loop starts. The iteration variable i191 // the number of entries in the list at the time this loop starts. The iteration variable 179 192 // is *not* used for indexing the list - we still traverse entries with entry.next 180 for(i=0; i<my_bss_info->associated_stations.length; i++) { 181 182 if(curr_station_info_entry == NULL) { 183 //First iteration - get the head of the dl_list 184 curr_station_info_entry = my_bss_info->associated_stations.first; 185 } else { 186 //Subsequent iteration - get the next entry in the dl_list 187 curr_station_info_entry = dl_entry_next(curr_station_info_entry); 188 } 189 190 //Get the station info pointer from the list entry 193 while((cur_station_info_entry != NULL) && (iter-- > 0)) { 194 195 // Get the station info pointer from the list entry 191 196 curr_station_info = (station_info*)(curr_station_info_entry->data); 192 197 193 // Get the queue ID and queue occupancy198 // Get the queue ID and queue occupancy 194 199 q_id = AID_TO_QID(curr_station_info->AID); 195 200 q_occ = queue_num_queued(q_id); 196 201 xil_printf("Q: %2d %3d\n", q_id, q_occ); 197 202 198 199 //Add the queue info to the response payload 203 // Add the queue info to the response payload 200 204 resp_args_32[resp_index++] = Xil_Htonl(q_id); 201 205 resp_args_32[resp_index++] = Xil_Htonl(q_occ); 202 206 203 //Break out of the for loop on the last station info entry or 204 // if our response is already reached the max size allowed by the framework 205 if( (curr_station_info_entry == my_bss_info->associated_stations.last) || 206 (dl_entry_next(curr_station_info_entry) == NULL) || 207 (resp_index >= max_resp_len) ) { 207 // Get the next entry in the dl_list 208 curr_station_info_entry = dl_entry_next(curr_station_info_entry); 209 210 // Break out of the for loop if our response is already reached the max size allowed 211 // by the framework 212 if(resp_index >= max_resp_len) { 208 213 break; 209 214 } … … 212 217 } 213 218 214 // All done - resp_args_32 now contains queue status, res_index is length of response arguments array215 // Copy these values into the response header struct219 // All done - resp_args_32 now contains queue status, res_index is length of response arguments array 220 // Update the response header struct with the length of the response and the number of arguments 216 221 resp_hdr->length += (resp_index * sizeof(resp_args_32[0])); 217 222 resp_hdr->num_args = resp_index; 218 219 223 } 224 break; 220 225 }}} 221 226 … … 225 230 {{{#!python 226 231 227 # Assume n0 is a wlan_exp node object that has already been initialized232 # Assume n0 is a wlan_exp node object that has already been initialized 228 233 q_stat = get_tx_queue_status(n0) 229 234 230 # Print the queue status response235 # Print the queue status response 231 236 if(q_stat): 232 237 print('Tx Queue Status for node {0}'.format(n0.sn_str)) … … 246 251 247 252 '''Write-Only'''[[BR]] 248 A Python script can only write parameters in CPU Low. The script cannot read any data directly from CPU Low. This is by design. The experiments framework C code runs in CPU High. CPU High communicates with CPU Low via the IPC Mailbox. This inter-CPU communication is asynchronous. CPU Low can take an arbitrarily long time to service any new mailbox message from CPU High. The experiments framework cannot block processing in CPU High waiting 253 A Python script can only write parameters in CPU Low. The script cannot read any data directly from CPU Low. This is by design. The experiments framework C code runs in CPU High. CPU High communicates with CPU Low via the IPC Mailbox. This inter-CPU communication is asynchronous. CPU Low can take an arbitrarily long time to service any new mailbox message from CPU High. The experiments framework cannot block processing in CPU High waiting for a response from CPU Low. 249 254 250 255 === Adding Parameters === … … 255 260 We suggest you set the 4 MSB of any new parameters to {{{0xF}}}. We will never use this range for parameters in the reference code. Do this by defining your new parameters with the form: 256 261 {{{ 257 // C code262 // C code 258 263 #define CMD_PARAM_LOW_PARAM_NEW_PARAM0 0xF00000000 259 264 #define CMD_PARAM_LOW_PARAM_NEW_PARAM1 0xF00000001 260 // etc...261 262 # Python code265 // etc... 266 267 # Python code 263 268 CMD_PARAM_LOW_PARAM_NEW_PARAM0 = 0xF00000000 264 269 CMD_PARAM_LOW_PARAM_NEW_PARAM1 = 0xF00000001 265 # etc...270 # etc... 266 271 }}} 267 272 … … 274 279 275 280 CPU Low handles Low Parameter messages in two places. 276 * '''Framework''': the MAC Low Framework handles parameters in the {{{case IPC_MBOX_LOW_PARAM:}}} clause of the IPC mailbox reception handler. This code is responsible for any framework or PHY parameters which are used by any low-level MAC. In the Reference Design code this handler is implemented in the {{{wlan_mac_low_process_ipc_msg()}}} function in [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_framework/wlan_mac_low.c #L544wlan_mac_low.c].277 278 * '''MAC''': the lower MAC handles parameters specific to the MAC application. Each lower-level MAC implements a callback function which processes any MA c-specific parameters. The framework executes this callback for any parameter not handled by the framework itself. The Reference Design code implements these callbacks in {{{wlan_dcf_process_low_param()}}} in [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_dcf/wlan_mac_dcf.c#L1423 wlan_mac_dcf.c] and {{{wlan_nomac_process_low_param()}}} in [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_nomac/wlan_mac_nomac.c#L296wlan_mac_nomac.c].281 * '''Framework''': the MAC Low Framework handles parameters in the {{{case IPC_MBOX_LOW_PARAM:}}} clause of the IPC mailbox reception handler. This code is responsible for any framework or PHY parameters which are used by any low-level MAC. In the Reference Design code this handler is implemented in the {{{wlan_mac_low_process_ipc_msg()}}} function in [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_framework/wlan_mac_low.c?rev=4956#L519 wlan_mac_low.c]. 282 283 * '''MAC''': the lower MAC handles parameters specific to the MAC application. Each lower-level MAC implements a callback function which processes any MAC-specific parameters. The framework executes this callback for any parameter not handled by the framework itself. The Reference Design code implements these callbacks in the {{{process_low_param()}}} function in [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_dcf/wlan_mac_dcf.c?rev=4933#L1428 wlan_mac_dcf.c] and [browser:ReferenceDesigns/w3_802.11/c/wlan_mac_low_nomac/wlan_mac_nomac.c?rev=4932#L300 wlan_mac_nomac.c]. 279 284 280 285 When adding a new parameter you should add a new {{{case}}} to either the framework handler or the MAC code's handler.