24#include <opencv2/opencv.hpp>
34 if(signal == SIGTERM || signal == SIGINT) {
35 IRSOL_LOG_INFO(
"Signal {} received, shutting down gracefully...", signal);
40std::optional<std::pair<size_t, cv::Mat>>
47 std::string headerTitle;
50 auto res = conn.read(&ch, 1);
53 if(ch ==
'\n' || ch ==
'=')
58 if(headerTitle ==
"gi;") {
60 }
else if(headerTitle ==
"isn") {
64 isnStr.insert(isnStr.end(), ch);
66 uint64_t isn = std::stoull(isnStr);
68 }
else if(headerTitle ==
"img") {
72 uint32_t imageHeight{0};
73 uint32_t imageWidth{0};
77 auto res = conn.read(&ch, 1);
78 if(res.value() <= 0) {
91 std::string heightStr;
94 heightStr.insert(heightStr.end(), ch);
96 imageHeight = std::stol(heightStr);
101 widthStr.insert(widthStr.end(), ch);
103 imageWidth = std::stol(widthStr);
112 uint64_t expectedSize = imageHeight * imageWidth * 2;
113 std::vector<uint8_t> buffer(expectedSize);
115 size_t totalRead = 0;
116 while(totalRead < expectedSize) {
117 auto res = conn.read(buffer.data() + totalRead, expectedSize - totalRead);
118 if(res.value() <= 0) {
122 totalRead += res.value();
126 return std::make_pair(
133 auto res = conn.read(&ch, 1);
141std::optional<irsol::types::connector_t>
143 const std::string& host,
145 std::chrono::seconds retryTimeout = std::chrono::seconds(1))
152 "Failed to connect to server at {}:{}: {}, retrying in {} seconds",
156 retryTimeout.count());
157 std::this_thread::sleep_for(retryTimeout);
160 return std::move(conn);
172 std::string server_host =
"localhost";
175 sockpp::initialize();
181 conn = std::move(connOpt.value());
187 if(
auto res = conn.read_timeout(std::chrono::seconds(10)); !res) {
188 IRSOL_LOG_ERROR(
"Error setting TCP read timeout: {}", res.error_message());
193 auto lastTimeShown = irsol::types::clock_t::now() - std::chrono::seconds(1000);
195 bool firstFrame =
true;
202 auto frameStart = irsol::types::clock_t::now();
207 if(!imageOpt.has_value()) {
209 std::this_thread::sleep_for(std::chrono::seconds(1));
213 auto [imageId, image] = std::move(imageOpt.value());
216 std::this_thread::sleep_for(std::chrono::seconds(1));
223 "Image {} received: {}x{} with {} channels",
233 "ImageID: " + std::to_string(imageId),
235 cv::FONT_HERSHEY_COMPLEX,
244 auto frameNow = irsol::types::clock_t::now();
245 double actualFps = 1.0 / std::chrono::duration<double>(frameNow - lastTimeShown).count();
246 lastTimeShown = frameNow;
252 "Measured FPS: " + std::to_string(actualFps),
254 cv::FONT_HERSHEY_COMPLEX,
263 cv::imshow(
"Viewer", image);
264 int key = cv::waitKey(1) & 0xFF;
265 if(key == 27 || key ==
'q') {
271 auto frameEnd = irsol::types::clock_t::now();
272 auto frameDuration = frameEnd - frameStart;
274 auto desiredFrameTime = std::chrono::microseconds(
static_cast<int64_t
>(1'000'000.0 / inFps));
275 if(frameDuration < desiredFrameTime) {
276 std::this_thread::sleep_for(desiredFrameTime - frameDuration);
293 args::ArgumentParser parser(
"TCP client viewer");
294 args::HelpFlag help(parser,
"help",
"Display this help menu", {
'h',
"help"});
295 args::ValueFlag<double> listen_fps_flag(parser,
"fps",
"The FPS at which to listen.", {
'f'});
297 parser.ParseCLI(argc, argv);
298 }
catch(args::Help) {
301 }
catch(args::ParseError e) {
302 IRSOL_LOG_ERROR(
"Error parsing command-line arguments: {}\n", e.what(), parser.Help());
304 }
catch(args::ValidationError e) {
305 IRSOL_LOG_ERROR(
"Error parsing command-line arguments: {}\n", e.what(), parser.Help());
308 double listen_fps = 0.5;
309 if(listen_fps_flag) {
310 listen_fps = args::get(listen_fps_flag);
void initAssertHandler()
Initializes the assertion handler system.
#define IRSOL_LOG_INFO(...)
Logs an info-level message using the default logger.
#define IRSOL_LOG_ERROR(...)
Logs an error-level message using the default logger.
#define IRSOL_LOG_WARN(...)
Logs a warning-level message using the default logger.
#define IRSOL_LOG_DEBUG(...)
Logs a debug-level message using the default logger.
void initLogging(const char *fileSinkFilename="logs/irsol.log", std::optional< spdlog::level::level_enum > minLogLevel=std::nullopt)
Initializes the irsol logging system.
cv::Mat createCvMatFromIrsolServerBuffer(unsigned char *data, size_t rows, size_t cols)
Creates an OpenCV cv::Mat from a raw buffer received from the IRSOL server.
uint16_t port_t
Represents a network port number. Typically used to specify TCP or UDP ports.
sockpp::tcp_connector connector_t
Alias for the TCP client connector type.
std::string bytesToString(const std::vector< irsol::types::byte_t > &input)
Converts a std::vector of irsol::types::byte_t to a std::string.
static constexpr uint64_t max()
Returns the maximum representable pixel value for this bit depth.
static constexpr irsol::types::byte_t SOH
Start of Header (SOH) byte: 0x01.
static constexpr irsol::types::byte_t STX
Start of Text (STX) byte: 0x02.
std::optional< irsol::types::connector_t > createConnectionWithRetry(const std::string &host, irsol::types::port_t port, std::chrono::seconds retryTimeout=std::chrono::seconds(1))
std::optional< std::pair< size_t, cv::Mat > > queryImage(irsol::types::connector_t &conn)
std::atomic< bool > g_terminate
void signalHandler(int signal)