[4196] | 1 | /** @file wl_node.c |
---|
| 2 | * @brief WARPLab Framework (Node) |
---|
| 3 | * |
---|
| 4 | * This contains the code for WARPLab Framework. |
---|
| 5 | * |
---|
[4668] | 6 | * @copyright Copyright 2013-2015, Mango Communications. All rights reserved. |
---|
[4196] | 7 | * Distributed under the WARP license (http://warpproject.org/license) |
---|
| 8 | * |
---|
| 9 | * @author Chris Hunter (chunter [at] mangocomm.com) |
---|
| 10 | * @author Patrick Murphy (murphpo [at] mangocomm.com) |
---|
| 11 | * @author Erik Welsh (welsh [at] mangocomm.com) |
---|
| 12 | */ |
---|
[1915] | 13 | |
---|
[4453] | 14 | |
---|
| 15 | |
---|
| 16 | /**********************************************************************************************************************/ |
---|
| 17 | /** |
---|
[4668] | 18 | * @brief Common Functions |
---|
[4453] | 19 | * |
---|
| 20 | **********************************************************************************************************************/ |
---|
| 21 | |
---|
[4196] | 22 | /***************************** Include Files *********************************/ |
---|
[1915] | 23 | |
---|
[4196] | 24 | // Xilinx / Standard library includes |
---|
[1915] | 25 | #include <stdlib.h> |
---|
| 26 | #include <stdio.h> |
---|
[4514] | 27 | #include <string.h> |
---|
| 28 | #include <xparameters.h> |
---|
[4196] | 29 | #include <xio.h> |
---|
| 30 | |
---|
| 31 | // Xilinx Peripheral includes |
---|
[1915] | 32 | #include <xtmrctr.h> |
---|
[2013] | 33 | |
---|
[4196] | 34 | // WARPLab includes |
---|
| 35 | #include "wl_common.h" |
---|
| 36 | #include "wl_node.h" |
---|
| 37 | #include "wl_baseband.h" |
---|
| 38 | #include "wl_interface.h" |
---|
| 39 | #include "wl_transport.h" |
---|
| 40 | #include "wl_user.h" |
---|
| 41 | #include "wl_trigger_manager.h" |
---|
| 42 | |
---|
[2054] | 43 | |
---|
[1915] | 44 | |
---|
[4196] | 45 | /*************************** Constant Definitions ****************************/ |
---|
[1915] | 46 | |
---|
[4668] | 47 | // |
---|
[4673] | 48 | // See wl_common.h for commonly modified control parameters |
---|
[4668] | 49 | // |
---|
[2054] | 50 | |
---|
[4196] | 51 | /*********************** Global Variable Definitions *************************/ |
---|
[2054] | 52 | |
---|
[4292] | 53 | extern int sock_unicast; // UDP socket for unicast traffic to / from the board |
---|
| 54 | extern struct sockaddr_in addr_unicast; |
---|
[4196] | 55 | |
---|
| 56 | |
---|
[4284] | 57 | |
---|
[4292] | 58 | /*************************** Variable Definitions ****************************/ |
---|
[4284] | 59 | |
---|
[4292] | 60 | u16 node; // Node ID |
---|
| 61 | static u8 dram_present; // Is DRAM present and available for use |
---|
| 62 | static u8 configure_buffers; // Configure the baseband buffers |
---|
[4284] | 63 | |
---|
[4668] | 64 | #if ALLOW_ETHERNET_PAUSE |
---|
| 65 | u8 ethernet_pause; // State variable to pause the reception of Ethernet packets |
---|
| 66 | #endif |
---|
[4292] | 67 | |
---|
[4196] | 68 | /*************************** Functions Prototypes ****************************/ |
---|
| 69 | |
---|
| 70 | void blink_node( int num_blinks, int blink_time ); |
---|
[4284] | 71 | |
---|
[4196] | 72 | void set_node_error_status( int status ); |
---|
| 73 | |
---|
| 74 | |
---|
| 75 | /******************************** Functions **********************************/ |
---|
| 76 | |
---|
[4514] | 77 | |
---|
[2159] | 78 | /*****************************************************************************/ |
---|
| 79 | /** |
---|
[4514] | 80 | * Node Transport Processing |
---|
| 81 | * |
---|
| 82 | * This function is how the node processes Ethernet frames from the Transport. This |
---|
| 83 | * function will be used as the transport callback for Host-to-Node messages. Based |
---|
| 84 | * on the Command Group field in the Command header, this function will call the |
---|
| 85 | * appropriate sub-system to continue processing the packet. |
---|
| 86 | * |
---|
| 87 | * @param socket_index - Index of the socket on which message was received |
---|
| 88 | * @param from - Pointer to socket address structure from which message was received |
---|
| 89 | * @param recv_buffer - Pointer to transport buffer with received message |
---|
| 90 | * @param send_buffer - Pointer to transport buffer for a node response to the message |
---|
| 91 | * |
---|
[4668] | 92 | * @return None |
---|
[4514] | 93 | * |
---|
[4668] | 94 | * @note If this packet is a host to node message, then the process_hton_msg_callback |
---|
[4514] | 95 | * is used to further process the packet. This method will strip off the |
---|
[4668] | 96 | * WARP transport header for future packet processing. |
---|
[4514] | 97 | * |
---|
| 98 | *****************************************************************************/ |
---|
| 99 | int node_rx_from_transport(int socket_index, struct sockaddr * from, warp_ip_udp_buffer * recv_buffer, warp_ip_udp_buffer * send_buffer) { |
---|
[1915] | 100 | |
---|
[4668] | 101 | u8 cmd_group; |
---|
| 102 | u32 resp_sent = NO_RESP_SENT; |
---|
| 103 | u32 resp_length; |
---|
[1942] | 104 | |
---|
[4668] | 105 | wl_cmd_resp_hdr * cmd_hdr; |
---|
[4514] | 106 | wl_cmd_resp command; |
---|
[4668] | 107 | wl_cmd_resp_hdr * resp_hdr; |
---|
| 108 | wl_cmd_resp response; |
---|
[2054] | 109 | |
---|
[4668] | 110 | // Initialize the Command/Response structures |
---|
| 111 | cmd_hdr = (wl_cmd_resp_hdr *)(recv_buffer->offset); |
---|
| 112 | command.header = cmd_hdr; |
---|
[4514] | 113 | command.args = (u32 *)((recv_buffer->offset) + sizeof(wl_cmd_resp_hdr)); |
---|
| 114 | command.buffer = (void *)(recv_buffer); |
---|
[1915] | 115 | |
---|
[4514] | 116 | resp_hdr = (wl_cmd_resp_hdr *)(send_buffer->offset); |
---|
| 117 | response.header = resp_hdr; |
---|
| 118 | response.args = (u32 *)((send_buffer->offset) + sizeof(wl_cmd_resp_hdr)); |
---|
| 119 | response.buffer = (void *)(send_buffer); |
---|
[1915] | 120 | |
---|
[4668] | 121 | // Endian swap the command header so future processing can understand it |
---|
[4514] | 122 | cmd_hdr->cmd = Xil_Ntohl(cmd_hdr->cmd); |
---|
| 123 | cmd_hdr->length = Xil_Ntohs(cmd_hdr->length); |
---|
| 124 | cmd_hdr->num_args = Xil_Ntohs(cmd_hdr->num_args); |
---|
[1915] | 125 | |
---|
[4196] | 126 | // Send command to appropriate processing sub-system |
---|
[4668] | 127 | cmd_group = WL_CMD_TO_GRP(cmd_hdr->cmd); |
---|
[4514] | 128 | |
---|
[4668] | 129 | switch(cmd_group){ |
---|
[4783] | 130 | case GROUP_NODE: |
---|
[4668] | 131 | resp_sent = node_process_cmd(socket_index, from, &command, &response); |
---|
| 132 | break; |
---|
[4783] | 133 | case GROUP_TRANSPORT: |
---|
[4668] | 134 | resp_sent = transport_process_cmd(socket_index, from, &command, &response); |
---|
| 135 | break; |
---|
[4783] | 136 | case GROUP_INTERFACE: |
---|
[4668] | 137 | resp_sent = ifc_process_cmd(socket_index, from, &command, &response); |
---|
| 138 | break; |
---|
[4783] | 139 | case GROUP_BASEBAND: |
---|
[4668] | 140 | resp_sent = baseband_process_cmd(socket_index, from, &command, &response); |
---|
| 141 | break; |
---|
[4783] | 142 | case GROUP_TRIGGER_MANAGER: |
---|
[4668] | 143 | resp_sent = trigmngr_process_cmd(socket_index, from, &command, &response); |
---|
| 144 | break; |
---|
[4783] | 145 | case GROUP_USER: |
---|
[4668] | 146 | resp_sent = user_process_cmd(socket_index, from, &command, &response); |
---|
| 147 | break; |
---|
| 148 | default: |
---|
| 149 | wl_printf(WL_PRINT_ERROR, print_type_node, "Unknown command group: %d\n", cmd_group); |
---|
| 150 | break; |
---|
| 151 | } |
---|
[1915] | 152 | |
---|
[4668] | 153 | // Adjust the length of the response to include the response data from the sub-system and the |
---|
| 154 | // response header |
---|
| 155 | // |
---|
| 156 | if((resp_sent == NO_RESP_SENT) || (resp_sent == NODE_NOT_READY)) { |
---|
| 157 | resp_length = (resp_hdr->length + sizeof(wl_cmd_resp_hdr)); |
---|
[4514] | 158 | |
---|
[4668] | 159 | // Keep the length and size of the response in sync since we are adding bytes to the buffer |
---|
| 160 | send_buffer->length += resp_length; |
---|
| 161 | send_buffer->size += resp_length; |
---|
| 162 | } |
---|
[1915] | 163 | |
---|
[4668] | 164 | // Endian swap the response header before returning |
---|
| 165 | resp_hdr->cmd = Xil_Ntohl(resp_hdr->cmd); |
---|
| 166 | resp_hdr->length = Xil_Ntohs(resp_hdr->length); |
---|
| 167 | resp_hdr->num_args = Xil_Ntohs(resp_hdr->num_args); |
---|
[4284] | 168 | |
---|
[4668] | 169 | // Return the status |
---|
| 170 | return resp_sent; |
---|
[1915] | 171 | } |
---|
| 172 | |
---|
[2159] | 173 | |
---|
| 174 | |
---|
| 175 | /*****************************************************************************/ |
---|
| 176 | /** |
---|
[4514] | 177 | * Node Send Early Response |
---|
| 178 | * |
---|
| 179 | * Allows a node to send a response back to the host before the command has |
---|
| 180 | * finished being processed. This is to minimize the latency between commands |
---|
| 181 | * since the node is able to finish processing the command during the time |
---|
| 182 | * it takes to communicate to the host and receive another command. |
---|
| 183 | * |
---|
| 184 | * @param socket_index - Index of the socket on which message was received |
---|
| 185 | * @param to - Pointer to socket address structure to which message will be sent |
---|
| 186 | * @param resp_hdr - Pointer to WARPLab Command / Response header for outgoing message |
---|
| 187 | * @param buffers - Pointer to array of IP/UDP buffers that contain the outgoing message |
---|
| 188 | * @param num_buffers - Number of IP/UDP buffers in the array |
---|
| 189 | * |
---|
[4668] | 190 | * @return None |
---|
[4514] | 191 | * |
---|
[4758] | 192 | * @note This function can only send one buffer at a time and will modify both the |
---|
| 193 | * response header and buffer length to create an appropriate outgoing message. |
---|
[4514] | 194 | * |
---|
| 195 | *****************************************************************************/ |
---|
[4758] | 196 | void node_send_early_resp(int socket_index, void * to, wl_cmd_resp_hdr * resp_hdr, void * buffer) { |
---|
[4668] | 197 | // |
---|
[4758] | 198 | // This function is used to send a response back to the host outside the normal command processing |
---|
| 199 | // (ie the response does not complete the steps in node_rx_from_transport() after distribution |
---|
| 200 | // to the different group processing commands), this method must perform the necessary manipulation |
---|
| 201 | // of the response header and the buffer size so that the message is ready to be sent and then |
---|
| 202 | // restore the contents so that everything is ready to be used if additional responses are required. |
---|
[4668] | 203 | // |
---|
[1915] | 204 | |
---|
[4668] | 205 | // wl_printf(WL_PRINT_DEBUG, print_type_node, "Send early response: cmd = 0x%08x length = %d\n", resp_hdr->cmd, resp_hdr->length); |
---|
[1915] | 206 | |
---|
[4758] | 207 | u32 tmp_cmd; |
---|
| 208 | u16 tmp_length; |
---|
| 209 | u16 tmp_num_args; |
---|
| 210 | u32 tmp_buffer_length; |
---|
| 211 | u32 tmp_buffer_size; |
---|
| 212 | |
---|
| 213 | warp_ip_udp_buffer * buffer_ptr; |
---|
| 214 | u32 resp_length; |
---|
| 215 | |
---|
| 216 | // Cast the buffer pointer so it is easier to use |
---|
| 217 | buffer_ptr = (warp_ip_udp_buffer *) buffer; |
---|
| 218 | |
---|
| 219 | // Get the current values in the buffer so we can restore them after transmission |
---|
| 220 | tmp_cmd = resp_hdr->cmd; |
---|
| 221 | tmp_length = resp_hdr->length; |
---|
| 222 | tmp_num_args = resp_hdr->num_args; |
---|
| 223 | tmp_buffer_length = buffer_ptr->length; |
---|
| 224 | tmp_buffer_size = buffer_ptr->size; |
---|
| 225 | |
---|
| 226 | // Adjust the length of the buffer |
---|
| 227 | resp_length = resp_hdr->length + sizeof(wl_cmd_resp_hdr); |
---|
| 228 | buffer_ptr->length += resp_length; |
---|
| 229 | buffer_ptr->size += resp_length; |
---|
| 230 | |
---|
[4668] | 231 | // Endian swap the response header before before transport sends it |
---|
[4758] | 232 | resp_hdr->cmd = Xil_Ntohl(tmp_cmd); |
---|
| 233 | resp_hdr->length = Xil_Ntohs(tmp_length); |
---|
| 234 | resp_hdr->num_args = Xil_Ntohs(tmp_num_args); |
---|
[1915] | 235 | |
---|
[4668] | 236 | // Send the packet |
---|
[4758] | 237 | transport_send(socket_index, (struct sockaddr *)to, (warp_ip_udp_buffer **)&buffer, 0x1); |
---|
[4284] | 238 | |
---|
[4758] | 239 | // Restore the values in the buffer |
---|
| 240 | resp_hdr->cmd = tmp_cmd; |
---|
| 241 | resp_hdr->length = tmp_length; |
---|
| 242 | resp_hdr->num_args = tmp_num_args; |
---|
| 243 | buffer_ptr->length = tmp_buffer_length; |
---|
| 244 | buffer_ptr->size = tmp_buffer_size; |
---|
[1915] | 245 | } |
---|
| 246 | |
---|
[2159] | 247 | |
---|
| 248 | |
---|
| 249 | /*****************************************************************************/ |
---|
| 250 | /** |
---|
[4668] | 251 | * Global initialization function |
---|
| 252 | * |
---|
| 253 | * Global_initialize is the subset of initialization commands that are safe |
---|
| 254 | * to execute multiple times when a user simply wants to reset stats on the board |
---|
| 255 | * |
---|
| 256 | * @param None. |
---|
| 257 | * |
---|
| 258 | * @return int - Status of the command: |
---|
| 259 | * XST_SUCCESS - Command completed successfully |
---|
| 260 | * XST_FAILURE - There was an error in the command |
---|
| 261 | * |
---|
| 262 | *****************************************************************************/ |
---|
[4453] | 263 | int global_initialize(){ |
---|
[4668] | 264 | int status = XST_SUCCESS; |
---|
[4453] | 265 | |
---|
[4668] | 266 | status = ifc_init(); |
---|
| 267 | if(status != XST_SUCCESS) { |
---|
| 268 | wl_printf(WL_PRINT_ERROR, print_type_node, "Interface initialization error! Exiting\n"); |
---|
| 269 | return XST_FAILURE; |
---|
| 270 | } |
---|
[4453] | 271 | |
---|
[4668] | 272 | status = baseband_init(dram_present, configure_buffers); |
---|
| 273 | if(status != XST_SUCCESS) { |
---|
| 274 | wl_printf(WL_PRINT_ERROR, print_type_node, "Baseband initialization error! Exiting\n"); |
---|
| 275 | return XST_FAILURE; |
---|
| 276 | } else { |
---|
| 277 | configure_buffers = 0; // Only need to configure the buffers once |
---|
| 278 | } |
---|
[4453] | 279 | |
---|
[4668] | 280 | status = user_init(); |
---|
| 281 | if(status != XST_SUCCESS) { |
---|
| 282 | wl_printf(WL_PRINT_ERROR, print_type_node, "User initialization error! Exiting\n"); |
---|
| 283 | return XST_FAILURE; |
---|
| 284 | } |
---|
[4453] | 285 | |
---|
[4668] | 286 | status = trigmngr_init(); |
---|
| 287 | if(status != XST_SUCCESS) { |
---|
| 288 | wl_printf(WL_PRINT_ERROR, print_type_node, "Trigger Manager initialization error! Exiting\n"); |
---|
| 289 | return XST_FAILURE; |
---|
| 290 | } |
---|
| 291 | return status; |
---|
[4453] | 292 | } |
---|
| 293 | |
---|
| 294 | |
---|
| 295 | |
---|
| 296 | |
---|
| 297 | /**********************************************************************************************************************/ |
---|
| 298 | /** |
---|
| 299 | * @brief WARP v3 Specific Functions |
---|
| 300 | * |
---|
| 301 | **********************************************************************************************************************/ |
---|
| 302 | |
---|
| 303 | #ifdef WARP_HW_VER_v3 |
---|
| 304 | |
---|
| 305 | /***************************** Include Files *********************************/ |
---|
| 306 | |
---|
| 307 | #include <w3_userio.h> |
---|
| 308 | #include <w3_clock_controller.h> |
---|
| 309 | #include <w3_iic_eeprom.h> |
---|
| 310 | #include <xil_cache.h> |
---|
| 311 | |
---|
| 312 | #ifdef XPAR_XSYSMON_NUM_INSTANCES |
---|
[4668] | 313 | #include <xsysmon_hw.h> |
---|
[4453] | 314 | #endif |
---|
| 315 | |
---|
| 316 | |
---|
| 317 | /*************************** Constant Definitions ****************************/ |
---|
| 318 | |
---|
| 319 | /*********************** Global Variable Definitions *************************/ |
---|
| 320 | |
---|
| 321 | /*************************** Variable Definitions ****************************/ |
---|
| 322 | |
---|
| 323 | // Hardware LED state |
---|
| 324 | u8 use_leds; |
---|
| 325 | u8 red_led_state; |
---|
| 326 | u8 green_led_state; |
---|
| 327 | |
---|
| 328 | |
---|
| 329 | /*************************** Functions Prototypes ****************************/ |
---|
| 330 | |
---|
| 331 | /******************************** Functions **********************************/ |
---|
| 332 | |
---|
| 333 | /*****************************************************************************/ |
---|
| 334 | /** |
---|
[4514] | 335 | * Process Node Commands |
---|
| 336 | * |
---|
| 337 | * This function is part of the Ethernet processing system and will process the |
---|
| 338 | * various node related commands. |
---|
| 339 | * |
---|
| 340 | * @param socket_index - Index of the socket on which to send message |
---|
| 341 | * @param from - Pointer to socket address structure (struct sockaddr *) where command is from |
---|
| 342 | * @param command - Pointer to WARPLab Command |
---|
| 343 | * @param response - Pointer to WARPLab Response |
---|
| 344 | * |
---|
[4668] | 345 | * @return int - Status of the command: |
---|
| 346 | * NO_RESP_SENT - No response has been sent |
---|
| 347 | * RESP_SENT - A response has been sent |
---|
[4514] | 348 | * |
---|
| 349 | * @note See on-line documentation for more information about the Ethernet |
---|
| 350 | * packet structure for WARPLab: www.warpproject.org |
---|
| 351 | * |
---|
[4668] | 352 | *****************************************************************************/ |
---|
[4514] | 353 | int node_process_cmd(int socket_index, void * from, wl_cmd_resp * command, wl_cmd_resp * response) { |
---|
[1915] | 354 | |
---|
[4668] | 355 | // |
---|
[4514] | 356 | // IMPORTANT ENDIAN NOTES: |
---|
[4668] | 357 | // - command |
---|
| 358 | // - header - Already endian swapped by the framework (safe to access directly) |
---|
| 359 | // - args - Must be endian swapped as necessary by code (framework does not know the contents of the command) |
---|
| 360 | // - response |
---|
| 361 | // - header - Will be endian swapped by the framework (safe to write directly) |
---|
| 362 | // - args - Must be endian swapped as necessary by code (framework does not know the contents of the response) |
---|
| 363 | // |
---|
[2054] | 364 | |
---|
[4668] | 365 | // Standard variables |
---|
[4514] | 366 | u32 resp_sent = NO_RESP_SENT; |
---|
| 367 | |
---|
| 368 | wl_cmd_resp_hdr * cmd_hdr = command->header; |
---|
| 369 | u32 * cmd_args_32 = command->args; |
---|
| 370 | u32 cmd_id = WL_CMD_TO_CMDID(cmd_hdr->cmd); |
---|
| 371 | |
---|
| 372 | wl_cmd_resp_hdr * resp_hdr = response->header; |
---|
| 373 | u32 * resp_args_32 = response->args; |
---|
| 374 | u32 resp_index = 0; |
---|
| 375 | |
---|
| 376 | // Specific command variables |
---|
| 377 | u32 eth_dev_num; |
---|
[4668] | 378 | int status; |
---|
| 379 | int numblinks; |
---|
| 380 | u8 node_ip_addr[IP_ADDR_LEN]; |
---|
| 381 | u8 node_hw_addr[ETH_MAC_ADDR_LEN]; |
---|
[4514] | 382 | |
---|
[4783] | 383 | u32 msg_cmd; |
---|
| 384 | u32 default_response; |
---|
| 385 | |
---|
| 386 | u32 mem_addr; |
---|
| 387 | u32 mem_length; |
---|
| 388 | u32 mem_index; |
---|
| 389 | |
---|
[4668] | 390 | // Set up the response header |
---|
| 391 | resp_hdr->cmd = cmd_hdr->cmd; |
---|
| 392 | resp_hdr->length = 0; |
---|
| 393 | resp_hdr->num_args = 0; |
---|
[4196] | 394 | |
---|
[4668] | 395 | // Get the Ethernet device number of the socket |
---|
| 396 | eth_dev_num = socket_get_eth_dev_num(socket_index); |
---|
[4514] | 397 | |
---|
[4668] | 398 | // Populate the IP / MAC addresses of the Ethernet device |
---|
| 399 | eth_get_ip_addr(eth_dev_num, (u8 *)&node_ip_addr); |
---|
| 400 | eth_get_hw_addr(eth_dev_num, (u8 *)&node_hw_addr); |
---|
[2054] | 401 | |
---|
[4196] | 402 | // Process the command |
---|
[4668] | 403 | switch(cmd_id){ |
---|
[2054] | 404 | |
---|
[4196] | 405 | //--------------------------------------------------------------------- |
---|
[4783] | 406 | case CMDID_NODE_INITIALIZE: |
---|
[2054] | 407 | |
---|
[4668] | 408 | // Set the decimal point of the rigth hex display |
---|
| 409 | userio_write_hexdisp_right(USERIO_BASEADDR, (userio_read_hexdisp_right( USERIO_BASEADDR ) | W3_USERIO_HEXDISP_DP ) ); |
---|
[4196] | 410 | |
---|
[4668] | 411 | // Initialize all the sub-systems of the node. |
---|
| 412 | // NOTE: The error condition is the same as during main() |
---|
| 413 | // |
---|
| 414 | status = global_initialize(); |
---|
[1915] | 415 | |
---|
[4668] | 416 | if(status != XST_SUCCESS) { |
---|
| 417 | wl_printf(WL_PRINT_ERROR, print_type_node, "Error in global_initialize()! Exiting...\n"); |
---|
| 418 | set_node_error_status(0x2); // Set user IO |
---|
| 419 | blink_node(0, 250000); // Infinite blink |
---|
| 420 | } |
---|
| 421 | break; |
---|
[4196] | 422 | |
---|
[1915] | 423 | |
---|
[4668] | 424 | //--------------------------------------------------------------------- |
---|
[4783] | 425 | case CMDID_NODE_INFO: |
---|
[1915] | 426 | |
---|
[4668] | 427 | // Send all node information |
---|
| 428 | // NOTE: This must match the expectations of the host |
---|
| 429 | |
---|
| 430 | resp_args_32[resp_index++] = Xil_Htonl(w3_eeprom_readSerialNum(EEPROM_BASEADDR)); |
---|
| 431 | resp_args_32[resp_index++] = Xil_Htonl(userio_read_fpga_dna_msb(USERIO_BASEADDR)); |
---|
| 432 | resp_args_32[resp_index++] = Xil_Htonl(userio_read_fpga_dna_lsb(USERIO_BASEADDR)); |
---|
| 433 | resp_args_32[resp_index++] = Xil_Htonl( (node_hw_addr[0] << 8) | node_hw_addr[1] ); |
---|
| 434 | resp_args_32[resp_index++] = Xil_Htonl( (node_hw_addr[2] << 24) | (node_hw_addr[3] << 16) | (node_hw_addr[4] << 8) | node_hw_addr[5] ); |
---|
| 435 | resp_args_32[resp_index++] = Xil_Htonl((3 << 24)|(WARPLAB_VER_MAJOR << 16)|(WARPLAB_VER_MINOR << 8)|(WARPLAB_VER_REV)); |
---|
| 436 | resp_args_32[resp_index++] = Xil_Htonl((wl_bb_get_supported_tx_length() + 1)); |
---|
| 437 | resp_args_32[resp_index++] = Xil_Htonl((wl_bb_get_supported_rx_length() + 1)); |
---|
| 438 | resp_args_32[resp_index++] = Xil_Htonl((wl_bb_get_tx_length() + 1)); |
---|
| 439 | resp_args_32[resp_index++] = Xil_Htonl((wl_bb_get_rx_length() + 1)); |
---|
[4783] | 440 | resp_args_32[resp_index++] = Xil_Htonl(trigger_proc_get_core_info()); |
---|
[4668] | 441 | resp_args_32[resp_index++] = Xil_Htonl(1); // num_interfaceGroups |
---|
| 442 | |
---|
| 443 | // Set the number of interfaces |
---|
[4196] | 444 | #if WARPLAB_CONFIG_4RF |
---|
[4668] | 445 | resp_args_32[resp_index++] = Xil_Htonl(4); |
---|
[4196] | 446 | #else |
---|
[4668] | 447 | resp_args_32[resp_index++] = Xil_Htonl(2); |
---|
[4196] | 448 | #endif |
---|
[1957] | 449 | |
---|
[4668] | 450 | resp_hdr->length += (resp_index * sizeof(resp_args_32)); |
---|
| 451 | resp_hdr->num_args = resp_index; |
---|
| 452 | break; |
---|
[1915] | 453 | |
---|
[4196] | 454 | |
---|
[4668] | 455 | //--------------------------------------------------------------------- |
---|
[4783] | 456 | case CMDID_NODE_IDENTIFY: |
---|
[1915] | 457 | |
---|
[4668] | 458 | // Send the response early so that M-Code does not hang waiting for the node to stop blinking |
---|
| 459 | // |
---|
| 460 | // NOTE: The host must wait the appropriate amount of time (see below) to send another |
---|
| 461 | // command. Otherwise, the node will possibly cause a transport timeout given that it |
---|
| 462 | // is still busy with this command and will ignore subsequent commands until it is done |
---|
| 463 | // with this command. |
---|
| 464 | // |
---|
[4758] | 465 | node_send_early_resp(socket_index, from, response->header, response->buffer); |
---|
[2003] | 466 | |
---|
[4668] | 467 | // Set LED initial state: Green = "ALL OFF"; Red = "ALL ON" |
---|
| 468 | userio_write_leds_green(USERIO_BASEADDR, 0x0); |
---|
| 469 | userio_write_leds_red(USERIO_BASEADDR, 0xF); |
---|
[4196] | 470 | |
---|
[4668] | 471 | // Currently, this code will toggle the Red and Green LEDs for "numblinks" times and pause for 0.1 |
---|
| 472 | // seconds between each loop. We have chosen the magic number of 10 "blinks", which results in this |
---|
| 473 | // command taking roughly 1 second. The reason for this choice is: 1) a second is long enough to |
---|
| 474 | // easily see which node is blinking but not overly long; 2) currently the transport timeout is 1 |
---|
| 475 | // second. By making this command roughly equivalent to the transport timeout, we limit the |
---|
| 476 | // probability that the host will error out if it doesn't wait after the 'identify' command to send |
---|
| 477 | // the next command due to the fact that the transport retransmits commands once after a timeout. |
---|
| 478 | // |
---|
| 479 | for (numblinks = 0; numblinks < 10; numblinks++) { |
---|
| 480 | userio_toggle_leds_red(USERIO_BASEADDR, 0xF); |
---|
| 481 | userio_toggle_leds_green(USERIO_BASEADDR, 0xF); |
---|
| 482 | usleep(100000); |
---|
| 483 | } |
---|
[2054] | 484 | |
---|
[4668] | 485 | // Set LEDs back to "ALL OFF" |
---|
| 486 | userio_write_leds_red(USERIO_BASEADDR, 0x0); |
---|
| 487 | userio_write_leds_green(USERIO_BASEADDR, 0x0); |
---|
| 488 | |
---|
| 489 | // Tell the transport that the command has already sent a response |
---|
| 490 | resp_sent = RESP_SENT; |
---|
| 491 | break; |
---|
| 492 | |
---|
| 493 | |
---|
| 494 | //--------------------------------------------------------------------- |
---|
[4783] | 495 | case CMDID_NODE_TEMPERATURE: |
---|
[4668] | 496 | |
---|
[4196] | 497 | #ifdef XPAR_XSYSMON_NUM_INSTANCES |
---|
[4668] | 498 | resp_args_32[resp_index++] = Xil_Htonl(XSysMon_ReadReg(SYSMON_BASEADDR, XSM_TEMP_OFFSET)); |
---|
| 499 | resp_args_32[resp_index++] = Xil_Htonl(XSysMon_ReadReg(SYSMON_BASEADDR, XSM_MIN_TEMP_OFFSET)); |
---|
| 500 | resp_args_32[resp_index++] = Xil_Htonl(XSysMon_ReadReg(SYSMON_BASEADDR, XSM_MAX_TEMP_OFFSET)); |
---|
[4196] | 501 | #else |
---|
[4284] | 502 | resp_args_32[resp_index++] = 0; |
---|
| 503 | resp_args_32[resp_index++] = 0; |
---|
| 504 | resp_args_32[resp_index++] = 0; |
---|
[4196] | 505 | #endif |
---|
[2054] | 506 | |
---|
[4668] | 507 | resp_hdr->length += (resp_index * sizeof(resp_args_32)); |
---|
| 508 | resp_hdr->num_args = resp_index; |
---|
| 509 | break; |
---|
[2013] | 510 | |
---|
[4196] | 511 | |
---|
[4668] | 512 | //--------------------------------------------------------------------- |
---|
[4783] | 513 | case CMDID_NODE_CONFIG_SETUP: |
---|
[2029] | 514 | // NODE_CONFIG_SETUP Packet Format: |
---|
[4284] | 515 | // - Note: All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl() |
---|
[2026] | 516 | // |
---|
[4284] | 517 | // - cmd_args_32[0] - Serial Number |
---|
| 518 | // - cmd_args_32[1] - Node ID |
---|
| 519 | // - cmd_args_32[2] - IP Address |
---|
[4453] | 520 | // |
---|
[4668] | 521 | // NOTE: This command will only execute on the node if it is in the "Network Reset" state |
---|
| 522 | // (ie the node is set to 0xFFFF). |
---|
| 523 | // |
---|
| 524 | if (node == 0xFFFF) { |
---|
| 525 | |
---|
[2026] | 526 | // Only update the parameters if the serial numbers match |
---|
[4668] | 527 | if (w3_eeprom_readSerialNum(EEPROM_BASEADDR) == Xil_Ntohl(cmd_args_32[0])) { |
---|
[2026] | 528 | |
---|
[4284] | 529 | node = Xil_Ntohl(cmd_args_32[1]) & 0xFFFF; |
---|
[2026] | 530 | |
---|
[4196] | 531 | wl_printf(WL_PRINT_NONE, NULL, " New Node ID : %d \n", node); |
---|
[4453] | 532 | |
---|
[4668] | 533 | // Set the hex display to the new Node ID |
---|
| 534 | userio_write_control(USERIO_BASEADDR, (userio_read_control(USERIO_BASEADDR) | (W3_USERIO_HEXDISP_L_MAPMODE | W3_USERIO_HEXDISP_R_MAPMODE))); |
---|
| 535 | userio_write_hexdisp_left(USERIO_BASEADDR, (node / 10)); |
---|
| 536 | userio_write_hexdisp_right(USERIO_BASEADDR, (node % 10)); |
---|
[2026] | 537 | |
---|
[4668] | 538 | // Get the new IP address |
---|
| 539 | node_ip_addr[0] = (Xil_Ntohl(cmd_args_32[2]) >> 24) & 0xFF; |
---|
| 540 | node_ip_addr[1] = (Xil_Ntohl(cmd_args_32[2]) >> 16) & 0xFF; |
---|
| 541 | node_ip_addr[2] = (Xil_Ntohl(cmd_args_32[2]) >> 8) & 0xFF; |
---|
| 542 | node_ip_addr[3] = (Xil_Ntohl(cmd_args_32[2]) ) & 0xFF; |
---|
| 543 | |
---|
[4196] | 544 | wl_printf(WL_PRINT_NONE, NULL, " New IP Address: %d.%d.%d.%d \n", node_ip_addr[0], node_ip_addr[1],node_ip_addr[2],node_ip_addr[3]); |
---|
[2026] | 545 | |
---|
[4668] | 546 | // Configure the transport with the node ID and IP address |
---|
[4514] | 547 | eth_set_ip_addr(eth_dev_num, node_ip_addr); |
---|
[2026] | 548 | |
---|
[4292] | 549 | status = transport_config_sockets(eth_dev_num, (NODE_UDP_UNICAST_PORT_BASE + node), NODE_UDP_MCAST_BASE); |
---|
[2054] | 550 | |
---|
[4292] | 551 | if(status != XST_SUCCESS) { |
---|
[4668] | 552 | wl_printf(WL_PRINT_ERROR, print_type_node, "Error binding transport...\n"); |
---|
| 553 | } |
---|
[2026] | 554 | |
---|
| 555 | } else { |
---|
[4668] | 556 | wl_printf(WL_PRINT_INFO, print_type_node, "NODE_IP_SETUP Packet with Serial Number %d ignored. My serial number is %d \n", Xil_Ntohl(cmd_args_32[0]), w3_eeprom_readSerialNum(EEPROM_BASEADDR)); |
---|
[2026] | 557 | } |
---|
| 558 | } |
---|
[4668] | 559 | break; |
---|
[2026] | 560 | |
---|
[4196] | 561 | |
---|
[4668] | 562 | //--------------------------------------------------------------------- |
---|
[4783] | 563 | case CMDID_NODE_CONFIG_RESET: |
---|
[2029] | 564 | // NODE_CONFIG_RESET Packet Format: |
---|
[4284] | 565 | // - Note: All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl() |
---|
[2026] | 566 | // |
---|
[4284] | 567 | // - cmd_args_32[0] - Serial Number |
---|
[4453] | 568 | // |
---|
| 569 | |
---|
[2026] | 570 | // Send the response early so that M-Code does not hang when IP address changes |
---|
[4758] | 571 | node_send_early_resp(socket_index, from, response->header, response->buffer); |
---|
[4453] | 572 | |
---|
[2026] | 573 | // Only update the parameters if the serial numbers match |
---|
[4668] | 574 | if (w3_eeprom_readSerialNum(EEPROM_BASEADDR) == Xil_Ntohl(cmd_args_32[0])) { |
---|
[2026] | 575 | |
---|
| 576 | // Reset node to 0xFFFF |
---|
| 577 | node = 0xFFFF; |
---|
| 578 | |
---|
[4196] | 579 | wl_printf(WL_PRINT_NONE, NULL, "\n!!! Reseting Network Configuration !!! \n\n"); |
---|
[4453] | 580 | |
---|
[2026] | 581 | // Reset transport; This will update the IP Address back to default and rebind the sockets |
---|
[4668] | 582 | transport_get_hw_info(eth_dev_num, node_ip_addr, node_hw_addr); |
---|
| 583 | |
---|
| 584 | eth_set_ip_addr(eth_dev_num, node_ip_addr); |
---|
| 585 | |
---|
[4292] | 586 | status = transport_config_sockets(eth_dev_num, NODE_UDP_UNICAST_PORT_BASE, NODE_UDP_MCAST_BASE); |
---|
[2026] | 587 | |
---|
[4292] | 588 | if(status != XST_SUCCESS) { |
---|
[4668] | 589 | wl_printf(WL_PRINT_ERROR, print_type_node, "Error binding transport...\n"); |
---|
| 590 | } |
---|
[4292] | 591 | |
---|
[2026] | 592 | // Update User IO |
---|
[4196] | 593 | wl_printf(WL_PRINT_NONE, NULL, "\n!!! Waiting for Network Configuration via Matlab !!! \n\n"); |
---|
[4453] | 594 | |
---|
[4668] | 595 | // Turn off hex mapping; set the center LED: "--" |
---|
| 596 | // NOTE: The hex mapping will be re-enabled when the broadcast packet is processed to set the node ID |
---|
| 597 | // |
---|
| 598 | userio_write_control(USERIO_BASEADDR, (userio_read_control(USERIO_BASEADDR) & (~(W3_USERIO_HEXDISP_L_MAPMODE | W3_USERIO_HEXDISP_R_MAPMODE)))); |
---|
| 599 | userio_write_hexdisp_left(USERIO_BASEADDR, 0x40); |
---|
| 600 | userio_write_hexdisp_right(USERIO_BASEADDR, 0x40); |
---|
[4453] | 601 | |
---|
[2026] | 602 | } else { |
---|
[4668] | 603 | wl_printf(WL_PRINT_INFO, print_type_node, "NODE_IP_RESET Packet with Serial Number %d ignored. My serial number is %d \n", Xil_Ntohl(cmd_args_32[0]), w3_eeprom_readSerialNum(EEPROM_BASEADDR)); |
---|
[2026] | 604 | } |
---|
| 605 | |
---|
[4668] | 606 | // Tell the transport that the command has already sent a response |
---|
| 607 | resp_sent = RESP_SENT; |
---|
| 608 | break; |
---|
[4196] | 609 | |
---|
[1942] | 610 | |
---|
[4668] | 611 | //--------------------------------------------------------------------- |
---|
[4783] | 612 | case CMDID_NODE_MEM_RW: |
---|
| 613 | // Read / write arbitrary memory location |
---|
| 614 | // |
---|
| 615 | // Write Message format: |
---|
| 616 | // cmd_args_32[0] Command == CMD_PARAM_WRITE_VAL |
---|
| 617 | // cmd_args_32[1] Address |
---|
| 618 | // cmd_args_32[2] Length (number of u32 words to write) |
---|
| 619 | // cmd_args_32[3:] Values to write (integral number of u32 words) |
---|
| 620 | // Response format: |
---|
| 621 | // resp_args_32[0] Status |
---|
| 622 | // |
---|
| 623 | // Read Message format: |
---|
| 624 | // cmd_args_32[0] Command == CMD_PARAM_READ_VAL |
---|
| 625 | // cmd_args_32[1] Address |
---|
| 626 | // cmd_args_32[2] Length (number of u32 words to read) |
---|
| 627 | // Response format: |
---|
| 628 | // resp_args_32[0] Status |
---|
| 629 | // resp_args_32[1] Length (number of u32 values) |
---|
| 630 | // resp_args_32[2:] Memory values (length u32 values) |
---|
| 631 | // |
---|
| 632 | msg_cmd = Xil_Ntohl(cmd_args_32[0]); |
---|
| 633 | mem_addr = Xil_Ntohl(cmd_args_32[1]); |
---|
| 634 | mem_length = Xil_Ntohl(cmd_args_32[2]); |
---|
| 635 | status = CMD_PARAM_SUCCESS; |
---|
| 636 | default_response = WL_TRUE; |
---|
| 637 | |
---|
| 638 | switch (msg_cmd) { |
---|
| 639 | case CMD_PARAM_WRITE_VAL: |
---|
| 640 | wl_printf(WL_PRINT_INFO, print_type_node, "Write CPU High Mem\n"); |
---|
| 641 | wl_printf(WL_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); |
---|
| 642 | wl_printf(WL_PRINT_INFO, print_type_node, " Len: %d\n", mem_length); |
---|
| 643 | |
---|
| 644 | // Don't bother if length is clearly bogus |
---|
| 645 | if (mem_length < CMD_PARAM_NODE_MEM_RW_MAX_BYTES) { |
---|
| 646 | for (mem_index = 0; mem_index < mem_length; mem_index++) { |
---|
| 647 | wl_printf(WL_PRINT_INFO, print_type_node, " W[%2d]: 0x%08x\n", mem_index, Xil_Ntohl(cmd_args_32[3 + mem_index])); |
---|
| 648 | Xil_Out32((mem_addr + (mem_index * sizeof(u32))), Xil_Ntohl(cmd_args_32[3 + mem_index])); |
---|
| 649 | } |
---|
| 650 | } else { |
---|
| 651 | wl_printf(WL_PRINT_ERROR, print_type_node, "NODE_MEM_RW write longer than %d bytes\n", CMD_PARAM_NODE_MEM_RW_MAX_BYTES); |
---|
| 652 | status = CMD_PARAM_ERROR; |
---|
| 653 | } |
---|
| 654 | break; |
---|
| 655 | |
---|
| 656 | case CMD_PARAM_READ_VAL: |
---|
| 657 | wl_printf(WL_PRINT_INFO, print_type_node, "Read CPU High Mem:\n"); |
---|
| 658 | wl_printf(WL_PRINT_INFO, print_type_node, " Addr: 0x%08x\n", mem_addr); |
---|
| 659 | wl_printf(WL_PRINT_INFO, print_type_node, " Len: %d\n", mem_length); |
---|
| 660 | |
---|
| 661 | // Add payload to response |
---|
| 662 | if(mem_length < CMD_PARAM_NODE_MEM_RW_MAX_BYTES) { |
---|
| 663 | |
---|
| 664 | // Don't set the default response / Don't send any response |
---|
| 665 | default_response = WL_FALSE; |
---|
| 666 | |
---|
| 667 | // Add length argument to response |
---|
| 668 | resp_args_32[resp_index++] = Xil_Htonl(status); |
---|
| 669 | resp_args_32[resp_index++] = Xil_Htonl(mem_length); |
---|
| 670 | |
---|
| 671 | resp_hdr->length += (resp_index * sizeof(resp_args_32)); |
---|
| 672 | resp_hdr->num_args = resp_index; |
---|
| 673 | |
---|
| 674 | for (mem_index = 0; mem_index < mem_length; mem_index++) { |
---|
| 675 | resp_args_32[resp_index + mem_index] = Xil_Ntohl(Xil_In32((void*)(mem_addr) + (mem_index * sizeof(u32)))); |
---|
| 676 | } |
---|
| 677 | |
---|
| 678 | // Update response header with payload length |
---|
| 679 | resp_hdr->length += (mem_length * sizeof(u32)); |
---|
| 680 | resp_hdr->num_args += mem_length; |
---|
| 681 | } else { |
---|
| 682 | wl_printf(WL_PRINT_ERROR, print_type_node, "NODE_MEM_RW read longer than %d bytes\n", CMD_PARAM_NODE_MEM_RW_MAX_BYTES); |
---|
| 683 | status = CMD_PARAM_ERROR; |
---|
| 684 | } |
---|
| 685 | break; |
---|
| 686 | |
---|
| 687 | default: |
---|
| 688 | wl_printf(WL_PRINT_ERROR, print_type_node, "Unknown command for 0x%6x: %d\n", cmd_id, msg_cmd); |
---|
| 689 | status = CMD_PARAM_ERROR; |
---|
| 690 | break; |
---|
| 691 | } |
---|
| 692 | |
---|
| 693 | if (default_response == WL_TRUE) { |
---|
| 694 | // Send default response |
---|
| 695 | resp_args_32[resp_index++] = Xil_Htonl(status); |
---|
| 696 | |
---|
| 697 | resp_hdr->length += (resp_index * sizeof(resp_args_32)); |
---|
| 698 | resp_hdr->num_args = resp_index; |
---|
| 699 | } |
---|
| 700 | break; |
---|
| 701 | |
---|
| 702 | |
---|
| 703 | //--------------------------------------------------------------------- |
---|
[4668] | 704 | default: |
---|
| 705 | wl_printf(WL_PRINT_ERROR, print_type_node, "Unknown node command: %d\n", cmd_id); |
---|
| 706 | break; |
---|
| 707 | } |
---|
| 708 | |
---|
| 709 | return resp_sent; |
---|
[1915] | 710 | } |
---|
| 711 | |
---|
[2159] | 712 | |
---|
| 713 | |
---|
| 714 | /*****************************************************************************/ |
---|
| 715 | /** |
---|
[4668] | 716 | * Node Clock Initialization Function |
---|
| 717 | * |
---|
| 718 | * This function will initialize the clock module |
---|
| 719 | * |
---|
| 720 | * @param None |
---|
| 721 | * |
---|
| 722 | * @return int - Status of the command: |
---|
| 723 | * XST_SUCCESS - Command completed successfully |
---|
| 724 | * XST_FAILURE - There was an error in the command |
---|
| 725 | * |
---|
| 726 | * @note This function works with w3_clock_controller v4.00.a |
---|
| 727 | * |
---|
| 728 | *****************************************************************************/ |
---|
[4308] | 729 | int node_clk_initialize() { |
---|
[4668] | 730 | int status = XST_SUCCESS; |
---|
| 731 | u32 clkmod_status; |
---|
[1915] | 732 | |
---|
[4668] | 733 | // Initialize w3_clock_controller hardware and AD9512 buffers |
---|
| 734 | // NOTE: The clock initialization will set the clock divider to 2 (for 40MHz clock) to RF A/B AD9963's |
---|
| 735 | status = clk_init(CLK_BASEADDR, 2); |
---|
| 736 | if(status != XST_SUCCESS) { |
---|
| 737 | wl_printf(WL_PRINT_ERROR, print_type_node, "Clock initialization failed with error code: %d\n", status); |
---|
| 738 | return XST_FAILURE; |
---|
| 739 | } |
---|
[1915] | 740 | |
---|
[4668] | 741 | // Check for a clock module and configure clock inputs, outputs and dividers as needed |
---|
| 742 | clkmod_status = clk_config_read_clkmod_status(CLK_BASEADDR); |
---|
[1915] | 743 | |
---|
[4668] | 744 | switch(clkmod_status & CM_STATUS_SW) { |
---|
| 745 | case CM_STATUS_DET_NOCM: |
---|
| 746 | case CM_STATUS_DET_CMPLL_BYPASS: |
---|
| 747 | // No clock module - default config from HDL/driver is good as-is |
---|
| 748 | wl_printf(WL_PRINT_NONE, NULL, "No clock module detected - selecting on-board clocks\n\n"); |
---|
| 749 | break; |
---|
[1915] | 750 | |
---|
[4668] | 751 | case CM_STATUS_DET_CMMMCX_CFG_A: |
---|
| 752 | // CM-MMCX config A: |
---|
| 753 | // Samp clk: on-board, RF clk: on-board |
---|
| 754 | // Samp MMCX output: 80MHz, RF MMCX output: 80MHz |
---|
| 755 | wl_printf(WL_PRINT_NONE, NULL, "CM-MMCX Config A Detected:\n"); |
---|
| 756 | wl_printf(WL_PRINT_NONE, NULL, " RF: On-board\n Samp: On-board\n MMCX Outputs: Enabled\n\n"); |
---|
[4196] | 757 | |
---|
[4668] | 758 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
| 759 | clk_config_dividers(CLK_BASEADDR, 1, CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR); |
---|
| 760 | break; |
---|
[4308] | 761 | |
---|
[4668] | 762 | case CM_STATUS_DET_CMMMCX_CFG_B: |
---|
| 763 | // CM-MMCX config B: |
---|
| 764 | // Samp clk: off-board, RF clk: off-board |
---|
| 765 | // Samp MMCX output: 80MHz, RF MMCX output: 80MHz |
---|
| 766 | wl_printf(WL_PRINT_NONE, NULL, "CM-MMCX Config B Detected:\n"); |
---|
| 767 | wl_printf(WL_PRINT_NONE, NULL, " RF: Off-board\n Samp: Off-board\n MMCX Outputs: Enabled\n\n"); |
---|
[4308] | 768 | |
---|
[4668] | 769 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
| 770 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
| 771 | clk_config_dividers(CLK_BASEADDR, 1, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
| 772 | break; |
---|
[4308] | 773 | |
---|
[4668] | 774 | case CM_STATUS_DET_CMMMCX_CFG_C: |
---|
| 775 | // CM-MMCX config C: |
---|
| 776 | // Samp clk: off-board, RF clk: off-board |
---|
| 777 | // Samp MMCX output: Off, RF MMCX output: Off |
---|
| 778 | wl_printf(WL_PRINT_NONE, NULL, "CM-MMCX Config C Detected:\n"); |
---|
| 779 | wl_printf(WL_PRINT_NONE, NULL, " RF: Off-board\n Samp: Off-board\n MMCX Outputs: Disabled\n\n"); |
---|
[4308] | 780 | |
---|
[4668] | 781 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
| 782 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_OFF, (CLK_SAMP_OUTSEL_CLKMODHDR | CLK_RFREF_OUTSEL_CLKMODHDR)); |
---|
| 783 | break; |
---|
[4308] | 784 | |
---|
[4668] | 785 | case CM_STATUS_DET_CMPLL_CFG_A: |
---|
| 786 | // CM-PLL config A: |
---|
| 787 | // Samp clk: clock module PLL |
---|
| 788 | // RF clk: on-board |
---|
| 789 | wl_printf(WL_PRINT_NONE, NULL, "CM-PLL Config A Detected:\n"); |
---|
| 790 | wl_printf(WL_PRINT_NONE, NULL, " RF: On-board\n Samp: clock module PLL\n"); |
---|
[4308] | 791 | |
---|
[4668] | 792 | // No changes from configuration applied by HDL and clk_init() |
---|
| 793 | break; |
---|
[4308] | 794 | |
---|
[4668] | 795 | case CM_STATUS_DET_CMPLL_CFG_B: |
---|
| 796 | // CM-PLL config B: |
---|
| 797 | // Samp clk: clock module PLL |
---|
| 798 | // RF clk: clock module PLL |
---|
| 799 | wl_printf(WL_PRINT_NONE, NULL, "CM-PLL Config B Detected:\n"); |
---|
| 800 | wl_printf(WL_PRINT_NONE, NULL, " RF: clock module PLL\n Samp: clock module PLL\n"); |
---|
[4308] | 801 | |
---|
[4668] | 802 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
| 803 | break; |
---|
[4308] | 804 | |
---|
[4668] | 805 | case CM_STATUS_DET_CMPLL_CFG_C: |
---|
| 806 | // CM-PLL config C: |
---|
| 807 | // Samp clk: clock module PLL |
---|
| 808 | // RF clk: clock module PLL |
---|
| 809 | wl_printf(WL_PRINT_NONE, NULL, "CM-PLL Config C Detected:\n"); |
---|
| 810 | wl_printf(WL_PRINT_NONE, NULL, " RF: clock module PLL\n Samp: clock module PLL\n"); |
---|
[4308] | 811 | |
---|
[4668] | 812 | clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD); |
---|
| 813 | break; |
---|
[4308] | 814 | |
---|
[4668] | 815 | default: |
---|
| 816 | // Should be impossible |
---|
| 817 | wl_printf(WL_PRINT_ERROR, print_type_node, "ERROR: Invalid clock module switch settings! (0x%08x)\n", clkmod_status); |
---|
| 818 | return XST_FAILURE; |
---|
| 819 | break; |
---|
| 820 | } |
---|
[4308] | 821 | |
---|
[1915] | 822 | #if WARPLAB_CONFIG_4RF |
---|
[4668] | 823 | // Turn on clocks to FMC |
---|
| 824 | clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_FMC | CLK_RFREF_OUTSEL_FMC)); |
---|
[1915] | 825 | |
---|
[4668] | 826 | // FMC samp clock divider = 2 (40MHz sampling reference, same as on-board AD9963 ref clk) |
---|
| 827 | clk_config_dividers(CLK_BASEADDR, 2, CLK_SAMP_OUTSEL_FMC); |
---|
[1915] | 828 | |
---|
[4668] | 829 | // FMC RF ref clock divider = 2 (40MHz RF reference, same as on-board MAX2829 ref clk) |
---|
| 830 | clk_config_dividers(CLK_BASEADDR, 2, CLK_RFREF_OUTSEL_FMC); |
---|
[1915] | 831 | #endif |
---|
| 832 | |
---|
[4668] | 833 | return status; |
---|
[4308] | 834 | } |
---|
| 835 | |
---|
| 836 | |
---|
[4453] | 837 | |
---|
[4308] | 838 | /*****************************************************************************/ |
---|
| 839 | /** |
---|
[4668] | 840 | * Node Initialization Function |
---|
| 841 | * |
---|
| 842 | * This function will initialize many aspects of the node. |
---|
| 843 | * |
---|
| 844 | * @param None. |
---|
| 845 | * |
---|
| 846 | * @return int - Status of the command: |
---|
| 847 | * XST_SUCCESS - Command completed successfully |
---|
| 848 | * XST_FAILURE - There was an error in the command |
---|
| 849 | * |
---|
| 850 | *****************************************************************************/ |
---|
[4308] | 851 | int node_init(){ |
---|
[4668] | 852 | int status = XST_SUCCESS; |
---|
| 853 | u64 timestamp; |
---|
[4308] | 854 | |
---|
[4668] | 855 | // Configure Microblaze |
---|
| 856 | microblaze_enable_exceptions(); |
---|
| 857 | Xil_DCacheDisable(); |
---|
| 858 | Xil_ICacheDisable(); |
---|
[4308] | 859 | |
---|
[4668] | 860 | // Initialize hardware components |
---|
| 861 | wl_timer_initialize(); |
---|
| 862 | wl_gpio_debug_initialize(); |
---|
[4308] | 863 | wl_sysmon_initialize(); |
---|
| 864 | wl_uart_initialize(); |
---|
[4668] | 865 | iic_eeprom_init(EEPROM_BASEADDR, 0x64); |
---|
[4308] | 866 | |
---|
[4668] | 867 | // Initialize LED global variables |
---|
| 868 | use_leds = 1; |
---|
[4316] | 869 | red_led_state = 0; |
---|
| 870 | green_led_state = 0; |
---|
| 871 | |
---|
[4668] | 872 | // Initialize the central DMA (CDMA) driver |
---|
| 873 | // NOTE: Need to die if not successful |
---|
| 874 | status = wl_cdma_initialize(); |
---|
[4308] | 875 | if (status != XST_SUCCESS) { |
---|
[4668] | 876 | return XST_FAILURE; |
---|
| 877 | } |
---|
[4308] | 878 | |
---|
| 879 | // Initialize the hardware clocking |
---|
| 880 | status = node_clk_initialize(); |
---|
| 881 | if (status != XST_SUCCESS) { |
---|
[4668] | 882 | return XST_FAILURE; |
---|
| 883 | } |
---|
[4308] | 884 | |
---|
[4668] | 885 | // Populate the Node ID |
---|
| 886 | node = userio_read_inputs(USERIO_BASEADDR) & W3_USERIO_DIPSW; |
---|
[2026] | 887 | |
---|
[4668] | 888 | // If the node has dip switch value of 0xF, then set the node to 0xFFFF |
---|
[2026] | 889 | if ( node == 0xF ) { |
---|
| 890 | node = 0xFFFF; |
---|
| 891 | } else { |
---|
| 892 | userio_write_hexdisp_left(USERIO_BASEADDR, ((node+1)/10) ); |
---|
| 893 | userio_write_hexdisp_right(USERIO_BASEADDR, (node+1)%10); |
---|
| 894 | } |
---|
[1915] | 895 | |
---|
[4196] | 896 | // Check the WARPLab version |
---|
[5627] | 897 | if( (wl_get_design_ver()&0xFFFF00) != ((REQ_WARPLAB_HW_VER)&0xFFFF00) ){ |
---|
[4668] | 898 | wl_printf(WL_PRINT_ERROR, print_type_node, "HW/SW Version Mismatch! Expected HW Ver: 0x%x -- Actual HW Ver: 0x%x\n\n", (REQ_WARPLAB_HW_VER), wl_get_design_ver()); |
---|
| 899 | return XST_FAILURE; |
---|
| 900 | } |
---|
[2009] | 901 | |
---|
[4308] | 902 | // Print node information |
---|
[4668] | 903 | wl_printf(WL_PRINT_NONE, print_type_node, "W3-a-%05d using Node ID: %d\n", w3_eeprom_readSerialNum(EEPROM_BASEADDR), node); |
---|
[4308] | 904 | |
---|
[4668] | 905 | // Test to see if DRAM SODIMM is connected to board |
---|
| 906 | timestamp = get_usec_timestamp(); |
---|
[4387] | 907 | |
---|
[4668] | 908 | while((get_usec_timestamp() - timestamp) < 100000){ |
---|
| 909 | if(wl_get_dram_init_done() == 1){ |
---|
| 910 | wl_printf(WL_PRINT_NONE, NULL, "DRAM SODIMM detected ... \n"); |
---|
[4387] | 911 | |
---|
[4668] | 912 | if(ddr_sodim_memory_test() == XST_SUCCESS){ |
---|
| 913 | dram_present = 1; |
---|
[4387] | 914 | |
---|
[4668] | 915 | if (CLEAR_DDR_ON_BOOT) { |
---|
| 916 | clear_ddr(WL_VERBOSE); |
---|
| 917 | } else { |
---|
| 918 | wl_printf(WL_PRINT_NONE, NULL, " Contents not cleared\n"); |
---|
| 919 | } |
---|
| 920 | } else { |
---|
| 921 | dram_present = 0; |
---|
| 922 | wl_printf(WL_PRINT_NONE, NULL, " Memory test failed; Will not use DRAM\n"); |
---|
| 923 | } |
---|
| 924 | break; |
---|
| 925 | } |
---|
| 926 | } |
---|
[4387] | 927 | |
---|
[4804] | 928 | if (wl_get_dram_init_done() != 1) { |
---|
| 929 | wl_printf(WL_PRINT_NONE, NULL, "DRAM SODIMM not detected.\n"); |
---|
| 930 | } |
---|
| 931 | |
---|
[4668] | 932 | return status; |
---|
[1915] | 933 | } |
---|
| 934 | |
---|
| 935 | |
---|
[2013] | 936 | |
---|
[2159] | 937 | /*****************************************************************************/ |
---|
| 938 | /** |
---|
[4668] | 939 | * Set Node Error Status |
---|
| 940 | * |
---|
| 941 | * This function will set the LEDs to be 0x5 and then set the hex display |
---|
| 942 | * to Ex, where x is the value of the status error |
---|
| 943 | * |
---|
| 944 | * @param status - Number from 0 - 0xF to indicate status error |
---|
| 945 | * |
---|
| 946 | * @return None |
---|
| 947 | * |
---|
| 948 | *****************************************************************************/ |
---|
| 949 | void set_node_error_status(int status) { |
---|
[2159] | 950 | |
---|
[4668] | 951 | userio_write_leds_red(USERIO_BASEADDR, 0x5); |
---|
| 952 | userio_write_hexdisp_left(USERIO_BASEADDR, 0xE); |
---|
| 953 | userio_write_hexdisp_right(USERIO_BASEADDR, status); |
---|
[2159] | 954 | } |
---|
| 955 | |
---|
| 956 | |
---|
| 957 | |
---|
| 958 | /*****************************************************************************/ |
---|
| 959 | /** |
---|
[4668] | 960 | * LED Functions |
---|
| 961 | * |
---|
| 962 | * Blink Node: |
---|
| 963 | * For WARP v3 Hardware, this function will toggle LEDs. The pattern depends |
---|
| 964 | * on the value of the LEDs before the function was called. |
---|
| 965 | * |
---|
| 966 | * @param num_blinks - Number of blinks (0 means blink forever) |
---|
| 967 | * blink_time - Time in us between blinks |
---|
| 968 | * |
---|
| 969 | * @return None |
---|
| 970 | * |
---|
| 971 | *****************************************************************************/ |
---|
| 972 | void blink_node(int num_blinks, int blink_time) { |
---|
| 973 | int i; |
---|
| 974 | use_leds = 0; |
---|
[4316] | 975 | |
---|
[4668] | 976 | if ( num_blinks > 0 ) { |
---|
[2159] | 977 | // Perform standard blink |
---|
[4668] | 978 | for( i = 0; i < num_blinks; i++ ) { |
---|
| 979 | userio_toggle_leds_green(USERIO_BASEADDR, 0xF); |
---|
| 980 | usleep( blink_time ); |
---|
| 981 | } |
---|
| 982 | } else { |
---|
| 983 | // Perform an infinite blink |
---|
| 984 | while(1){ |
---|
| 985 | userio_toggle_leds_red(USERIO_BASEADDR, 0xF); |
---|
| 986 | usleep( blink_time ); |
---|
| 987 | } |
---|
| 988 | } |
---|
[4316] | 989 | |
---|
[4668] | 990 | use_leds = 1; |
---|
[2159] | 991 | } |
---|
| 992 | |
---|
| 993 | |
---|
[4316] | 994 | // Increment the green LEDs in a one-hot manner (ie 0x1 -> 0x2 -> 0x4 -> 0x8 -> 0x1 ...) |
---|
| 995 | void increment_green_leds_one_hot() { |
---|
[4668] | 996 | if (use_leds) { |
---|
| 997 | userio_write_leds_green(USERIO_BASEADDR, (1 << green_led_state)); |
---|
| 998 | green_led_state = (green_led_state + 1) % 4; |
---|
| 999 | } |
---|
[4316] | 1000 | } |
---|
| 1001 | |
---|
| 1002 | |
---|
| 1003 | // Increment the red LEDs in a one-hot manner (ie 0x1 -> 0x2 -> 0x4 -> 0x8 -> 0x1 ...) |
---|
| 1004 | void increment_red_leds_one_hot() { |
---|
[4668] | 1005 | if (use_leds) { |
---|
| 1006 | userio_write_leds_red(USERIO_BASEADDR, (1 << red_led_state)); |
---|
| 1007 | red_led_state = (red_led_state + 1) % 4; |
---|
| 1008 | } |
---|
[4316] | 1009 | } |
---|
| 1010 | |
---|
| 1011 | |
---|
| 1012 | |
---|
[2854] | 1013 | /*****************************************************************************/ |
---|
| 1014 | /** |
---|
[4668] | 1015 | * Process Received UART characters |
---|
| 1016 | * |
---|
| 1017 | * Due to the need to use interrupts for IQ processing, we decided to also connect and |
---|
| 1018 | * initialize the UART interrupt. This allows the user to communicate with the board |
---|
| 1019 | * via a terminal program, such as Putty. Each character typed in the terminal program |
---|
| 1020 | * will cause the function below to be called with the ACSII value of the character. |
---|
| 1021 | * |
---|
| 1022 | * Currently, a few characters have been allocated for various debug modes, but no |
---|
| 1023 | * characters have been officially allocated for particular functions. Therefore, any |
---|
| 1024 | * user can feel free to extend this method if needed for their experiment. By default, |
---|
| 1025 | * the node will echo all characters back to the terminal. |
---|
| 1026 | * |
---|
| 1027 | * @param rx_byte - Character received from the UART via the terminal program on the host |
---|
| 1028 | * |
---|
| 1029 | * @return None |
---|
| 1030 | * |
---|
| 1031 | * @note Some characters have been allocated for various debug functions that are enabled |
---|
| 1032 | * through defines found in wl_node.c and wl_common.h: |
---|
| 1033 | * |
---|
| 1034 | * _DEBUG_STORAGE_ |
---|
| 1035 | * - 'c' - Clear the debug storage (ie reset the storage) |
---|
| 1036 | * - 'p' - Print the contents of the debug storage |
---|
| 1037 | * |
---|
| 1038 | * ALLOW_ETHERNET_PAUSE |
---|
| 1039 | * - 's' - Toggles the state of Ethernet receptions; Will either pause or un-pause |
---|
| 1040 | * the reception of Ethernet packets based on the current state. By default, |
---|
| 1041 | * Ethernet receptions are un-paused. |
---|
| 1042 | * |
---|
| 1043 | *****************************************************************************/ |
---|
[4284] | 1044 | void uart_rx(u8 rx_byte){ |
---|
[4292] | 1045 | char character = rx_byte; |
---|
[4284] | 1046 | |
---|
[4668] | 1047 | // Process the received character |
---|
| 1048 | switch(character) { |
---|
| 1049 | |
---|
[4333] | 1050 | #if _DEBUG_STORAGE_ |
---|
[4668] | 1051 | case 'c': |
---|
| 1052 | reset_debug_storage(); |
---|
| 1053 | break; |
---|
[4284] | 1054 | |
---|
[4668] | 1055 | case 'p': |
---|
| 1056 | print_debug_storage(); |
---|
| 1057 | break; |
---|
[4333] | 1058 | #endif |
---|
[4514] | 1059 | |
---|
[4668] | 1060 | #if ALLOW_ETHERNET_PAUSE |
---|
| 1061 | case 's': |
---|
| 1062 | if (ethernet_pause == 1) { |
---|
| 1063 | ethernet_pause = 0; |
---|
| 1064 | } else { |
---|
| 1065 | ethernet_pause = 1; |
---|
| 1066 | } |
---|
[4514] | 1067 | break; |
---|
[4668] | 1068 | #endif |
---|
[4514] | 1069 | |
---|
[4668] | 1070 | // Echo any unknown characters back to the terminal |
---|
| 1071 | default: |
---|
| 1072 | wl_printf(WL_PRINT_NONE, NULL, "%c", rx_byte); |
---|
| 1073 | break; |
---|
| 1074 | } |
---|
[4284] | 1075 | } |
---|
| 1076 | |
---|
| 1077 | |
---|
| 1078 | |
---|
| 1079 | /*****************************************************************************/ |
---|
| 1080 | /** |
---|
| 1081 | * @brief Node initialization |
---|
| 1082 | * |
---|
| 1083 | * This is the main function of the embedded C code. It will initialize the |
---|
| 1084 | * board and then begin a infinite polling loop on the Ethernet peripheral to |
---|
| 1085 | * process any commands that are sent to the board. |
---|
| 1086 | * |
---|
[4668] | 1087 | * @param None |
---|
[4284] | 1088 | * |
---|
[4668] | 1089 | * @return None. Implements an infinite while loop |
---|
[4284] | 1090 | * |
---|
[4668] | 1091 | * @note The hex display values during boot should be as follows: |
---|
| 1092 | * OFF - Bit stream is being downloaded to the board |
---|
| 1093 | * 00 - Initial power up of the downloaded bit stream |
---|
| 1094 | * 01 to 99 - ID value of the node. |
---|
| 1095 | * -- - Node is ready to recieve network configuration |
---|
| 1096 | * Ex - Error condition where x is the value of the status error |
---|
| 1097 | * Please plug in a USB cable for further debug messages |
---|
[4284] | 1098 | * |
---|
[4668] | 1099 | * A value of 01 to 99 or -- indicates a successful boot and is ready to |
---|
| 1100 | * receive commands. |
---|
| 1101 | * |
---|
[4284] | 1102 | ******************************************************************************/ |
---|
[1915] | 1103 | int main() { |
---|
[4673] | 1104 | int status; |
---|
| 1105 | u32 tmp_eth_dev_num; |
---|
| 1106 | volatile u32 link_status = LINK_NOT_READY; |
---|
| 1107 | u32 init_transport = 1; // Does the transport need to be initialized |
---|
[1915] | 1108 | |
---|
[4668] | 1109 | // ------------------------------------------ |
---|
| 1110 | // Initialize global variables |
---|
| 1111 | // |
---|
| 1112 | dram_present = 0; |
---|
| 1113 | configure_buffers = 1; |
---|
[1915] | 1114 | |
---|
[4668] | 1115 | #if ALLOW_ETHERNET_PAUSE |
---|
| 1116 | ethernet_pause = 0; |
---|
| 1117 | #endif |
---|
[4196] | 1118 | |
---|
[4668] | 1119 | // Set the print level |
---|
| 1120 | wl_set_print_level(DEFAULT_DEBUG_PRINT_LEVEL); |
---|
[4284] | 1121 | |
---|
[4196] | 1122 | |
---|
[4668] | 1123 | // ------------------------------------------ |
---|
| 1124 | // Print initial message to UART |
---|
| 1125 | // |
---|
| 1126 | wl_printf(WL_PRINT_NONE, NULL, "\fWARPLab v%d.%d.%d (compiled %s %s)\n", WARPLAB_VER_MAJOR, WARPLAB_VER_MINOR, WARPLAB_VER_REV, __DATE__, __TIME__); |
---|
[1915] | 1127 | |
---|
[4668] | 1128 | if(WARPLAB_CONFIG_4RF) { |
---|
| 1129 | wl_printf(WL_PRINT_NONE, NULL, "Configured for 4 RF Interfaces - FMC-RF-2X245 FMC module must be installed\n"); |
---|
| 1130 | } else { |
---|
| 1131 | wl_printf(WL_PRINT_NONE, NULL, "Configured for 2 RF Interfaces - Using WARP v3 on-board RF interfaces\n"); |
---|
| 1132 | } |
---|
[4196] | 1133 | |
---|
[4292] | 1134 | |
---|
[4668] | 1135 | // ------------------------------------------ |
---|
| 1136 | // Check that right shift works correctly |
---|
| 1137 | // Issue with -Os in Xilinx SDK 14.7 |
---|
| 1138 | if (microblaze_right_shift_test() != XST_SUCCESS) { |
---|
| 1139 | wl_printf(WL_PRINT_ERROR, print_type_node, "Node right shift error! Exiting...\n"); |
---|
| 1140 | set_node_error_status(0x0); // Set user IO |
---|
| 1141 | blink_node(0, 250000); // Infinite blink |
---|
| 1142 | } |
---|
[4292] | 1143 | |
---|
[4514] | 1144 | |
---|
[4668] | 1145 | // ------------------------------------------ |
---|
| 1146 | // Node initialization |
---|
| 1147 | // NOTE: These errors are fatal and status error will be displayed |
---|
| 1148 | // on the hex display. Also, please attach a USB cable for |
---|
| 1149 | // terminal debug messages. |
---|
| 1150 | // |
---|
| 1151 | status = node_init(); |
---|
[2026] | 1152 | |
---|
[4668] | 1153 | if(status != XST_SUCCESS) { |
---|
| 1154 | wl_printf(WL_PRINT_ERROR, print_type_node, "Node initialization error! Exiting...\n"); |
---|
| 1155 | set_node_error_status(0x1); // Set user IO |
---|
| 1156 | blink_node(0, 250000); // Infinite blink |
---|
| 1157 | } |
---|
[4196] | 1158 | |
---|
[4514] | 1159 | |
---|
[4668] | 1160 | // ------------------------------------------ |
---|
| 1161 | // Global initialization |
---|
| 1162 | // NOTE: These errors are fatal and status error will be displayed |
---|
| 1163 | // on the hex display. Also, please attach a USB cable for |
---|
| 1164 | // terminal debug messages. |
---|
| 1165 | // |
---|
| 1166 | status = global_initialize(); |
---|
[1915] | 1167 | |
---|
[4668] | 1168 | if(status != XST_SUCCESS) { |
---|
| 1169 | wl_printf(WL_PRINT_ERROR, print_type_node, "Global initialization error! Exiting...\n"); |
---|
| 1170 | set_node_error_status(0x2); // Set user IO |
---|
| 1171 | blink_node(0, 250000); // Infinite blink |
---|
| 1172 | } |
---|
[4196] | 1173 | |
---|
[4668] | 1174 | |
---|
| 1175 | // ------------------------------------------ |
---|
[2159] | 1176 | // Transport initialization |
---|
[4668] | 1177 | // NOTE: These errors are fatal and status error will be displayed |
---|
| 1178 | // on the hex display. Also, please attach a USB cable for |
---|
| 1179 | // terminal debug messages. |
---|
| 1180 | // |
---|
[4673] | 1181 | if (WL_USE_ETH_A) { |
---|
| 1182 | status = transport_init(WL_ETH_A, init_transport); |
---|
| 1183 | init_transport = 0; |
---|
| 1184 | } |
---|
[4514] | 1185 | |
---|
[4673] | 1186 | if ((status == XST_SUCCESS) && WL_USE_ETH_B) { |
---|
| 1187 | status = transport_init(WL_ETH_B, init_transport); |
---|
| 1188 | init_transport = 0; |
---|
| 1189 | } |
---|
| 1190 | |
---|
[4668] | 1191 | if(status != XST_SUCCESS) { |
---|
| 1192 | wl_printf(WL_PRINT_ERROR, print_type_node, "Transport initialization error! Exiting...\n"); |
---|
| 1193 | set_node_error_status(0x3); // Set user IO |
---|
| 1194 | blink_node(0, 250000); // Infinite blink |
---|
| 1195 | } |
---|
[1915] | 1196 | |
---|
[4514] | 1197 | // A common error that can occur when regenerating the linker script, is that the linker |
---|
[4668] | 1198 | // script puts the global data structures for the WARP IP/UDP transport in to a memory |
---|
| 1199 | // that is not accessible by the Ethernet DMA. Unfortunately, this is an extremely fatal |
---|
| 1200 | // error, so this check was added to catch this. |
---|
| 1201 | // |
---|
[4673] | 1202 | if (WL_USE_ETH_A) { |
---|
| 1203 | status = eth_not_in_memory_range(WL_ETH_A, XPAR_MICROBLAZE_0_D_BRAM_CTRL_HIGHADDR, XPAR_MICROBLAZE_0_D_BRAM_CTRL_BASEADDR); |
---|
| 1204 | tmp_eth_dev_num = WL_ETH_A; |
---|
| 1205 | } |
---|
[4514] | 1206 | |
---|
[4673] | 1207 | if ((status == WARP_IP_UDP_SUCCESS) && WL_USE_ETH_B) { |
---|
| 1208 | status = eth_not_in_memory_range(WL_ETH_B, XPAR_MICROBLAZE_0_D_BRAM_CTRL_HIGHADDR, XPAR_MICROBLAZE_0_D_BRAM_CTRL_BASEADDR); |
---|
| 1209 | tmp_eth_dev_num = WL_ETH_B; |
---|
| 1210 | } |
---|
| 1211 | |
---|
[4668] | 1212 | if(status != WARP_IP_UDP_SUCCESS) { |
---|
[4673] | 1213 | wl_printf(WL_PRINT_ERROR, print_type_node, "Ethernet device %c: \n", warp_conv_eth_dev_num(tmp_eth_dev_num)); |
---|
[4668] | 1214 | wl_printf(WL_PRINT_ERROR, print_type_node, " Global data structures not accessible by DMA.\n\n"); |
---|
| 1215 | wl_printf(WL_PRINT_ERROR, print_type_node, "Please update your linker command file to put buffers in shared BRAM. Exiting...\n"); |
---|
| 1216 | set_node_error_status(0x4); // Set user IO |
---|
| 1217 | blink_node(0, 250000); // Infinite blink |
---|
| 1218 | } |
---|
[2854] | 1219 | |
---|
| 1220 | |
---|
[4668] | 1221 | // ------------------------------------------ |
---|
| 1222 | // Interrupt initialization |
---|
| 1223 | // NOTE: These errors are fatal and status error will be displayed |
---|
| 1224 | // on the hex display. Also, please attach a USB cable for |
---|
| 1225 | // terminal debug messages. |
---|
| 1226 | status = wl_interrupt_init(); |
---|
[4514] | 1227 | |
---|
[4668] | 1228 | if(status != XST_SUCCESS) { |
---|
| 1229 | wl_printf(WL_PRINT_ERROR, print_type_node, "Interrupt initialization error! Exiting...\n"); |
---|
| 1230 | set_node_error_status(0x5); // Set user IO |
---|
| 1231 | blink_node(0, 250000); // Infinite blink |
---|
| 1232 | } |
---|
[2013] | 1233 | |
---|
[4196] | 1234 | |
---|
[4668] | 1235 | // ------------------------------------------ |
---|
[4196] | 1236 | // Wait for Ethernet to finish initializing the link |
---|
[4668] | 1237 | // |
---|
[4673] | 1238 | if (WL_WAIT_FOR_ETH) { |
---|
| 1239 | wl_printf(WL_PRINT_NONE, NULL, "\nWaiting for Ethernet link ...\n"); |
---|
[4196] | 1240 | |
---|
[4673] | 1241 | while(link_status == LINK_NOT_READY) { |
---|
| 1242 | |
---|
| 1243 | // Check the link status of each Ethernet device in use |
---|
| 1244 | if (((transport_link_status(WL_ETH_A) == LINK_NOT_READY) && WL_USE_ETH_A) || |
---|
| 1245 | ((transport_link_status(WL_ETH_B) == LINK_NOT_READY) && WL_USE_ETH_B)) { |
---|
| 1246 | |
---|
| 1247 | link_status = LINK_NOT_READY; |
---|
| 1248 | } else { |
---|
| 1249 | link_status = LINK_READY; |
---|
| 1250 | } |
---|
| 1251 | |
---|
| 1252 | // Update LEDs for a visual cue that we are waiting on the Ethernet device |
---|
| 1253 | userio_toggle_leds_green(USERIO_BASEADDR, 0x1); |
---|
| 1254 | usleep(100000); |
---|
| 1255 | } |
---|
| 1256 | |
---|
| 1257 | } else { |
---|
| 1258 | xil_printf(" Not waiting for Ethernet link. Current status:\n"); |
---|
| 1259 | |
---|
| 1260 | if ((transport_link_status(WL_ETH_A) == LINK_READY) && WL_USE_ETH_A) { |
---|
| 1261 | xil_printf(" ETH A ready\n"); |
---|
| 1262 | } else { |
---|
| 1263 | xil_printf(" ETH A not ready\n"); |
---|
| 1264 | } |
---|
| 1265 | |
---|
| 1266 | if ((transport_link_status(WL_ETH_B) == LINK_READY) && WL_USE_ETH_B) { |
---|
| 1267 | xil_printf(" ETH B ready\n"); |
---|
| 1268 | } else { |
---|
| 1269 | xil_printf(" ETH B not ready\n"); |
---|
| 1270 | } |
---|
| 1271 | |
---|
| 1272 | xil_printf("\n Make sure link is ready before using WARPLab.\n"); |
---|
[4668] | 1273 | } |
---|
[1915] | 1274 | |
---|
[4668] | 1275 | wl_printf(WL_PRINT_NONE, NULL, "\nInitialization Successful - Waiting for Commands from MATLAB\n\n"); |
---|
[4196] | 1276 | |
---|
[4417] | 1277 | |
---|
[4668] | 1278 | // ------------------------------------------ |
---|
| 1279 | // Assign the transport receive callback (how to process received Ethernet packets) |
---|
| 1280 | // IMPORTANT: Must be called after transport_init() |
---|
| 1281 | transport_set_process_hton_msg_callback((void *)node_rx_from_transport); |
---|
[1921] | 1282 | |
---|
[2159] | 1283 | |
---|
[4668] | 1284 | // ------------------------------------------ |
---|
| 1285 | // Assign the uart receive callback (how to process received uart characters) |
---|
| 1286 | // IMPORTANT: Must be called after node_init() |
---|
[4284] | 1287 | wl_set_uart_rx_callback((void*)uart_rx); |
---|
| 1288 | |
---|
| 1289 | |
---|
[4668] | 1290 | // ------------------------------------------ |
---|
| 1291 | // Enable all interrupts |
---|
| 1292 | status = wl_interrupt_restore_state(INTERRUPTS_ENABLED); |
---|
[1915] | 1293 | |
---|
[4668] | 1294 | if(status != XST_SUCCESS) { |
---|
| 1295 | wl_printf(WL_PRINT_ERROR, print_type_node, "Cannot enable interrupts! Exiting...\n"); |
---|
| 1296 | set_node_error_status(0x6); // Set user IO |
---|
| 1297 | blink_node(0, 250000); // Infinite blink |
---|
| 1298 | } |
---|
[2159] | 1299 | |
---|
[1915] | 1300 | |
---|
[4668] | 1301 | // ------------------------------------------ |
---|
| 1302 | // Blink LEDs to show we are done |
---|
| 1303 | // |
---|
| 1304 | userio_write_leds_green(USERIO_BASEADDR, 0x5); |
---|
| 1305 | blink_node(10, 100000); // Blink 10 times |
---|
| 1306 | userio_write_leds_red(USERIO_BASEADDR, 0x0); |
---|
| 1307 | userio_write_leds_green(USERIO_BASEADDR, 0x0); |
---|
[2030] | 1308 | |
---|
[4668] | 1309 | // If you are in configure over network mode, then indicate that to the user |
---|
| 1310 | if ( node == 0xFFFF ) { |
---|
| 1311 | wl_printf(WL_PRINT_NONE, NULL, "!!! Waiting for Network Configuration via Matlab !!! \n\n"); |
---|
[4184] | 1312 | |
---|
[4668] | 1313 | // Turn off hex mapping; set the center LED |
---|
| 1314 | // NOTE: hex mapping will be re-enabled when the bcast packet is processed to set the node ID |
---|
| 1315 | userio_write_control(USERIO_BASEADDR, (userio_read_control(USERIO_BASEADDR) & (~(W3_USERIO_HEXDISP_L_MAPMODE | W3_USERIO_HEXDISP_R_MAPMODE)))); |
---|
| 1316 | userio_write_hexdisp_left(USERIO_BASEADDR, 0x40); |
---|
| 1317 | userio_write_hexdisp_right(USERIO_BASEADDR, 0x40); |
---|
| 1318 | } |
---|
[4184] | 1319 | |
---|
| 1320 | |
---|
[4668] | 1321 | // ------------------------------------------ |
---|
| 1322 | // Go into infinite while loop |
---|
| 1323 | // |
---|
| 1324 | while(1){ |
---|
[4453] | 1325 | |
---|
[4668] | 1326 | #if ALLOW_ETHERNET_PAUSE |
---|
| 1327 | if (ethernet_pause) { |
---|
| 1328 | // Indicate visually to the user that the node is not accepting Ethernet packets |
---|
| 1329 | increment_red_leds_one_hot(); |
---|
| 1330 | usleep(100000); |
---|
| 1331 | } else { |
---|
[4673] | 1332 | // Process Ethernet packets. |
---|
| 1333 | // NOTE: This is polling based and not interrupt based. |
---|
| 1334 | // NOTE: #if is used in this case vs standard if() statement since this section of |
---|
| 1335 | // code is performance critical. |
---|
| 1336 | // |
---|
| 1337 | #if WL_USE_ETH_A |
---|
| 1338 | transport_poll(WL_ETH_A); |
---|
| 1339 | #endif |
---|
| 1340 | #if WL_USE_ETH_B |
---|
| 1341 | transport_poll(WL_ETH_B); |
---|
| 1342 | #endif |
---|
[4668] | 1343 | } |
---|
| 1344 | #else |
---|
[4673] | 1345 | // Process Ethernet packets. |
---|
| 1346 | // NOTE: This is polling based and not interrupt based. |
---|
| 1347 | // NOTE: #if is used in this case vs standard if() statement since this section of |
---|
| 1348 | // code is performance critical. |
---|
| 1349 | // |
---|
| 1350 | #if WL_USE_ETH_A |
---|
| 1351 | transport_poll(WL_ETH_A); |
---|
[4453] | 1352 | #endif |
---|
[4673] | 1353 | #if WL_USE_ETH_B |
---|
| 1354 | transport_poll(WL_ETH_B); |
---|
| 1355 | #endif |
---|
[4453] | 1356 | |
---|
[4673] | 1357 | #endif |
---|
| 1358 | |
---|
[4668] | 1359 | } |
---|
[4453] | 1360 | |
---|
[4668] | 1361 | return XST_SUCCESS; |
---|
[4453] | 1362 | } |
---|
| 1363 | |
---|
| 1364 | #endif |
---|
| 1365 | |
---|
[4668] | 1366 | // |
---|
| 1367 | // |
---|
| 1368 | // NOTE: As of WARPLab 7.6.0, the code associated with WARP v2 has been removed. If you are using WARP v2, please use |
---|
| 1369 | // WARPLab 7.5.1 or earlier. |
---|
| 1370 | // |
---|
| 1371 | // |
---|