Go to the documentation of this file.
38 #ifndef WIN32_LEAN_AND_MEAN
39 #define WIN32_LEAN_AND_MEAN 1
46 #include <arpa/inet.h>
112 constexpr uint16_t MAX_MTU = 9000;
117 constexpr std::array<uint16_t, 10> MTUS_TO_TEST{9000, 8167, 7333, 6500, 5667, 4833, 4000, 3167, 2333, 1500};
126 m_message_assembler(m_buffer_pool)
128 if (config.connect_on_initialization && connect(config) !=
Status::OK)
143 using namespace std::chrono_literals;
163 CRL_DEBUG(
"Start streams ack invalid: %" PRIi32
"\n", ack->status);
167 for (
const auto &source : sources)
182 using namespace std::chrono_literals;
202 CRL_DEBUG(
"Start streams ack invalid: %" PRIi32
"\n", ack->status);
206 for (
const auto &source : sources)
237 CRL_DEBUG(
"Channel is already connected to the MultiSense\n");
241 std::lock_guard<std::mutex> lock(
m_mutex);
248 int result = WSAStartup (MAKEWORD (0x02, 0x02), &wsaData);
258 auto [sensor_socket, server_socket_port] =
bind(config.
interface,
false);
281 [
this](
const std::vector<uint8_t>& data)
285 CRL_DEBUG(
"Processing packet of %" PRIu64
" bytes failed\n",
286 static_cast<uint64_t>(data.size()));
315 m_info = std::move(info.value());
353 std::lock_guard<std::mutex> lock(
m_mutex);
388 std::lock_guard<std::mutex> lock(
m_mutex);
392 CRL_DEBUG(
"Warning: MultiSense is not connected");
407 std::vector<Status> responses{};
412 constexpr
size_t setting_retries = 3;
419 convert<wire::CamSetResolution>(config),
427 responses.push_back(
get_status(res_ack->status));
435 convert<wire::CamControl>(config),
443 responses.push_back(
get_status(cam_ack->status));
463 responses.push_back(
get_status(aux_ack->status));
486 responses.push_back(
get_status(imu_ack->status));
507 responses.push_back(
get_status(lighting_ack->status));
525 responses.push_back(
get_status(ptp_ack->status));
543 responses.push_back(
get_status(packet_ack->status));
547 const auto errors = std::any_of(std::begin(responses), std::end(responses),
566 ptp_enabled); new_config)
568 std::lock_guard<std::mutex> lock(
m_mutex);
576 if (config == new_config.value())
589 std::lock_guard<std::mutex> lock(
m_mutex);
593 CRL_DEBUG(
"Warning: MultiSense is not connected");
624 std::lock_guard<std::mutex> lock(
m_mutex);
637 std::lock_guard<std::mutex> lock(
m_mutex);
641 CRL_DEBUG(
"Warning: MultiSense is not connected");
667 std::lock_guard<std::mutex> lock(
m_mutex);
703 std::optional<wire::PtpStatusResponse> ptp_status = std::nullopt;
714 CRL_DEBUG(
"Unable to query ptp status\n");
724 status->host_start_transmit_time,
725 status->host_transmit_receive_roundtrip / 2};
729 message_stats.dropped_messages,
730 message_stats.invalid_packets};
733 (ptp_status ? std::make_optional(
convert(ptp_status.value())) : std::nullopt),
734 convert<MultiSenseStatus::CameraStatus>(status->message),
735 convert<MultiSenseStatus::TemperatureStatus>(status->message),
736 convert<MultiSenseStatus::PowerStatus>(status->message),
737 std::move(client_stats),
738 std::move(time_status)};
742 const std::optional<std::string> &broadcast_interface)
747 config.
gateway ==
"0.0.0.0" || config.
gateway ==
"255.255.255.255" ||
748 config.
netmask ==
"0.0.0.0" || config.
netmask ==
"255.255.255.255")
753 if (broadcast_interface)
759 NetworkSocket broadcast_socket{std::move(broadcast_address), std::move(socket), std::move(socket_port)};
797 CRL_DEBUG(
"Testing MTU of %" PRIu16
" bytes failed."
798 " Please verify you can ping the MultiSense with a MTU of %" PRIu16
" bytes at %s.\n",
812 CRL_DEBUG(
"Unable to set MTU to %" PRIu16
" bytes: %i\n", mtu, ack->status);
831 for (
const auto &value : MTUS_TO_TEST)
835 CRL_DEBUG(
"Auto-setting MTU to %" PRIu16
" bytes \n", value);
839 CRL_DEBUG(
"Unable to find a MTU that works with the MultiSense. "
859 const auto aux_config = has_aux_camera ? wait_for_data<wire::AuxCamConfig>(
m_message_assembler,
890 return convert(camera_config.value(),
900 CRL_DEBUG(
"Unable to query the camera's configuration\n");
916 return std::make_optional(
convert(new_cal.value()));
930 CRL_DEBUG(
"Unable to query the device info\n");
942 CRL_DEBUG(
"Unable to query the version info\n");
955 CRL_DEBUG(
"Unable to query the device modes\n");
981 CRL_DEBUG(
"Unable to query the network info\n");
988 imu_info ? std::make_optional(
convert(imu_info.value())) : std::nullopt,
989 convert(network_info.value())};
1003 return std::make_optional(
convert(device_info.value()));
1006 return std::nullopt;
1013 const auto wire_meta = deserialize<wire::ImageMeta>(*data);
1021 using namespace std::chrono;
1023 const auto wire_image = deserialize<wire::Image>(*data);
1025 const auto meta =
m_meta_cache.find(wire_image.frameId);
1028 CRL_DEBUG(
"Missing corresponding meta for frame_id %" PRIu64
"\n", wire_image.frameId);
1032 const nanoseconds capture_time{seconds{meta->second.timeSeconds} +
1033 microseconds{meta->second.timeMicroSeconds}};
1035 const TimeT capture_time_point{capture_time};
1037 const TimeT ptp_capture_time_point{nanoseconds{meta->second.ptpNanoSeconds}};
1040 switch (wire_image.bitsPerPixel)
1044 default: {
CRL_DEBUG(
"Unknown pixel format %" PRIu32
"\n", wire_image.bitsPerPixel);}
1047 const auto source =
convert_sources(
static_cast<uint64_t
>(wire_image.sourceExtended) << 32 | wire_image.source);
1048 if (source.size() != 1)
1060 std::lock_guard<std::mutex> lock(
m_mutex);
1065 const auto cal_x_scale =
static_cast<double>(wire_image.width) /
static_cast<double>(info.
imager_width);
1066 const auto cal_y_scale =
static_cast<double>(wire_image.height) /
static_cast<double>(info.
imager_height);
1069 static_cast<const uint8_t*
>(wire_image.dataP) - data->data(),
1070 ((wire_image.bitsPerPixel / 8) * wire_image.width * wire_image.height),
1075 ptp_capture_time_point,
1083 ptp_capture_time_point);
1089 using namespace std::chrono;
1091 const auto wire_image = deserialize<wire::Disparity>(*data);
1093 const auto meta =
m_meta_cache.find(wire_image.frameId);
1096 CRL_DEBUG(
"Missing corresponding meta for frame_id %" PRIu64
"\n", wire_image.frameId);
1100 const nanoseconds capture_time{seconds{meta->second.timeSeconds} +
1101 microseconds{meta->second.timeMicroSeconds}};
1103 const TimeT capture_time_point{capture_time};
1105 const TimeT ptp_capture_time_point{nanoseconds{meta->second.ptpNanoSeconds}};
1108 switch (wire::Disparity::API_BITS_PER_PIXEL)
1112 default: {
CRL_DEBUG(
"Unknown pixel format %" PRIu8
"\n", wire::Disparity::API_BITS_PER_PIXEL);}
1117 const auto disparity_length =
1118 static_cast<size_t>(((
static_cast<double>(wire::Disparity::API_BITS_PER_PIXEL) / 8.0) *
1120 wire_image.height));
1128 std::lock_guard<std::mutex> lock(
m_mutex);
1133 const auto cal_x_scale =
static_cast<double>(wire_image.width) /
static_cast<double>(info.
imager_width);
1134 const auto cal_y_scale =
static_cast<double>(wire_image.height) /
static_cast<double>(info.
imager_height);
1137 static_cast<const uint8_t*
>(wire_image.dataP) - data->data(),
1143 ptp_capture_time_point,
1151 ptp_capture_time_point);
1165 const auto wire_imu = deserialize<wire::ImuData>(*data);
1167 for (
const auto &wire_sample : wire_imu.samples)
1169 const TimeT camera_time{std::chrono::nanoseconds{wire_sample.timeNanoSeconds}};
1170 const TimeT ptp_time{std::chrono::nanoseconds{wire_sample.ptpNanoSeconds}};
1198 ImuSample sample{std::nullopt, std::nullopt, std::nullopt, camera_time, ptp_time};
1208 const TimeT &capture_time,
1209 const TimeT &ptp_capture_time)
1216 const auto source = image.
source;
1218 std::map<DataSource, Image>{std::make_pair(source, std::move(image))},
1238 [&frame](
const auto &e){
return is_image_source(e) ? frame.has_image(e) :
true;}))
ImuFrame m_current_imu_frame
A cache of IMU samples which will be internally filled until it reaches the sample threshold for disp...
constexpr bool has_aux_camera() const
Determine if the MultiSense has a Aux color camera.
std::atomic_bool m_connected
Atomic flag to determine if we are connected to an active camera.
std::optional< MultiSenseConfig > query_configuration(bool has_aux_camera, bool has_imu, bool ptp_enabled)
Query the full configuration.
The network configuration for the MultiSense.
Complete configuration object for configuring the MultiSense. Can be updated during camera operation.
static CRL_CONSTEXPR Status Status_Ok
std::mutex m_image_callback_mutex
Internal mutex used to handle user callbacks for image data.
void disparity_callback(std::shared_ptr< const std::vector< uint8_t >> data)
Disparity callback used to internally receive images sent from the MultiSense.
CameraCalibration scale_calibration(const CameraCalibration &input, double x_scale, double y_scale)
Scale a calibration used to update a full-res calibration based on the current operating resolution.
std::optional< CameraCalibration > aux
Calibration information for the aux camera (optional 3rd center camera)
#define CRL_DEBUG(fmt,...)
std::unique_ptr< sockaddr_in > sensor_address
FrameNotifier< ImuFrame > m_imu_frame_notifier
Notifier used to service the get_next_imu_frame member function.
uint32_t imager_width
The native width of the primary imager.
StereoCalibration get_calibration() final override
Get the current stereo calibration. The output calibration will correspond to the full-resolution ope...
uint32_t imager_height
The native height of the primary imager.
ImuSampleScalars m_imu_scalars
Scalars to convert imu samples from wire units to standard LibMultiSense units.
size_t large_buffer_size
The size of each small buffer in bytes.
std::atomic_uint32_t m_max_batched_imu_messages
The max number of IMU messages which can be batched over the wire.
A frame containing multiple images (indexed by DataSource).
Config m_config
Channel config.
MultiSenseInfo get_info() final override
Get the device info associated with the camera.
std::unique_ptr< UdpReceiver > m_udp_receiver
Helper object to receive UDP traffic. Internally manages a receive thread.
std::unique_ptr< sockaddr_in > get_broadcast_sockaddr(uint16_t command_port)
Create a socketaddr_in object to boradcast to a given port.
Status set_mtu(uint16_t mtu)
Try and set the MTU.
std::optional< int16_t > mtu
The MTU to use for sending and receiving data from the camera. Setting the MTU to nullopt will trigge...
void image_callback(std::shared_ptr< const std::vector< uint8_t >> data)
Image callback used to internally receive images sent from the MultiSense.
bool process_packet(const std::vector< uint8_t > &raw_data)
std::optional< std::string > interface
An optional name of network interface to bind to. (i.e. eth0)
std::chrono::time_point< std::chrono::system_clock, std::chrono::nanoseconds > TimeT
Status start_streams(const std::vector< DataSource > &sources) final override
Start a collection of image streams. Repeated calls to this function will not implicitly stop the pre...
void add_image_frame_callback(std::function< void(const ImageFrame &)> callback) final override
Add a image frame callback to get serviced inline with the receipt of a new frame....
Status set_network_config(const MultiSenseInfo::NetworkInfo &config, const std::optional< std::string > &broadcast_interface) final override
Update the network configuration of the MultiSense. This will require a hardware reboot of the MultiS...
std::vector< ImuSample > samples
A batched collection of IMU samples.
ImuSampleScalars get_imu_scalars(const crl::multisense::details::wire::ImuInfo &info)
Get IMU scalars from the cameras's reported IMU info.
std::optional< MultiSenseInfo::DeviceInfo > query_device_info()
Query the device_info from the camera.
std::optional< MultiSenseStatus > get_system_status() final override
Query the current MultiSense status.
std::optional< TimeConfig > time_config
Config for the MultiSense time-sync options.
Status stop_streams(const std::vector< DataSource > &sources) final override
Stop a collection of streams.
void disconnect() final override
Disconnect from the camera.
PixelFormat
Pixel formats.
void enable(SourceType mask)
uint16_t command_port
The UDP port on the MultiSense which accepts user commands. All production firmware builds use port 9...
ImuSample add_wire_sample(ImuSample sample, const crl::multisense::details::wire::ImuSample &wire, const ImuSampleScalars &scalars)
Add a wire sample to a ImuSample.
std::string gateway
The gateway of the camera (i.e. X.X.X.X)
A collection of IMU samples from the camera.
void remove_callback(const crl::multisense::details::wire::IdType &message_id)
Remove a callback for a specific message type.
std::optional< ImageFrame > get_next_image_frame() final override
A blocking call that waits for one image frame from the camera.
DataSource source
The camera data source which this image corresponds to.
#define CRL_EXCEPTION(fmt,...)
std::map< int64_t, crl::multisense::details::wire::ImageMeta > m_meta_cache
A cache of image metadata associated with a specific frame id.
std::tuple< socket_t, uint16_t > bind(const std::optional< std::string > &interface_name, bool broadcast)
Create a UDP socket to communicate with the MultiSense. Optionally bind to a specific interface.
std::vector< uint8_t > serialize(const T &message, uint16_t sequence_id, size_t mtu)
Serialize a MultiSense Wire message for transmission. This adds the wire header to the message for tr...
void register_callback(const crl::multisense::details::wire::IdType &message_id, std::function< void(std::shared_ptr< const std::vector< uint8_t >>)> callback)
Register a callback to receive valid messages of a given id. Note currently only one callback can be ...
std::function< void(const ImuFrame &)> m_user_imu_frame_callback
The currently active imu frame user callback.
std::atomic_uint16_t m_current_mtu
The current MTU the camera is operating with.
void imu_callback(std::shared_ptr< const std::vector< uint8_t >> data)
Disparity callback used to internally receive images sent from the MultiSense.
std::optional< LightingConfig > lighting_config
The lighting configuration for the camera. If invalid, the camera does not support lighting configura...
MultiSenseInfo m_info
The current cached device info stored here for convenience.
A single IMU sample from the camera.
std::set< DataSource > m_active_streams
The current set of active data streams the MultiSense is transmitting.
int64_t publish_data(const NetworkSocket &socket, const std::vector< uint8_t > &data)
Convenience function used to user specified data out on the host's UDP socket.
Status get_status(const crl::multisense::details::wire::Ack::AckStatus &status)
std::optional< MultiSenseInfo > query_info()
Query the MultiSense Info.
Convenience network socket object which contains the data corresponding to our connection.
std::map< int64_t, ImageFrame > m_frame_buffer
A cache of image frames associated with a specific frame id.
std::vector< DataSource > convert_sources(const crl::multisense::details::wire::SourceType &source)
Convert wire sources to a vector of DataSources.
std::string netmask
The netmask of the camera (i.e. X.X.X.X)
MessageAssembler m_message_assembler
Helper object to assemble raw UDP packets into complete MultiSense wire messages.
StereoCalibration m_calibration
The current cached calibration stored here for convenience.
std::optional< crl::multisense::details::wire::Ack > wait_for_ack(MessageAssembler &assembler, const NetworkSocket &socket, const QueryMessage &query, uint16_t sequence_id, uint16_t mtu, const std::optional< std::chrono::duration< Rep, Period >> &wait_time, size_t attempts=1)
Helper to wait for ack from the camera from a given query command. Once a query command is sent to th...
std::optional< ImuInfo > imu
Supported operating modes for the IMU sensors (accelerometer, gyroscope, magnetometer)....
The Device information associated with the MultiSense. The DeviceInfo is used to determine what featu...
CameraCalibration convert(const crl::multisense::details::wire::CameraCalData &cal)
Convert a wire calibration to our API calibration object.
bool system_ok(const crl::multisense::details::wire::StatusResponse &status)
Summarize the status info and determine fit the MultiSense system is operating properly.
std::mutex m_mutex
Internal mutex used to handle updates from users.
Object to handle the management and delivery of buffers to used to store incoming data without needin...
Status set_calibration(const StereoCalibration &calibration) final override
Set the current stereo calibration. The calibration is expected to be or the full-resolution operatin...
std::string ip_address
the IP address of the MultiSense camera to connect to
CameraCalibration select_calibration(const StereoCalibration &input, const DataSource &source)
Get the correct calibration corresponding to the input source.
void handle_and_dispatch(Image image, int64_t frame_id, const StereoCalibration &calibration, const TimeT &capture_time, const TimeT &ptp_capture_time)
Handle internal process, and potentially dispatch a image.
MultiSenseConfig get_config() final override
Get the current MultiSense configuration.
uint16_t server_socket_port
std::string ip_address
The ip address of the camera (i.e. X.X.X.X)
MultiSenseConfig m_multisense_config
The current cached MultiSense configuration stored for convenience.
std::optional< ImuFrame > get_next_imu_frame() final override
A blocking call that waits for one imu frame from the camera.
size_t num_small_buffers
The number of small buffers to preallocate for receiving small MultiSense messages.
ReceiveBufferConfig receive_buffer_configuration
Config for the number and size of internal buffers used to receive data without recurring memory allo...
bool is_image_source(const DataSource &source)
Determine if a datasource is a image source.
Static status info for the MultiSense. Will not change during camera operation.
std::function< void(const ImageFrame &)> m_user_image_frame_callback
The currently active image frame user callback.
Status connect(const Config &config) final override
Initialize the connection to the camera.
Status set_config(const MultiSenseConfig &config) final override
Get set the current MultiSense configuration.
Represents a single image plus metadata.
std::optional< StereoCalibration > query_calibration()
Query the calibration from the camera.
NetworkSocket m_socket
Active network socket for receiving and transmitting data.
DeviceInfo device
Device info.
std::optional< NetworkTransmissionConfig > network_config
Config to control network transmission settings.
std::unique_ptr< sockaddr_in > get_sockaddr(const std::string &ip_address, uint16_t command_port)
Create a socketaddr_in object for a given IP address and port.
void disable(SourceType mask)
LegacyChannel(const Config &config)
std::vector< DataSource > expand_source(const DataSource &source)
Expand sources since some sources may represent multiple sources on the wire.
Status set_device_info(const MultiSenseInfo::DeviceInfo &device_info, const std::string &key) final override
Set the camera's device info. This setting is protected via a key since invalid values in the device ...
MessageStatistics get_message_statistics() const
size_t num_large_buffers
The number of large buffers to preallocate for receiving MultiSense sensor data.
std::optional< ImuConfig > imu_config
The imu configuration to use for the camera. Will be invalid if sensor does not contain an IMU.
std::atomic_uint16_t m_transmit_id
Monotonically increasing internal id used to uniquely identify requests sent to the camera.
std::optional< std::chrono::milliseconds > receive_timeout
Timeout to use when waiting for MultiSense command responses. Setting the timeout to nullopt will res...
size_t received_messages
The total number of valid messages received from the client.
void add_imu_frame_callback(std::function< void(const ImuFrame &)> callback) final override
Add a imu frame callback to get serviced inline with the receipt of a new frame. Only a single imu fr...
size_t small_buffer_size
The size of each small buffer in bytes.
int width
Width of the image in pixels.
std::string to_string(const Status &status)
Convert a status object to a user readable string.
void image_meta_callback(std::shared_ptr< const std::vector< uint8_t >> data)
Image meta callback used to internally receive images sent from the MultiSense.
std::mutex m_imu_callback_mutex
Internal mutex used to handle user callbacks imu data.
FrameNotifier< ImageFrame > m_image_frame_notifier
Notifier used to service the get_next_image_frame member function.
std::optional< AuxConfig > aux_config
The image configuration to use for the aux camera if present.
Consolidated status information which can be queried on demand from the MultiSense....