mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-23 00:00:01 +01:00

Logging is used everywhere and there's no justification of the clutter and runtime overhead of `aut logger = getLogger();` everywhere.
124 lines
2.9 KiB
C++
124 lines
2.9 KiB
C++
#include <map>
|
|
#include <stdexcept>
|
|
#include <jansson.h>
|
|
|
|
#include "utils.hpp"
|
|
#include "fpga/ip_node.hpp"
|
|
#include "fpga/ips/switch.hpp"
|
|
#include "fpga/card.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
|