diff --git a/src/common/server/NetRemoteServerConfiguration.cxx b/src/common/server/NetRemoteServerConfiguration.cxx index fe9930ca..ec983942 100644 --- a/src/common/server/NetRemoteServerConfiguration.cxx +++ b/src/common/server/NetRemoteServerConfiguration.cxx @@ -45,17 +45,17 @@ ConfigureCliAppOptions(CLI::App& app, NetRemoteServerConfiguration& config) ->default_val(NetRemoteServerConfiguration::LogVerbosityDefault); app.add_option( - "-at, --att-type", + "-t,--att-type", config.RfAttenuatorConfiguration.Type, "The type of RF attenuator to use. Supported types: 'none', 'software', 'socket' (default: 'none')"); app.add_option( - "-aa, --att-address", + "-i,--att-address", config.RfAttenuatorConfiguration.Address, "The address of the RF attenuator. This is only used if the type is 'socket'"); app.add_option( - "-ap, --att-port", + "-p,--att-port", config.RfAttenuatorConfiguration.Port, "The port of the RF attenuator. This is only used if the type is 'socket'"); return app; diff --git a/src/linux/rfattenuator/lib/RfAttenuatorAeroflexWeinschle83XX.hxx b/src/linux/rfattenuator/lib/RfAttenuatorAeroflexWeinschle83XX.hxx index 3f8196b3..09c33a06 100644 --- a/src/linux/rfattenuator/lib/RfAttenuatorAeroflexWeinschle83XX.hxx +++ b/src/linux/rfattenuator/lib/RfAttenuatorAeroflexWeinschle83XX.hxx @@ -66,8 +66,9 @@ struct RfAttenuatorAeroflexWeinschle83XXFactory : public IRfAttenuatorWithTcpCon // These values have been determined from experimentation. static constexpr uint32_t ReceiveSize{ 1024 }; - static constexpr auto ReceiveDelay{ 1s }; - static constexpr auto SettlingTime{ 1s }; + // We don't need extra delay for receiving data, the delay is handled by select timeout argument. + static constexpr auto ReceiveDelay{ 0s }; + static constexpr auto SettlingTime{ 0s }; static constexpr TcpTransportConfiguration TransportConfiguration{ .ReceiveSize = ReceiveSize, diff --git a/src/linux/rfattenuator/lib/SocketHelpers.cxx b/src/linux/rfattenuator/lib/SocketHelpers.cxx index 2bcb8b71..1134f2ed 100644 --- a/src/linux/rfattenuator/lib/SocketHelpers.cxx +++ b/src/linux/rfattenuator/lib/SocketHelpers.cxx @@ -9,13 +9,26 @@ namespace detail { // Timeout to wait for a socket to become ready for Transmit (send()) operation. +// +// On Linux, the network takes longer time to receive the response from the AFW83 attenuator. +// Tested, it take 3 seconds to receive the response after sending the GetProperties request. +// If SettingTime is set to 1, then after GetProperties request, the response is partially received (Only the first line, *IDN?). +// After this, if we send another request, then the rest of GetProperties will be received along with the response of the second request. +// Like below +// Request: *IDN? +// AdaptResponse: *IDN? +// Request: CHAN 1; ATTN? <-- The second request is sent before all reponse of the first request is received. +// AdaptResponse: CHAN 1; ATTN? +// Weinschel, 8311-352-9-TN, 386, V2.98 <-- this is the rest of GetProperties response +// 103.00 +// +// GetAttenuation takes 2 seconds to receive the response. +// +// 3 seconds is a good value to ensure that the response for different type of request is fully received. timeval TransmitReadyTimeout{ - .tv_sec = 1, // 1 second + .tv_sec = 3, // 3 seconds .tv_usec = 0 }; - -// Timeout to wait for a socket to become ready for Receive (recv()) operation. -timeval ReceiveReadyTimeout = TransmitReadyTimeout; } // namespace detail namespace SocketHelpers @@ -91,7 +104,8 @@ Transmit(const int& socket, std::span buffer) FD_SET(socket, &writeSet); // Wait for socket write buffer to become ready for data. - const auto numSocketsReady = select(0, nullptr, &writeSet, nullptr, &detail::TransmitReadyTimeout); + auto readyTimeout = detail::TransmitReadyTimeout; + const auto numSocketsReady = select(socket + 1, nullptr, &writeSet, nullptr, &readyTimeout); if (numSocketsReady < 0) { throw SocketHelperException(std::format("Error while waiting for socket write buffer to become ready for data with errno=0x{:08x}", errno).c_str(), errno); } else if (numSocketsReady == 0) { @@ -128,7 +142,22 @@ Receive(const int& socket, std::span buffer, std::chrono::milliseconds FD_SET(socket, &readSet); // Wait for data to become available for reading on the socket. - const auto numSocketsReady = select(0, &readSet, nullptr, nullptr, &detail::ReceiveReadyTimeout); + // + // On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1 + // permits either behavior.) This causes problems both when Linux + // code which reads timeout is ported to other operating systems, and + // when code is ported to Linux that reuses a struct timeval for + // multiple select()s in a loop without reinitializing it. Consider + // timeout to be undefined after select() returns. + // + // So, we need to reinitialize the timeout value for each select() call. Tested on Ubuntu 24.10, readyTimeout will be changed to 0. + // After the select() call, the next select will return immediately if reuse the variable without reinitializing it. + // + // SettlingTime and ReceiveDelay may be originally introduced to mitigate this issue without reinitializing the timeout value. + // With this change, we can techinically remove the SettlingTime and ReceiveDelay. I will keep them in case we need tune them in the future. + // But I set both of them to 0s for now to avoid unnecessary delay. + auto readyTimeout = detail::TransmitReadyTimeout; + const auto numSocketsReady = select(socket + 1, &readSet, nullptr, nullptr, &readyTimeout); if (numSocketsReady < 0) { throw SocketHelperException(std::format("Error while waiting for data to become available with errno=0x{:08x}", errno).c_str(), errno); } else if (numSocketsReady == 0) {