Skip to content

Commit

Permalink
Merge pull request #16 from Huzifa1/master
Browse files Browse the repository at this point in the history
Fix Bugs + Update the README
  • Loading branch information
deffel authored Nov 4, 2024
2 parents 9ca7b5e + 7fc2fea commit e862cb1
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 97 deletions.
57 changes: 31 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

2 changes: 2 additions & 0 deletions gui/NodeShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down
7 changes: 7 additions & 0 deletions gui/SwitchShape.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
90 changes: 26 additions & 64 deletions gui/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ example.Toolbar = Class.extend({
this.redoButton = $("<button>Redo</button>");
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);

Expand Down Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
27 changes: 24 additions & 3 deletions gui/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand All @@ -137,7 +158,7 @@ function delete_connections(connections, canvas, addToStack=true) {
canvas.getCommandStack().execute(cmd);
} else {
canvas.remove(conn);
}
}
}
}

Expand All @@ -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}`;
Expand Down
12 changes: 8 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<title>FPGALink-GUI</title>
<!-- powered by at least five blockchains! -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

Expand Down Expand Up @@ -96,23 +96,27 @@
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 {
// Apply minor heuristic if command is for Xilinx or Intel.
// 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;
}
Expand Down

0 comments on commit e862cb1

Please sign in to comment.