source: ResearchApps/PHY/WARPLAB/WARPLab7/C_Code_Reference/wl_node.c

Last change on this file was 5627, checked in by chunter, 5 years ago

loosened the requirement for matching hardware and software version numbers to only major/minor

File size: 55.3 KB
Line 
1/** @file wl_node.c
2 *  @brief WARPLab Framework (Node)
3 *
4 *  This contains the code for WARPLab Framework.
5 *
6 *  @copyright Copyright 2013-2015, Mango Communications. All rights reserved.
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 */
13
14
15
16/**********************************************************************************************************************/
17/**
18 * @brief Common Functions
19 *
20 **********************************************************************************************************************/
21
22/***************************** Include Files *********************************/
23
24// Xilinx / Standard library includes
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <xparameters.h>
29#include <xio.h>
30
31// Xilinx Peripheral includes
32#include <xtmrctr.h>
33
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
43
44
45/*************************** Constant Definitions ****************************/
46
47//
48// See wl_common.h for commonly modified control parameters
49//
50
51/*********************** Global Variable Definitions *************************/
52
53extern int                   sock_unicast;                 // UDP socket for unicast traffic to / from the board
54extern struct sockaddr_in    addr_unicast;
55
56
57
58/*************************** Variable Definitions ****************************/
59
60u16                          node;                         // Node ID
61static u8                    dram_present;                 // Is DRAM present and available for use
62static u8                    configure_buffers;            // Configure the baseband buffers
63
64#if ALLOW_ETHERNET_PAUSE
65u8                           ethernet_pause;               // State variable to pause the reception of Ethernet packets
66#endif
67
68/*************************** Functions Prototypes ****************************/
69
70void blink_node( int num_blinks, int blink_time );
71
72void set_node_error_status( int status );
73
74
75/******************************** Functions **********************************/
76
77
78/*****************************************************************************/
79/**
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 *
92 * @return  None
93 *
94 * @note    If this packet is a host to node message, then the process_hton_msg_callback
95 *          is used to further process the packet.  This method will strip off the
96 *          WARP transport header for future packet processing.
97 *
98 *****************************************************************************/
99int  node_rx_from_transport(int socket_index, struct sockaddr * from, warp_ip_udp_buffer * recv_buffer, warp_ip_udp_buffer * send_buffer) {
100
101    u8                  cmd_group;
102    u32                 resp_sent      = NO_RESP_SENT;
103    u32                 resp_length;
104
105    wl_cmd_resp_hdr   * cmd_hdr;
106    wl_cmd_resp         command;
107    wl_cmd_resp_hdr   * resp_hdr;
108    wl_cmd_resp         response;
109
110    // Initialize the Command/Response structures
111    cmd_hdr             = (wl_cmd_resp_hdr *)(recv_buffer->offset);
112    command.header      = cmd_hdr;
113    command.args        = (u32 *)((recv_buffer->offset) + sizeof(wl_cmd_resp_hdr));
114    command.buffer      = (void *)(recv_buffer);
115
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);
120
121    // Endian swap the command header so future processing can understand it
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);
125
126    // Send command to appropriate processing sub-system
127    cmd_group           = WL_CMD_TO_GRP(cmd_hdr->cmd);
128
129    switch(cmd_group){
130        case GROUP_NODE:
131            resp_sent = node_process_cmd(socket_index, from, &command, &response);
132        break;
133        case GROUP_TRANSPORT:
134            resp_sent = transport_process_cmd(socket_index, from, &command, &response);
135        break;
136        case GROUP_INTERFACE:
137            resp_sent = ifc_process_cmd(socket_index, from, &command, &response);
138        break;
139        case GROUP_BASEBAND:
140            resp_sent = baseband_process_cmd(socket_index, from, &command, &response);
141        break;
142        case GROUP_TRIGGER_MANAGER:
143            resp_sent = trigmngr_process_cmd(socket_index, from, &command, &response);
144        break;
145        case GROUP_USER:
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    }
152
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));
158
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    }
163
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);
168
169    // Return the status
170    return resp_sent;
171}
172
173
174
175/*****************************************************************************/
176/**
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 *
190 * @return  None
191 *
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.
194 *
195 *****************************************************************************/
196void node_send_early_resp(int socket_index, void * to, wl_cmd_resp_hdr * resp_hdr, void * buffer) {
197    //
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.
203    //
204
205    // wl_printf(WL_PRINT_DEBUG, print_type_node, "Send early response:  cmd = 0x%08x   length = %d\n", resp_hdr->cmd, resp_hdr->length);
206
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
231    // Endian swap the response header before before transport sends it
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);
235
236    // Send the packet
237    transport_send(socket_index, (struct sockaddr *)to, (warp_ip_udp_buffer **)&buffer, 0x1);
238
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;
245}
246
247
248
249/*****************************************************************************/
250/**
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 *****************************************************************************/
263int global_initialize(){
264    int status = XST_SUCCESS;
265
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    }
271
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    }
279
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    }
285
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;
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
313    #include <xsysmon_hw.h>
314#endif
315
316
317/*************************** Constant Definitions ****************************/
318
319/*********************** Global Variable Definitions *************************/
320
321/*************************** Variable Definitions ****************************/
322
323// Hardware LED state
324u8                           use_leds;
325u8                           red_led_state;
326u8                           green_led_state;
327
328
329/*************************** Functions Prototypes ****************************/
330
331/******************************** Functions **********************************/
332
333/*****************************************************************************/
334/**
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 *
345 * @return  int              - Status of the command:
346 *                                 NO_RESP_SENT - No response has been sent
347 *                                 RESP_SENT    - A response has been sent
348 *
349 * @note    See on-line documentation for more information about the Ethernet
350 *          packet structure for WARPLab:  www.warpproject.org
351 *
352 *****************************************************************************/
353int node_process_cmd(int socket_index, void * from, wl_cmd_resp * command, wl_cmd_resp * response) {
354
355    //
356    // IMPORTANT ENDIAN NOTES:
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    //
364
365    // Standard variables
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;
378    int                 status;
379    int                 numblinks;
380    u8                  node_ip_addr[IP_ADDR_LEN];
381    u8                  node_hw_addr[ETH_MAC_ADDR_LEN];
382
383    u32                 msg_cmd;
384    u32                 default_response;
385
386    u32                 mem_addr;
387    u32                 mem_length;
388    u32                 mem_index;
389
390    // Set up the response header
391    resp_hdr->cmd       = cmd_hdr->cmd;
392    resp_hdr->length    = 0;
393    resp_hdr->num_args  = 0;
394
395    // Get the Ethernet device number of the socket
396    eth_dev_num         = socket_get_eth_dev_num(socket_index);
397
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);
401
402    // Process the command
403    switch(cmd_id){
404
405        //---------------------------------------------------------------------
406        case CMDID_NODE_INITIALIZE:
407
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 ) );
410
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();
415
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;
422
423
424        //---------------------------------------------------------------------
425        case CMDID_NODE_INFO:
426
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));
440            resp_args_32[resp_index++] = Xil_Htonl(trigger_proc_get_core_info());
441            resp_args_32[resp_index++] = Xil_Htonl(1);                  // num_interfaceGroups
442
443            // Set the number of interfaces
444            #if WARPLAB_CONFIG_4RF
445                resp_args_32[resp_index++] = Xil_Htonl(4);
446            #else
447                resp_args_32[resp_index++] = Xil_Htonl(2);
448            #endif
449
450            resp_hdr->length  += (resp_index * sizeof(resp_args_32));
451            resp_hdr->num_args = resp_index;
452        break;
453
454
455        //---------------------------------------------------------------------
456        case CMDID_NODE_IDENTIFY:
457
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            //
465            node_send_early_resp(socket_index, from, response->header, response->buffer);
466
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);
470
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            }
484
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        //---------------------------------------------------------------------
495        case CMDID_NODE_TEMPERATURE:
496
497            #ifdef XPAR_XSYSMON_NUM_INSTANCES
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));
501            #else
502                resp_args_32[resp_index++] = 0;
503                resp_args_32[resp_index++] = 0;
504                resp_args_32[resp_index++] = 0;
505            #endif
506
507            resp_hdr->length  += (resp_index * sizeof(resp_args_32));
508            resp_hdr->num_args = resp_index;
509        break;
510
511
512        //---------------------------------------------------------------------
513        case CMDID_NODE_CONFIG_SETUP:
514            // NODE_CONFIG_SETUP Packet Format:
515            //   - Note:  All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl()
516            //
517            //   - cmd_args_32[0] - Serial Number
518            //   - cmd_args_32[1] - Node ID
519            //   - cmd_args_32[2] - IP Address
520            //
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
526                // Only update the parameters if the serial numbers match
527                if (w3_eeprom_readSerialNum(EEPROM_BASEADDR) ==  Xil_Ntohl(cmd_args_32[0])) {
528
529                    node = Xil_Ntohl(cmd_args_32[1]) & 0xFFFF;
530
531                    wl_printf(WL_PRINT_NONE, NULL, "  New Node ID   : %d \n", node);
532
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));
537
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
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]);
545
546                    // Configure the transport with the node ID and IP address
547                    eth_set_ip_addr(eth_dev_num, node_ip_addr);
548
549                    status = transport_config_sockets(eth_dev_num, (NODE_UDP_UNICAST_PORT_BASE + node), NODE_UDP_MCAST_BASE);
550
551                    if(status != XST_SUCCESS) {
552                        wl_printf(WL_PRINT_ERROR, print_type_node, "Error binding transport...\n");
553                    }
554
555                } else {
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));
557                }
558            }
559        break;
560
561
562        //---------------------------------------------------------------------
563        case CMDID_NODE_CONFIG_RESET:
564            // NODE_CONFIG_RESET Packet Format:
565            //   - Note:  All u32 parameters in cmd_args_32 are byte swapped so use Xil_Ntohl()
566            //
567            //   - cmd_args_32[0] - Serial Number
568            //
569
570            // Send the response early so that M-Code does not hang when IP address changes
571            node_send_early_resp(socket_index, from, response->header, response->buffer);
572
573            // Only update the parameters if the serial numbers match
574            if (w3_eeprom_readSerialNum(EEPROM_BASEADDR) ==  Xil_Ntohl(cmd_args_32[0])) {
575
576                // Reset node to 0xFFFF
577                node = 0xFFFF;
578
579                wl_printf(WL_PRINT_NONE, NULL, "\n!!! Reseting Network Configuration !!! \n\n");
580
581                // Reset transport;  This will update the IP Address back to default and rebind the sockets
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
586                status = transport_config_sockets(eth_dev_num, NODE_UDP_UNICAST_PORT_BASE, NODE_UDP_MCAST_BASE);
587
588                if(status != XST_SUCCESS) {
589                    wl_printf(WL_PRINT_ERROR, print_type_node, "Error binding transport...\n");
590                }
591
592                // Update User IO
593                wl_printf(WL_PRINT_NONE, NULL, "\n!!! Waiting for Network Configuration via Matlab !!! \n\n");
594
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);
601
602            } else {
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));
604            }
605
606            // Tell the transport that the command has already sent a response
607            resp_sent = RESP_SENT;
608        break;
609
610
611        //---------------------------------------------------------------------
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        //---------------------------------------------------------------------
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;
710}
711
712
713
714/*****************************************************************************/
715/**
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 *****************************************************************************/
729int node_clk_initialize() {
730    int status               = XST_SUCCESS;
731    u32 clkmod_status;
732
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    }
740
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);
743
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;
750
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");
757
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;
761
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");
768
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;
773
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");
780
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;
784
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");
791
792            // No changes from configuration applied by HDL and clk_init()
793        break;
794
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");
801
802            clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD);
803        break;
804
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");
811
812            clk_config_input_rf_ref(CLK_BASEADDR, CLK_INSEL_CLKMOD);
813        break;
814
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    }
821
822#if WARPLAB_CONFIG_4RF
823    // Turn on clocks to FMC
824    clk_config_outputs(CLK_BASEADDR, CLK_OUTPUT_ON, (CLK_SAMP_OUTSEL_FMC | CLK_RFREF_OUTSEL_FMC));
825
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);
828
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);
831#endif
832
833    return status;
834}
835
836
837
838/*****************************************************************************/
839/**
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 *****************************************************************************/
851int node_init(){
852    int status               = XST_SUCCESS;
853    u64 timestamp;
854
855    // Configure Microblaze
856    microblaze_enable_exceptions();
857    Xil_DCacheDisable();
858    Xil_ICacheDisable();
859
860    // Initialize hardware components
861    wl_timer_initialize();
862    wl_gpio_debug_initialize();
863    wl_sysmon_initialize();
864    wl_uart_initialize();
865    iic_eeprom_init(EEPROM_BASEADDR, 0x64);
866
867    // Initialize LED global variables
868    use_leds        = 1;
869    red_led_state   = 0;
870    green_led_state = 0;
871
872    // Initialize the central DMA (CDMA) driver
873    //     NOTE:  Need to die if not successful
874    status = wl_cdma_initialize();
875    if (status != XST_SUCCESS) {
876        return XST_FAILURE;
877    }
878
879    // Initialize the hardware clocking
880    status = node_clk_initialize();
881    if (status != XST_SUCCESS) {
882        return XST_FAILURE;
883    }
884
885    // Populate the Node ID
886    node = userio_read_inputs(USERIO_BASEADDR) & W3_USERIO_DIPSW;
887       
888    // If the node has dip switch value of 0xF, then set the node to 0xFFFF
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    }
895
896    // Check the WARPLab version
897    if( (wl_get_design_ver()&0xFFFF00) != ((REQ_WARPLAB_HW_VER)&0xFFFF00) ){
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    }
901
902    // Print node information
903    wl_printf(WL_PRINT_NONE, print_type_node, "W3-a-%05d using Node ID: %d\n", w3_eeprom_readSerialNum(EEPROM_BASEADDR), node);
904
905    // Test to see if DRAM SODIMM is connected to board
906    timestamp    = get_usec_timestamp();
907
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");
911
912            if(ddr_sodim_memory_test() == XST_SUCCESS){
913                dram_present = 1;
914
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    }
927
928    if (wl_get_dram_init_done() != 1) {
929        wl_printf(WL_PRINT_NONE, NULL, "DRAM SODIMM not detected.\n");
930    }
931
932    return status;
933}
934
935
936
937/*****************************************************************************/
938/**
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 *****************************************************************************/
949void set_node_error_status(int status) {
950
951    userio_write_leds_red(USERIO_BASEADDR, 0x5);
952    userio_write_hexdisp_left(USERIO_BASEADDR, 0xE);
953    userio_write_hexdisp_right(USERIO_BASEADDR, status);
954}
955
956
957
958/*****************************************************************************/
959/**
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 *****************************************************************************/
972void blink_node(int num_blinks, int blink_time) {
973    int i;
974    use_leds = 0;
975
976    if ( num_blinks > 0 ) {
977        // Perform standard blink
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    }
989
990    use_leds = 1;
991}
992
993
994// Increment the green LEDs in a one-hot manner (ie 0x1 -> 0x2 -> 0x4 -> 0x8 -> 0x1 ...)
995void increment_green_leds_one_hot() {
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    }
1000}
1001
1002
1003// Increment the red LEDs in a one-hot manner (ie 0x1 -> 0x2 -> 0x4 -> 0x8 -> 0x1 ...)
1004void increment_red_leds_one_hot() {
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    }
1009}
1010
1011
1012
1013/*****************************************************************************/
1014/**
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 *****************************************************************************/
1044void uart_rx(u8 rx_byte){
1045    char character = rx_byte;
1046
1047    // Process the received character
1048    switch(character) {
1049
1050#if _DEBUG_STORAGE_
1051        case 'c':
1052            reset_debug_storage();
1053        break;
1054
1055        case 'p':
1056            print_debug_storage();
1057        break;
1058#endif
1059
1060#if ALLOW_ETHERNET_PAUSE
1061        case 's':
1062            if (ethernet_pause == 1) {
1063                ethernet_pause = 0;
1064            } else {
1065                ethernet_pause = 1;
1066            }
1067        break;
1068#endif
1069
1070        // Echo any unknown characters back to the terminal
1071        default:
1072            wl_printf(WL_PRINT_NONE, NULL, "%c", rx_byte);
1073        break;
1074    }
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 *
1087 * @param   None
1088 *
1089 * @return  None.  Implements an infinite while loop
1090 *
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
1098 *
1099 *          A value of 01 to 99 or -- indicates a successful boot and is ready to
1100 *          receive commands.
1101 *
1102 ******************************************************************************/
1103int main() {
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
1108
1109    // ------------------------------------------
1110    // Initialize global variables
1111    //
1112    dram_present             = 0;
1113    configure_buffers        = 1;
1114
1115#if ALLOW_ETHERNET_PAUSE
1116    ethernet_pause           = 0;
1117#endif
1118
1119    // Set the print level
1120    wl_set_print_level(DEFAULT_DEBUG_PRINT_LEVEL);
1121
1122
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__);
1127
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    }
1133
1134
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    }
1143
1144
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();
1152
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    }
1158
1159
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();
1167
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    }
1173
1174
1175    // ------------------------------------------
1176    // Transport initialization
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    //
1181    if (WL_USE_ETH_A) {
1182        status = transport_init(WL_ETH_A, init_transport);
1183        init_transport = 0;
1184    }
1185
1186    if ((status == XST_SUCCESS) && WL_USE_ETH_B) {
1187        status = transport_init(WL_ETH_B, init_transport);
1188        init_transport = 0;
1189    }
1190
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    }
1196
1197    // A common error that can occur when regenerating the linker script, is that the linker
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    //
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    }
1206
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
1212    if(status != WARP_IP_UDP_SUCCESS) {
1213        wl_printf(WL_PRINT_ERROR, print_type_node, "Ethernet device %c: \n", warp_conv_eth_dev_num(tmp_eth_dev_num));
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    }
1219
1220
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();
1227
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    }
1233
1234
1235    // ------------------------------------------
1236    // Wait for Ethernet to finish initializing the link
1237    //
1238    if (WL_WAIT_FOR_ETH) {
1239        wl_printf(WL_PRINT_NONE, NULL, "\nWaiting for Ethernet link ...\n");
1240
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");
1273    }
1274
1275    wl_printf(WL_PRINT_NONE, NULL, "\nInitialization Successful - Waiting for Commands from MATLAB\n\n");
1276
1277
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);
1282
1283
1284    // ------------------------------------------
1285    // Assign the uart receive callback (how to process received uart characters)
1286    //     IMPORTANT: Must be called after node_init()
1287    wl_set_uart_rx_callback((void*)uart_rx);
1288
1289
1290    // ------------------------------------------
1291    // Enable all interrupts
1292    status = wl_interrupt_restore_state(INTERRUPTS_ENABLED);
1293
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    }
1299
1300
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);
1308
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");
1312
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    }
1319
1320
1321    // ------------------------------------------
1322    // Go into infinite while loop
1323    //
1324    while(1){
1325
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 {
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
1343        }
1344#else
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);
1352#endif
1353#if WL_USE_ETH_B
1354        transport_poll(WL_ETH_B);
1355#endif
1356
1357#endif
1358
1359    }
1360
1361    return XST_SUCCESS;
1362}
1363
1364#endif
1365
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//
Note: See TracBrowser for help on using the repository browser.