|
|
@@ -1,5 +1,3 @@
|
|
|
-#include "ndi_interface.h"
|
|
|
-
|
|
|
#include "core/basic_obj_types.hpp"
|
|
|
#include "core/small_obj.hpp"
|
|
|
#include "utility/config_utility.hpp"
|
|
|
@@ -30,6 +28,12 @@
|
|
|
#include <boost/smart_ptr/scoped_ptr.hpp>
|
|
|
#include <boost/system/error_code.hpp>
|
|
|
|
|
|
+#ifdef BOOST_OS_WINDOWS_AVAILABLE
|
|
|
+
|
|
|
+#include <winbase.h> // for sending serial break
|
|
|
+
|
|
|
+#endif // BOOST_OS_WINDOWS_AVAILABLE
|
|
|
+
|
|
|
#include <fmt/format.h>
|
|
|
#include <spdlog/spdlog.h>
|
|
|
|
|
|
@@ -40,6 +44,8 @@
|
|
|
|
|
|
#include "utility/assert_utility.h"
|
|
|
|
|
|
+DEFAULT_TRISTATE_OBJ_DEF(ndi_interface)
|
|
|
+
|
|
|
namespace sophiar {
|
|
|
|
|
|
using boost::asio::async_read;
|
|
|
@@ -100,7 +106,6 @@ namespace sophiar {
|
|
|
|
|
|
static constexpr auto default_tracking_interval = std::chrono::milliseconds(17); // 60Hz
|
|
|
static constexpr uint16_t default_ndi_port = 8765;
|
|
|
- static constexpr auto stream_queue_size = 4;
|
|
|
static constexpr auto ndi_endian = boost::endian::order::little;
|
|
|
|
|
|
static constexpr uint16_t binary_reply_header_magic = 0xA5C4;
|
|
|
@@ -118,9 +123,6 @@ namespace sophiar {
|
|
|
using reply_callback_type = std::function<void(dynamic_memory::pointer &&)>;
|
|
|
string_map<reply_callback_type> stream_reply_callback_pool;
|
|
|
|
|
|
- using streambuf_type = basic_streambuf<DYNAMIC_ALLOCATOR(char) >;
|
|
|
- streambuf_type ascii_buf;
|
|
|
-
|
|
|
ndi_address_type address_type;
|
|
|
|
|
|
// If address type is ethernet
|
|
|
@@ -189,6 +191,7 @@ namespace sophiar {
|
|
|
return async_read_value<ndi_endian, T>(*ndi_tcp_socket);
|
|
|
}
|
|
|
assert(false);
|
|
|
+ __builtin_unreachable();
|
|
|
}
|
|
|
|
|
|
template<WriteableMemory MemoryType>
|
|
|
@@ -199,6 +202,7 @@ namespace sophiar {
|
|
|
return async_fill_memory_from(*ndi_tcp_socket, mem);
|
|
|
}
|
|
|
assert(false);
|
|
|
+ __builtin_unreachable();
|
|
|
}
|
|
|
|
|
|
awaitable<dynamic_memory::pointer> read_binary_reply(uint16_t header_magic) {
|
|
|
@@ -280,16 +284,20 @@ namespace sophiar {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- auto stream_id = stream_id_buf->as_string_view();
|
|
|
+ auto stream_id = std::string_view{stream_id_buf->data(), stream_id_length};
|
|
|
assert(stream_reply_callback_pool.contains(stream_id));
|
|
|
auto &callback = stream_reply_callback_pool.query(stream_id);
|
|
|
callback(std::move(reply_buf));
|
|
|
+ co_return;
|
|
|
}
|
|
|
|
|
|
// header_magic is also part of the reply
|
|
|
awaitable<dynamic_memory::pointer> read_ascii_reply(uint16_t header_magic) {
|
|
|
static constexpr char cr_ascii = '\r';
|
|
|
|
|
|
+ using streambuf_type = basic_streambuf<DYNAMIC_ALLOCATOR(char) >;
|
|
|
+ streambuf_type ascii_buf;
|
|
|
+
|
|
|
// read the rest ascii reply
|
|
|
if (address_type == ndi_address_type::serial) {
|
|
|
co_await async_read_until(*ndi_com_socket, ascii_buf, cr_ascii, use_awaitable);
|
|
|
@@ -392,6 +400,7 @@ namespace sophiar {
|
|
|
return async_write(*ndi_tcp_socket, buffer(cmd.data(), cmd.size()), use_awaitable);
|
|
|
}
|
|
|
assert(false);
|
|
|
+ __builtin_unreachable();
|
|
|
}
|
|
|
|
|
|
template<typename T, typename OutputIterator>
|
|
|
@@ -463,8 +472,20 @@ namespace sophiar {
|
|
|
ndi_com_socket->set_option(serial_port::stop_bits(serial_port::stop_bits::one));
|
|
|
ndi_com_socket->set_option(serial_port::flow_control(serial_port::flow_control::none));
|
|
|
|
|
|
+#ifdef BOOST_OS_WINDOWS_AVAILABLE // boost asio cannot send serial break under windows
|
|
|
+
|
|
|
+ using namespace std::chrono_literals;
|
|
|
+ auto handle = ndi_com_socket->native_handle();
|
|
|
+ ENSURE_CO(SetCommBreak(handle));
|
|
|
+ co_await coro_sleep(250ms); // hold serial break for 250ms
|
|
|
+ ENSURE_CO(ClearCommBreak(handle));
|
|
|
+
|
|
|
+#else // BOOST_OS_WINDOWS_AVAILABLE
|
|
|
+
|
|
|
ndi_com_socket->send_break(); // cause the system to reset
|
|
|
|
|
|
+#endif // BOOST_OS_WINDOWS_AVAILABLE
|
|
|
+
|
|
|
// wait the RESET to be sent from ndi
|
|
|
auto reset_reply = co_await command_reply_queue->async_receive(use_awaitable);
|
|
|
auto reset_reply_str = reset_reply->as_string_view();
|
|
|
@@ -493,6 +514,7 @@ namespace sophiar {
|
|
|
assert(false);
|
|
|
co_return 0;
|
|
|
}
|
|
|
+ SPDLOG_INFO("NDI api version is {}.", reply->as_string_view());
|
|
|
auto major_version = lexical_cast<int>(reply->data() + 2, 3); // Like G.001.004A0C0
|
|
|
co_return major_version;
|
|
|
}
|
|
|
@@ -737,6 +759,8 @@ namespace sophiar {
|
|
|
|
|
|
ndi_api_major_version = co_await get_api_major_version();
|
|
|
|
|
|
+ // TODO increase Param.Tracking.IlluminatorRate to 60 for Polaris Spectra device
|
|
|
+
|
|
|
CO_ENSURE(initialize_ndi())
|
|
|
CO_ENSURE(config_tools())
|
|
|
|
|
|
@@ -751,7 +775,8 @@ namespace sophiar {
|
|
|
reply_callback_type callback = [this](dynamic_memory::pointer &&mem) {
|
|
|
handle_bx_reply(std::move(mem));
|
|
|
};
|
|
|
- stream_reply_callback_pool.insert(stream_cmd, std::move(callback));
|
|
|
+ auto stream_cmd_id = stream_cmd.substr(0, stream_cmd.size() - 1); // strip the '\r'
|
|
|
+ stream_reply_callback_pool.insert(stream_cmd_id, std::move(callback));
|
|
|
CO_ENSURE(start_stream(stream_cmd))
|
|
|
} else { // use interval streaming
|
|
|
assert(tracking_tools_worker == nullptr);
|
|
|
@@ -815,7 +840,7 @@ namespace sophiar {
|
|
|
try {
|
|
|
CO_ENSURE(pimpl->on_init_impl())
|
|
|
} catch (std::exception &e) {
|
|
|
- // TODO show log
|
|
|
+ SPDLOG_ERROR("Failed to initialize ndi: {}", e.what());
|
|
|
co_return false;
|
|
|
}
|
|
|
CO_ENSURE(tristate_obj::on_init(config))
|