Skip to content

Commit 94a397d

Browse files
committed
mvlc-cli: implement new send_eth_delay command
Simple command to send EthDelay (0x0207) commands to the MVLC ETH delay port.
1 parent ff5d40f commit 94a397d

File tree

4 files changed

+104
-31
lines changed

4 files changed

+104
-31
lines changed

extras/mvlc-cli/mvlc-cli.cc

+68
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <mesytec-mvlc/mesytec-mvlc.h>
88
#include <mesytec-mvlc/mvlc_impl_eth.h>
99
#include <mesytec-mvlc/mvlc_impl_usb.h>
10+
#include <mesytec-mvlc/util/udp_sockets.h>
1011
#include <yaml-cpp/yaml.h>
1112
#include <yaml-cpp/emittermanip.h>
1213

@@ -1138,6 +1139,72 @@ usage: mvlc-cli show_usb_devices [--all-devices]
11381139
.exec = show_usb_devices,
11391140
};
11401141

1142+
// Note: This does not connect an MVLC instance as that class does way too much
1143+
// work for this use case and the InUse detection would get in our way. Instead
1144+
// the MVLC instance is created to get the remote host address and then a socket
1145+
// for sending data to the MVLC eth delay port is created and used.
1146+
DEF_EXEC_FUNC(send_eth_delay_command)
1147+
{
1148+
spdlog::trace("entered send_eth_delay_command()");
1149+
1150+
auto &parser = ctx.parser;
1151+
trace_log_parser_info(parser, "send_eth_delay_command");
1152+
1153+
auto delay = parse_unsigned<u16>(parser[2]);
1154+
1155+
if(!delay)
1156+
{
1157+
std::cerr << "Error: invalid delay value given\n";
1158+
return 1;
1159+
}
1160+
1161+
auto mvlc = make_mvlc_from_standard_params(parser);
1162+
1163+
if (!mvlc)
1164+
return 1;
1165+
1166+
auto ethImpl = dynamic_cast<eth::Impl *>(mvlc.getImpl());
1167+
1168+
if (!ethImpl)
1169+
{
1170+
std::cerr << "Error: send_eth_delay command requires an ETH connection\n";
1171+
return 1;
1172+
}
1173+
1174+
std::error_code ec;
1175+
auto remote = ethImpl->getRemoteAddress();
1176+
int sock = eth::connect_udp_socket(remote, eth::DelayPort, &ec);
1177+
1178+
if (ec || sock < 0)
1179+
{
1180+
std::cerr << fmt::format("Error: could not connect to remote address '{}': {}\n",
1181+
remote, ec.message());
1182+
return 1;
1183+
}
1184+
1185+
if (auto ec = eth::send_delay_command(sock, delay.value()))
1186+
{
1187+
std::cerr << fmt::format("Error: could not send EthDelay command: {}\n", ec.message());
1188+
return 1;
1189+
}
1190+
1191+
std::cout << fmt::format("Sent EthDelay command to {} with delay {} µs\n", remote, delay.value());
1192+
return 0;
1193+
}
1194+
1195+
static const Command SendEthDelayCommand
1196+
{
1197+
.name = "send_eth_delay",
1198+
.description = "Send an EthDelay command to the MVLC",
1199+
.help = R"~(
1200+
usage: mvlc-cli [--mvlc <url/ip>] send_eth_delay <delay_µs>
1201+
1202+
Send an EthDelay command to the MVLC with the given delay in microseconds.
1203+
Delay is a 16-bit value, max is 65535 µs.
1204+
)~",
1205+
.exec = send_eth_delay_command,
1206+
};
1207+
11411208
int main(int argc, char *argv[])
11421209
{
11431210
std::string generalHelp = R"~(
@@ -1231,6 +1298,7 @@ MVLC connection URIs:
12311298
ctx.commands.insert(VmeWriteCommand);
12321299
ctx.commands.insert(DumpRegistersCommand);
12331300
ctx.commands.insert(ShowUsbDevicesCommand);
1301+
ctx.commands.insert(SendEthDelayCommand);
12341302
ctx.parser = parser;
12351303

12361304
// mvlc-cli // show generalHelp

src/mesytec-mvlc/mvlc_impl_eth.cc

+30-30
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,6 @@
4444

4545
using namespace mesytec::mvlc;
4646

47-
namespace
48-
{
49-
50-
static const unsigned DefaultWriteTimeout_ms = 500;
51-
static const unsigned DefaultReadTimeout_ms = 500;
52-
53-
// Amount of receive buffer space requested from the OS for both the command
54-
// and data sockets. It's not considered an error if less buffer space is
55-
// granted.
56-
static const int DesiredSocketReceiveBufferSize = 1024 * 1024 * 10;
57-
5847
/* Ethernet throttling implementation:
5948
* The MVLC now has a new 'delay pipe' on port 0x8002. It accepts delay
6049
* commands only and doesn't send any responses. Delay commands carry a 16-bit
@@ -75,22 +64,22 @@ static const int DesiredSocketReceiveBufferSize = 1024 * 1024 * 10;
7564
* fill level.
7665
*/
7766

78-
std::error_code send_delay_command(int delaySock, u16 delay_us)
67+
namespace mesytec::mvlc::eth
7968
{
80-
u32 cmd = static_cast<u32>(super_commands::SuperCommandType::EthDelay) << super_commands::SuperCmdShift;
81-
cmd |= delay_us;
82-
83-
size_t bytesTransferred = 0;
84-
auto ec = eth::write_to_socket(delaySock, reinterpret_cast<const u8 *>(&cmd), sizeof(cmd), bytesTransferred);
69+
std::error_code send_delay_command(int delaySock, u16 delay_us);
70+
}
8571

86-
if (ec)
87-
return ec;
72+
namespace
73+
{
74+
using namespace mesytec::mvlc::eth;
8875

89-
if (bytesTransferred != sizeof(cmd))
90-
return make_error_code(MVLCErrorCode::ShortWrite);
76+
static const unsigned DefaultWriteTimeout_ms = 500;
77+
static const unsigned DefaultReadTimeout_ms = 500;
9178

92-
return {};
93-
};
79+
// Amount of receive buffer space requested from the OS for both the command
80+
// and data sockets. It's not considered an error if less buffer space is
81+
// granted.
82+
static const int DesiredSocketReceiveBufferSize = 1024 * 1024 * 10;
9483

9584
// This code increases the delay value by powers of two. The max value is 64k
9685
// so we need 16 steps to reach the maximum.
@@ -497,12 +486,25 @@ void mvlc_eth_throttler(
497486

498487
} // end anon namespace
499488

500-
namespace mesytec
489+
namespace mesytec::mvlc::eth
501490
{
502-
namespace mvlc
503-
{
504-
namespace eth
491+
492+
std::error_code send_delay_command(int delaySock, u16 delay_us)
505493
{
494+
u32 cmd = static_cast<u32>(super_commands::SuperCommandType::EthDelay) << super_commands::SuperCmdShift;
495+
cmd |= delay_us;
496+
497+
size_t bytesTransferred = 0;
498+
auto ec = eth::write_to_socket(delaySock, reinterpret_cast<const u8 *>(&cmd), sizeof(cmd), bytesTransferred);
499+
500+
if (ec)
501+
return ec;
502+
503+
if (bytesTransferred != sizeof(cmd))
504+
return make_error_code(MVLCErrorCode::ShortWrite);
505+
506+
return {};
507+
};
506508

507509
Impl::Impl(const std::string &host)
508510
: m_host(host)
@@ -1242,6 +1244,4 @@ s32 calc_packet_loss(u16 lastPacketNumber, u16 packetNumber)
12421244
return diff - 1;
12431245
}
12441246

1245-
} // end namespace eth
1246-
} // end namespace mvlc
1247-
} // end namespace mesytec
1247+
}

