From 7fc2fea1375d801e8acaedf915b31e2b0658debd Mon Sep 17 00:00:00 2001 From: Huzifa Kabakebo Date: Mon, 4 Nov 2024 11:59:44 +0100 Subject: [PATCH] Fix Bugs + Update the README --- README.md | 57 +++++++++++++++-------------- gui/NodeShape.js | 2 ++ gui/SwitchShape.js | 7 ++++ gui/Toolbar.js | 90 ++++++++++++++-------------------------------- gui/Util.js | 27 ++++++++++++-- index.html | 12 ++++--- 6 files changed, 98 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index c93a0b5..260df4d 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,32 @@ -# Documentation - -The general documentation and technical background can be found in the [main wiki](https://wikis.uni-paderborn.de/pc2doc/FPGA_Serial_Channels). - -# PLANNED FEATURES - -If you want to request more features, please file an issue. Current list of planed features: - -* collapse nodes for better overview -* concept to colorize links to have a better overview - * "random" where useful - * defined schemes for specific topologies. -* generate directly the image from ?import argument -* write actual documentation how to use the tool -* generate topology from predefined set - * e.g. ring; then ask for number of nodes -* http://jsfiddle.net/gopi1410/yWs7P/ warn on close tag -* tutorial mode -* new feature goes here -* one feature is not enough - -# TODOs -* srun: found predefined topology (ring, etc.), ignoring explicitly given links -* delete has issues if node has self-links -* svg export computes wrong size when bounding box is a connection. -* nodes are smaller after undo/redo +# FPGA Link GUI Tool + +The FPGA Link GUI Tool is a graphical interface that enables users to visualize and configure connections between FPGA nodes and Ethernet switches. This tool is particularly useful for managing FPGA-to-FPGA networks, providing an intuitive, drag-and-drop interface for setting up custom configurations. + +For more detailed information about FPGA-to-FPGA networking, please refer to the [FPGA-to-FPGA Networking Documentation](https://upb-pc2.atlassian.net/wiki/spaces/PC2DOK/pages/1903573/FPGA-to-FPGA+Networking). + +## Using the Tool + +- On the left sidebar, you’ll find various components: + - **Intel Nodes**: Drag and drop to add Intel FPGA nodes to the workspace. + - **Xilinx Nodes**: Drag and drop to add Xilinx FPGA nodes. + - **Ethernet Switches**: Drag and drop to add Ethernet switches to the network. + - **Custom Labels**: Annotate your design with custom labels for easier identification of nodes and connections. + - **Grid Toggle**: Enable or disable grid view to aid in node placement. + - **Connection Types**: Select from different types of connections via the dropdown menu to tailor the network design to your needs. + + +- **Connecting Nodes**: + - Use the **grey ports** on each node to establish connections either within the same node or between different nodes. + - Use the **green ports** to set up predefined configurations for connecting nodes. + + +- **Editing and Configuring**: + - Utilize the **Undo** and **Redo** buttons at the top left corner to adjust your design as needed. + - Once your configuration is complete, use the following options to save or share it: + - **Copy --fpgalink**: Generates a command for use with the `changeFPGAlinks` bash command to configure your FPGA setup. + - **Copy URL**: Copies a URL that links directly to your current configuration, allowing you to share or revisit it later. + + +- **Importing and Exporting Configurations**: + - To visualize an existing configuration, use the **Import Intel** or **Import Xilinx** buttons to import a command and render it within the GUI. diff --git a/gui/NodeShape.js b/gui/NodeShape.js index dd0a50d..c50ad3a 100755 --- a/gui/NodeShape.js +++ b/gui/NodeShape.js @@ -76,6 +76,8 @@ ChannelShape = draw2d.shape.basic.Label.extend({ port.on("connect", function () { this.setVisible(false); + console.log("Firing"); + if (siblingChannel) siblingChannel.setVisible(false) }, port) port.on("disconnect", function () { diff --git a/gui/SwitchShape.js b/gui/SwitchShape.js index 39e8d7c..fb03195 100755 --- a/gui/SwitchShape.js +++ b/gui/SwitchShape.js @@ -42,10 +42,17 @@ SwitchShape = draw2d.shape.basic.Label.extend({ port.on("dragstart", function (e) { toggle_config_ports(app.view.figures.data, false); + + // Switches cannot be connceted to Intel nodes + // Loop over all figures and all ports and hide all intel ports + toggle_all_intel_ports(app.view.figures.data, false) }, port); port.on("dragend", function (e) { toggle_config_ports(app.view.figures.data, true); + + // Show intel ports again + toggle_all_intel_ports(app.view.figures.data, true) }, port); } diff --git a/gui/Toolbar.js b/gui/Toolbar.js index 0bf21b3..1d06d8f 100755 --- a/gui/Toolbar.js +++ b/gui/Toolbar.js @@ -30,6 +30,20 @@ example.Toolbar = Class.extend({ this.redoButton = $(""); this.html.append(this.redoButton); this.redoButton.button().click($.proxy(function () { + + // This is a workaround to fix a bug in the redo + // The bug is when the connections are created using the connectChannels + // function, then the redo command will cause bugs, so this will check + // if the redo command is a connection, then set the source and target + // port to fix the bug + let redostack = this.view.getCommandStack().redostack; + let redocommand = redostack[redostack.length - 1]; + if (redocommand.figure instanceof HoverConnection && redocommand.label == "Add Shape") { + let connection = redocommand.figure; + connection.setSource(connection.sourcePort); + connection.setTarget(connection.targetPort); + } + this.view.getCommandStack().redo(); }, this)).button("option", "disabled", true); @@ -367,7 +381,16 @@ example.Toolbar = Class.extend({ var srun_fpgalinks_needle = "--fpgalink="; var srun_raw_copy = srun_raw; - var fromIndex = 0; + + // If there is no --fpgalink, just add them so that the following + // while loop will work normally + if(srun_raw_copy.indexOf(srun_fpgalinks_needle) == -1) { + srun_raw_copy = srun_raw_copy.trim().split(" ").map((x => { + x = "--fpgalink=" + x; + return x; + })).join(" "); + } + while ((i = srun_raw_copy.indexOf(srun_fpgalinks_needle)) > -1) { var next_space = srun_raw_copy.indexOf(" ", i + srun_fpgalinks_needle.length); // Check if space symbol is available at end. @@ -385,63 +408,6 @@ example.Toolbar = Class.extend({ // Remove found link. srun_raw_copy = srun_raw_copy.substring(next_space); } - - - // Parse and add fpga links: n00:acl0:ch0-n00:acl1:ch0 - if (srun_raw.indexOf(srun_fpgalinks_needle) == -1) { - // Array(7) [ "n00:acl1:ch0-n00:acl1:ch1", "00", "1", "0", "00", "1", "1" ] - // Array(9)["n00:acl0:ch1-eth", "n00:acl0:ch1", "n00", "acl0", "ch1", "eth", undefined, undefined, undefined] - for (var i = 0; i < fpgalinks.length; i++) { - // Parse and add fpga links: n00:acl0:ch0-n00:acl1:ch0 - var links = fpgalinks[i][0].split("-"); - - // Point 1 (think of source). - // value: n00:acl0:ch0 or eth (for Ethernet switch). - var link_p1 = links[0].split(":"); - // Point 2 (think of destination). - // value: n00:acl0:ch0 or eth (for Ethernet switch). - var link_p2 = links[1].split(":"); - - // Channels to connect. Logic is required to differentiate if - // the channel is between FPGAs or to/from Ethernet switch. - let chan0; - let chan1; - - if (link_p1.length == 3) { - // Channel is from FPGA node. - // Get node. - var tnode_p1 = this.getNodeIdFpgalink(link_p1[0], fpganodes); - // Get FPGA. - var tfpga_p1 = tnode_p1.getFPGAFromFpgalink(link_p1[1]); - - // Get channel. - chan0 = tfpga_p1.getChannelFromFpgalink(link_p1[2]); - } else { - // Channel is to ethernet switch. - chan0 = this.getSwitchFromName(link_p1[0], eth_switches); - } - - if (link_p2.length == 3) { - // Channel is to FPGA node. - - // Get node. - var tnode_p2 = this.getNodeIdFpgalink(link_p2[0], fpganodes); - // Get FPGA. - var tfpga_p2 = tnode_p2.getFPGAFromFpgalink(link_p2[1]); - - chan1 = tfpga_p2.getChannelFromFpgalink(link_p2[2]); - } else { - // Channel is to ethernet switch. - chan1 = this.getSwitchFromName(link_p2[0], eth_switches); - } - - // Get channels, connect and draw them. - this.connectChannels(chan0, chan1); - } - } - - - }, createNodesAndConnections: function (full_match, srun_N, fpganodes, eth_switches) { @@ -866,9 +832,6 @@ example.Toolbar = Class.extend({ } // Get channels, connect and draw them. - // console.log(srun_raw); - // console.log(eth_switches); - // console.log("The 2 channels are: ", chan0, chan1); this.connectChannels(chan0, chan1); // if(link_p1[2] == "ch0") { @@ -981,7 +944,7 @@ example.Toolbar = Class.extend({ // // Draw connection only ones. // if (!tchannel_p1.getIsDrawn()) { - var c = new HoverConnection(); + // In case of ethernet switch, distirbute the connections over all // ports, this is just visiual optimization @@ -1004,8 +967,7 @@ example.Toolbar = Class.extend({ let sourcePort = getLeastPort(tchannel_p1); let targetPort = getLeastPort(tchannel_p2); - c.setSource(sourcePort); - c.setTarget(targetPort); + var c = new HoverConnection(sourcePort, targetPort); // Add connector to model. tchannel_p1.setConnector(c); diff --git a/gui/Util.js b/gui/Util.js index 1a0cc2d..49c9829 100644 --- a/gui/Util.js +++ b/gui/Util.js @@ -128,7 +128,28 @@ function toggle_all_switch_ports(figures, isVisible) { } } -function delete_connections(connections, canvas, addToStack=true) { +function toggle_all_intel_ports(figures, isVisible) { + for (let i = 0; i < figures.length; i++) { + const figure = figures[i]; + if (figure instanceof NodeShape && figure.getType() == "Intel") { + let channelPorts = figure.getChannelPorts(); + for (let k = 0; k < channelPorts.length; k++) { + const p = channelPorts[k]; + + if (!isVisible) { + p.setVisible(false); + } else { + // Show only ports that does not have any connection + if (!p.connections.data.length && p.parent.siblingChannel) { + p.setVisible(true); + } + } + } + } + } +} + +function delete_connections(connections, canvas, addToStack = true) { for (let i = 0; i < connections.length; i++) { const conn = connections[i]; @@ -137,7 +158,7 @@ function delete_connections(connections, canvas, addToStack=true) { canvas.getCommandStack().execute(cmd); } else { canvas.remove(conn); - } + } } } @@ -160,7 +181,7 @@ function connectBasedOnConfig(nodes, config, eth_switch) { } } else if (config == "loopback") { let fpgalink_cmd = `${nodes[0].getName()}:acl${i}:ch${j}-${nodes[0].getName()}:acl${i}:ch${j}`; - app.toolbar.createNodesAndConnections(fpgalink_cmd, 2, nodes, []) + app.toolbar.createNodesAndConnections(fpgalink_cmd, 2, nodes, []) } else if (config == "channel") { if (j % 2 == 0) { let fpgalink_cmd = `${nodes[0].getName()}:acl${i}:ch${j}-${nodes[0].getName()}:acl${i}:ch${j + 1}`; diff --git a/index.html b/index.html index eead10a..e2955f9 100755 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ FPGALink-GUI - + @@ -96,16 +96,17 @@ var get_decoded = decodeURI(window.location.search); const urlParams = new URLSearchParams(get_decoded); + if (urlParams.has('import')) { srun_cmd = urlParams.get('import'); - + // Special case to replace eth with eth00 srun_cmd = srun_cmd.replace(/eth(?!\d{2})/g, 'eth00') - + var get_node_type = ""; if (urlParams.has('node-type') && - (urlParams.get('node-type') == NodeTypeEnum.intel || + (urlParams.get('node-type') == NodeTypeEnum.intel || urlParams.get('node-type') == NodeTypeEnum.xilinx)) { get_node_type = urlParams.get('node-type'); } else { @@ -113,6 +114,9 @@ // Idea: If command has // * acl2, it has to be Xilinx // * chX, where X >= 2, it has to be Intel + + + if (srun_cmd.indexOf("acl2") > -1) { get_node_type = NodeTypeEnum.xilinx; }