1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-23 00:00:01 +01:00
VILLASnode/fpga/lib/ip_node.cpp
2018-06-04 13:24:57 +02:00

125 lines
3 KiB
C++

#include <map>
#include <stdexcept>
#include <jansson.h>
#include <villas/utils.hpp>
#include <villas/fpga/card.hpp>
#include <villas/fpga/ip_node.hpp>
#include <villas/fpga/ips/switch.hpp>
namespace villas {
namespace fpga {
namespace ip {
bool
IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
{
auto& ipNode = reinterpret_cast<IpNode&>(ip);
auto logger = getLogger();
json_t* json_ports = json_object_get(json_ip, "ports");
if(not json_is_array(json_ports)) {
logger->debug("IP has no ports");
return true;
}
size_t index;
json_t* json_port;
json_array_foreach(json_ports, index, json_port) {
if(not json_is_object(json_port)) {
logger->error("Port {} is not an object", index);
return false;
}
const char *role_raw, *target_raw, *name_raw;
int ret = json_unpack(json_port, "{ s: s, s: s, s: s }",
"role", &role_raw,
"target", &target_raw,
"name", &name_raw);
if(ret != 0) {
logger->error("Cannot parse port {}", index);
return false;
}
const auto tokens = utils::tokenize(target_raw, ":");
if(tokens.size() != 2) {
logger->error("Cannot parse 'target' of port {}", index);
return false;
}
int port_num;
try {
port_num = std::stoi(tokens[1]);
} catch(const std::invalid_argument&) {
logger->error("Target port number is not an integer: '{}'", target_raw);
return false;
}
IpNode::StreamPort port;
port.nodeName = tokens[0];
port.portNumber = port_num;
const std::string role(role_raw);
if(role == "master" or role == "initiator") {
ipNode.portsMaster[name_raw] = port;
} else /* slave */ {
ipNode.portsSlave[name_raw] = port;
}
}
return true;
}
std::pair<std::string, std::string>
IpNode::getLoopbackPorts() const
{
for(auto& [masterName, masterTo] : portsMaster) {
for(auto& [slaveName, slaveTo] : portsSlave) {
// TODO: should we also check which IP both ports are connected to?
if(masterTo.nodeName == slaveTo.nodeName) {
return { masterName, slaveName };
}
}
}
return { "", "" };
}
bool
IpNode::loopbackPossible() const
{
auto ports = getLoopbackPorts();
return (not ports.first.empty()) and (not ports.second.empty());
}
bool
IpNode::connectLoopback()
{
auto ports = getLoopbackPorts();
const auto& portMaster = portsMaster[ports.first];
const auto& portSlave = portsSlave[ports.second];
logger->debug("master port: {}", ports.first);
logger->debug("slave port: {}", ports.second);
logger->debug("switch at: {}", portMaster.nodeName);
// TODO: verify this is really a switch!
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
card->lookupIp(portMaster.nodeName));
if(axiStreamSwitch == nullptr) {
logger->error("Cannot find switch");
return false;
}
// switch's slave port is our master port and vice versa
return axiStreamSwitch->connect(portMaster.portNumber, portSlave.portNumber);
}
} // namespace ip
} // namespace fpga
} // namespace villas