src/mesytec-mvlc/mvlc_impl_eth.h

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class MESYTEC_MVLC_EXPORT Impl: public MVLCBasicInterface, public MVLC_ETH_Inter
108108

109109
// Returns the host/IP string given to the constructor.
110110
std::string getHost() const { return m_host; }
111+
std::string getRemoteAddress() const { return getHost(); }
111112

112113
sockaddr_in getCmdSockAddress() const { return m_cmdAddr; }
113114
sockaddr_in getDataSockAddress() const { return m_dataAddr; }
@@ -167,6 +168,10 @@ class MESYTEC_MVLC_EXPORT Impl: public MVLCBasicInterface, public MVLC_ETH_Inter
167168
// packets in-between, taking overflow into account.
168169
s32 MESYTEC_MVLC_EXPORT calc_packet_loss(u16 lastPacketNumber, u16 packetNumber);
169170

171+
// Sends an EthDelay (0x0207) command packet through the given socket.
172+
// No response data; the MVLC delay port is write only.
173+
std::error_code send_delay_command(int delaySock, u16 delay_us);
174+
170175
}
171176

172177
#endif /* __MESYTEC_MVLC_MVLC_IMPL_UDP_H__ */

src/mesytec-mvlc/mvlc_readout_worker.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ std::pair<std::error_code, size_t> readout_usb(
562562

563563
const size_t bytesToRead = usb::USBStreamPipeReadSize;
564564
size_t totalBytesTransferred = 0;
565-
size_t readCycles = 0;
565+
[[maybe_unused]] size_t readCycles = 0;
566566
std::error_code ec;
567567

568568
while (dest.size() >= bytesToRead && sw.get_elapsed() < timeout)

0 commit comments

Comments
 (0)