From 0115c99d086a1bbdffa43f9e511df04e0d6dd051 Mon Sep 17 00:00:00 2001 From: Heinrich Riebler Date: Thu, 14 Sep 2023 09:39:53 +0200 Subject: [PATCH] Added Ethernet Switch. --- gui/SelectionMenuPolicy.js | 5 + gui/SwitchShape.js | 96 ++++++++++++++++++ gui/Toolbar.js | 199 ++++++++++++++++++++++++------------- gui/Util.js | 30 ++++++ gui/View.js | 13 ++- index.html | 28 +++--- 6 files changed, 286 insertions(+), 85 deletions(-) create mode 100755 gui/SwitchShape.js diff --git a/gui/SelectionMenuPolicy.js b/gui/SelectionMenuPolicy.js index 7dc44da..d26ff2f 100755 --- a/gui/SelectionMenuPolicy.js +++ b/gui/SelectionMenuPolicy.js @@ -98,6 +98,11 @@ var SelectionMenuPolicy = draw2d.policy.figure.SelectionPolicy.extend({ var num_to_delete = parseInt(figure.getName().substring(1)); for (i = 0; i < fpganodes.getSize(); i++) { var node = fpganodes.get(i); + + if (node.NAME != "NodeShape") { + continue; + } + var nodeLabel = node.getLabel(); var nodeNum = parseInt(nodeLabel.getText().substring(1)); // Update all nodes that have greater num than the node to delete. diff --git a/gui/SwitchShape.js b/gui/SwitchShape.js new file mode 100755 index 0000000..1d811ba --- /dev/null +++ b/gui/SwitchShape.js @@ -0,0 +1,96 @@ +// +SwitchShape = draw2d.shape.basic.Label.extend({ + NAME: "SwitchShape", + + ORIENTATION_PROPERTIES: Object.freeze({ + [OrientationEnum.north]: { + "rotationAngle": 0, + "padding": { left: 25, top: 5, right: 25, bottom: 5 }, + "locator": new draw2d.layout.locator.BottomLocator(), + }, + [OrientationEnum.east]: { + "rotationAngle": 0, + "padding": { left: 25, top: 5, right: 25, bottom: 5 }, + "locator": new draw2d.layout.locator.RightLocator(), + }, + [OrientationEnum.south]: { + "rotationAngle": 0, + "padding": { left: 25, top: 5, right: 25, bottom: 5 }, + "locator": new draw2d.layout.locator.TopLocator(), + }, + [OrientationEnum.west]: { + "rotationAngle": 0, + "padding": { left: 25, top: 5, right: 25, bottom: 5 }, + "locator": new draw2d.layout.locator.LeftLocator(), + }, + }), + + init: function (attr) { + this._super($.extend({}, attr)); + + this.setText("Ethernet Switch"); + + // Allows multiple connections. + this.linksToChannel = []; + + // Shape for view. + this.connector; + this.isDrawn = false; + let port = this.createPort("hybrid"); + port.setName("inout_" + this.id); + // port.setMaxFanOut(1); + // port.on("connect", function () { + // this.setVisible(false); + // }, port); + // port.on("disconnect", function () { + // this.setVisible(true); + // }, port); + + // this.orientation = attr.orientation; + this.setOrientation(attr.orientation, false); + // this.getFPGA().channelLayout.add(this); + }, + + setLinksToChannel: function (partner) { + this.linksToChannel.push(partner); + }, + + // TODO: update to array structure of switch. + // getLinksToChannel: function () { + // return this.linksToChannel; + // }, + + setIsDrawn: function (isDrawn) { + this.isDrawn = isDrawn; + }, + + getIsDrawn: function () { + return this.isDrawn; + }, + + setConnector: function (connector) { + this.connector = connector; + }, + + getConnector: function () { + return this.connector; + }, + + getOrientation: function () { + return this.orientation; + }, + + setOrientation: function (orientation, repaint = true) { + this.orientation = orientation; + let prop = this.ORIENTATION_PROPERTIES[orientation]; + this.getHybridPort(0).setLocator(prop.locator); + this.rotationAngle = prop.rotationAngle; + this.height = 0; + this.setPadding(prop.padding); + + if (repaint) { + this.repaint(); + } + } +}); + diff --git a/gui/Toolbar.js b/gui/Toolbar.js index abbc645..adaa0e6 100755 --- a/gui/Toolbar.js +++ b/gui/Toolbar.js @@ -200,6 +200,7 @@ example.Toolbar = Class.extend({ var srun_N_needle = "-N "; var srun_N = -1; var fpgalinks = []; + let with_ethernet = false; // Look for -N argument. var i = 0; @@ -210,17 +211,23 @@ example.Toolbar = Class.extend({ } else { // -N not available. Pre-process command: - // Pre-process command for "n2fpga.." node id to replace - // with "n00.." node names. - var regFPGA = /(n2fpga\d{2}):(acl[012]{1}):(ch[0123]{1})-(n2fpga\d{2}):(acl[012]{1}):(ch[0123]{1})/g; + // Pre-process command for "n2fpga.." node id to replace with "n.." node names. + var regFPGA = /((n2fpga\d{2}):(acl[012]{1}):(ch[0123]{1})|eth)-((n2fpga\d{2}):(acl[012]{1}):(ch[0123]{1})|eth)/g; var resultFPGA; const mapFPGA = new Map(); while ((resultFPGA = regFPGA.exec(srun_raw)) !== null) { // fpgalinks.push(result); - - mapFPGA.set(resultFPGA[1], 1); - mapFPGA.set(resultFPGA[4], 1); + if (resultFPGA[1] != "eth") { + mapFPGA.set(resultFPGA[2], 1); + } else { + with_ethernet = true; + } + if (resultFPGA[5] != "eth") { + mapFPGA.set(resultFPGA[6], 1); + } else { + with_ethernet = true; + } // console.log(resultFPGA); } @@ -236,20 +243,27 @@ example.Toolbar = Class.extend({ // console.log(srun_raw); - - // return ; - // salloc: SPANK_FPGALINK0=n00:acl0:ch3-n00:acl1:ch3 salloc: SPANK_FPGALINK1=n00:acl0:ch2-n00:acl1:ch2 salloc: SPANK_FPGALINK2=n00:acl0:ch0-n00:acl1:ch0 salloc: SPANK_FPGALINK3=n00:acl0:ch1-n00:acl1:ch1 - var reg = /(n[01]{1}\d{1}):(acl[012]{1}):(ch[0123]{1})-(n[01]{1}\d{1}):(acl[012]{1}):(ch[0123]{1})/g; + var reg = /((n[01]{1}\d{1}):(acl[012]{1}):(ch[0123]{1})|eth)-((n[01]{1}\d{1}):(acl[012]{1}):(ch[0123]{1})|eth)/g; var result; const mapN = new Map(); + // result: Array(9) [ "n00:acl0:ch1-n00:acl2:ch0", "n00:acl0:ch1", "n00", "acl0", "ch1", "n00:acl2:ch0", "n00", "acl2", "ch0" ] while ((result = reg.exec(srun_raw)) !== null) { fpgalinks.push(result); - mapN.set(result[1], 1); - mapN.set(result[4], 1); + if (result[1] != "eth") { + mapN.set(result[2], 1); + } else { + with_ethernet = true; + } + if (result[5] != "eth") { + mapN.set(result[6], 1); + } else { + with_ethernet = true; + } + // console.log(result); } @@ -257,6 +271,19 @@ example.Toolbar = Class.extend({ srun_N = mapN.size; } + // Create Ethernet switch if required. + var eth_switch = null; + if (with_ethernet) { + var pos_y = 20; + var pos_x = 200; + + eth_switch = new SwitchShape({ "orientation": OrientationEnum.north }) + + // create a command for the undo/redo support + var command = new draw2d.command.CommandAdd(this.view, eth_switch, pos_x, pos_y); + this.view.getCommandStack().execute(command); + } + // Create fpganodes. var fpganodes = []; var pos_y = 20; @@ -697,30 +724,47 @@ example.Toolbar = Class.extend({ var links = full_match.split("-"); // Point 1 (think of source). - // value: n00:acl0:ch0 + // value: n00:acl0:ch0 or eth (for Ethernet switch). var link_p1 = links[0].split(":"); - // 0: n00 - // 1: acl0 - // 2: ch0 - // Set the link. - // Get node. - var tnode_p1 = fpganodes[this.getNodeIdFpgalink(link_p1[0])]; - // Get FPGA. - var tfpga_p1 = tnode_p1.getFPGAFromFpgalink(link_p1[1]); - // Point 2 (think of destination). + // value: n00:acl0:ch0 or eth (for Ethernet switch). var link_p2 = links[1].split(":"); - // 0: n00 - // 1: acl0 - // 2: ch0 - // Set the link. - // Get node. - var tnode_p2 = fpganodes[this.getNodeIdFpgalink(link_p2[0])]; - // Get FPGA. - var tfpga_p2 = tnode_p2.getFPGAFromFpgalink(link_p2[1]); + + // 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 = fpganodes[this.getNodeIdFpgalink(link_p1[0])]; + // 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 = eth_switch; + } + + if (link_p2.length == 3) { + // Channel is to FPGA node. + + // Get node. + var tnode_p2 = fpganodes[this.getNodeIdFpgalink(link_p2[0])]; + // 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 = eth_switch; + } // Get channels, connect and draw them. - this.connectChannels(tfpga_p1.getChannelFromFpgalink(link_p1[2]), tfpga_p2.getChannelFromFpgalink(link_p2[2])); + this.connectChannels(chan0, chan1); // if(link_p1[2] == "ch0") { // tfpga_p1.getChannelFromFpgalink(link_p1[2]).getConnector().setColor(ColorEnum.red); @@ -733,43 +777,62 @@ example.Toolbar = Class.extend({ srun_raw_copy = srun_raw_copy.substring(next_space); } + // Parse and add fpga links: n00:acl0:ch0-n00:acl1:ch0 - // - // Array(7) [ "n00:acl1:ch0-n00:acl1:ch1", "00", "1", "0", "00", "1", "1" ] - for (var i = 0; i < fpgalinks.length; i++) { - // Point 1 (think of source). - // 0: n00 - // 1: acl0 - // 2: ch0 - // Set the link. - // Get node. - var tnode_p1 = fpganodes[this.getNodeIdFpgalink(fpgalinks[i][1])]; - // Get FPGA. - var tfpga_p1 = tnode_p1.getFPGAFromFpgalink(fpgalinks[i][2]); - // Point 2 (think of destination). - // 0: n00 - // 1: acl0 - // 2: ch0 - // Set the link. - // Get node. - var tnode_p2 = fpganodes[this.getNodeIdFpgalink(fpgalinks[i][4])]; - // Get FPGA. - var tfpga_p2 = tnode_p2.getFPGAFromFpgalink(fpgalinks[i][5]); - - // Get channels, connect and draw them. - this.connectChannels( - tfpga_p1.getChannelFromFpgalink(fpgalinks[i][3]), - tfpga_p2.getChannelFromFpgalink(fpgalinks[i][6]) - ); - - // if(link_p1[2] == "ch0") { - // tfpga_p1.getChannelFromFpgalink(link_p1[2]).getConnector().setColor(ColorEnum.red); - // } - } + 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 = fpganodes[this.getNodeIdFpgalink(link_p1[0])]; + // 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 = eth_switch; + } + if (link_p2.length == 3) { + // Channel is to FPGA node. + // Get node. + var tnode_p2 = fpganodes[this.getNodeIdFpgalink(link_p2[0])]; + // 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 = eth_switch; + } + // Get channels, connect and draw them. + this.connectChannels(chan0, chan1); + } + } + + + }, makeGrid: function (N, width) { @@ -873,7 +936,7 @@ example.Toolbar = Class.extend({ // Draw them in View. // // Draw connection only ones. - if (!tchannel_p1.getIsDrawn()) { + // if (!tchannel_p1.getIsDrawn()) { var c = new HoverConnection(); c.setSource(tchannel_p1.getHybridPort(0)); @@ -883,14 +946,14 @@ example.Toolbar = Class.extend({ tchannel_p1.setConnector(c); tchannel_p2.setConnector(c); - // Flag both connectors as drawn. - tchannel_p1.setIsDrawn(true); - tchannel_p2.setIsDrawn(true); + // // Flag both connectors as drawn. + // tchannel_p1.setIsDrawn(true); + // tchannel_p2.setIsDrawn(true); // create a command for the undo/redo support var command = new draw2d.command.CommandAdd(this.view, c, 0, 0); this.view.getCommandStack().execute(command); - } + // } }, arrangeTopology: function (topology_name, fpganodes) { diff --git a/gui/Util.js b/gui/Util.js index 281a747..f1c649c 100644 --- a/gui/Util.js +++ b/gui/Util.js @@ -10,3 +10,33 @@ function pad_node_name(num) { var s = "0" + num; return "n" + s.substr(s.length - 2); } + +function generate_fpgalink_output(channel) { + let fpgalink = ""; + // channel is either of type ChannelShape (if connected to FPGA node) + // or "Ethernet Switch" (if connected to the switch) + if(channel.getText() == "Ethernet Switch") { + fpgalink = "eth"; + } else { + var parent_fpga = channel.getFPGA(); + var parent_node = parent_fpga.getNode(); + + fpgalink = parent_node.getName() + ":" + parent_fpga.getName() + ":" + channel.getText(); + } + + return fpgalink; +} + +function get_number_of_fpga_nodes(figures) { + let number_of_fpga_nodes = 0; + + let figure = figures.data; + + for(let i = 0; i < figure.length; i++) { + if (figure.at(i).NAME == "NodeShape") { + number_of_fpga_nodes++ + } + } + + return number_of_fpga_nodes; +} diff --git a/gui/View.js b/gui/View.js index 04fa54e..119be5d 100755 --- a/gui/View.js +++ b/gui/View.js @@ -27,7 +27,8 @@ example.View = draw2d.Canvas.extend({ getNodeNameNew: function () { var newname = "n"; - var numnodes = this.getFigures().getSize(); + // var numnodes = this.getFigures().getSize(); + var numnodes = get_number_of_fpga_nodes(this.getFigures()); if (numnodes < 10) { newname += "0"; @@ -105,9 +106,17 @@ example.View = draw2d.Canvas.extend({ console.log("unknown shape."); } + break; + case "node-ethernet-switch": + var eth_switch = new SwitchShape({ "orientation": $(droppedDomNode).data("shape") }) + + // create a command for the undo/redo support + var command = new draw2d.command.CommandAdd(this, eth_switch, x, y); + this.getCommandStack().execute(command); + break; default : - console.log("unknown type."); + console.log("unknown type: \"" + $(droppedDomNode).data("type") + "\"."); } } diff --git a/index.html b/index.html index fd4468b..fd9e17d 100755 --- a/index.html +++ b/index.html @@ -25,6 +25,7 @@ +