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

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

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

File size: 55.3 KB
RevLine 
[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]53extern int                   sock_unicast;                 // UDP socket for unicast traffic to / from the board
54extern struct sockaddr_in    addr_unicast;
[4196]55
56
[4284]57
[4292]58/*************************** Variable Definitions ****************************/
[4284]59
[4292]60u16                          node;                         // Node ID
61static u8                    dram_present;                 // Is DRAM present and available for use
62static u8                    configure_buffers;            // Configure the baseband buffers
[4284]63
[4668]64#if ALLOW_ETHERNET_PAUSE
65u8                           ethernet_pause;               // State variable to pause the reception of Ethernet packets
66#endif
[4292]67
[4196]68/*************************** Functions Prototypes ****************************/
69
70void blink_node( int num_blinks, int blink_time );
[4284]71
[4196]72void 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 *****************************************************************************/
99int  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]196void 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]263int 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
324u8                           use_leds;
325u8                           red_led_state;
326u8                           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]353int 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]729int 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]851int 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 *****************************************************************************/
949void 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 *****************************************************************************/
972void 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 ...)
995void 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 ...)
1004void 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]1044void 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]1103int 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//
Note: See TracBrowser for help on using the repository browser.