legacy/utilities.cc
Go to the documentation of this file.
1 
37 #include <algorithm>
38 
41 
42 namespace multisense{
43 namespace legacy{
44 
45 bool is_image_source(const DataSource &source)
46 {
47  switch (source)
48  {
66  return true;
67  default:
68  return false;
69  }
70 }
71 
73 {
74  using namespace crl::multisense::details::wire;
75 
76  switch(status)
77  {
78  case Ack::Status_Ok: {return Status::OK;}
81  case Ack::Status_Failed: {return Status::FAILED;}
83  case Ack::Status_Unknown: {return Status::UNKNOWN;}
85  default: {return Status::UNKNOWN;}
86  }
87 }
88 
90 {
91  return MultiSenseInfo::Version{static_cast<uint32_t>(version >> 8), static_cast<uint32_t>(version & 0xFF), 0};
92 }
93 
95 {
96  auto disparities = MultiSenseConfig::MaxDisparities::D256;
97  switch (disparity)
98  {
99  case 64: {disparities = MultiSenseConfig::MaxDisparities::D64; break;}
100  case 128: {disparities = MultiSenseConfig::MaxDisparities::D128; break;}
101  case 256: {disparities = MultiSenseConfig::MaxDisparities::D256; break;}
102  default: {CRL_EXCEPTION("Unsupported disparity value %d", disparity);}
103  }
104 
105  return disparities;
106 }
107 
108 std::vector<DataSource> convert_sources(const crl::multisense::details::wire::SourceType &source)
109 {
110  using namespace crl::multisense::details;
111 
112  std::vector<DataSource> sources;
113  if (source & wire::SOURCE_LUMA_LEFT) {sources.push_back(DataSource::LEFT_MONO_RAW);}
114  if (source & wire::SOURCE_LUMA_RIGHT) {sources.push_back(DataSource::RIGHT_MONO_RAW);}
115  if (source & wire::SOURCE_COMPRESSED_LEFT) {sources.push_back(DataSource::LEFT_MONO_COMPRESSED);}
116  if (source & wire::SOURCE_COMPRESSED_RIGHT) {sources.push_back(DataSource::RIGHT_MONO_COMPRESSED);}
117  if (source & wire::SOURCE_LUMA_RECT_LEFT) {sources.push_back(DataSource::LEFT_RECTIFIED_RAW);}
118  if (source & wire::SOURCE_LUMA_RECT_RIGHT) {sources.push_back(DataSource::RIGHT_RECTIFIED_RAW);}
121  if (source & wire::SOURCE_DISPARITY) {sources.push_back(DataSource::LEFT_DISPARITY_RAW);}
122  if (source & wire::SOURCE_COMPRESSED_AUX) {sources.push_back(DataSource::AUX_COMPRESSED);}
124  if (source & wire::SOURCE_LUMA_AUX) {sources.push_back(DataSource::AUX_LUMA_RAW);}
125  if (source & wire::SOURCE_LUMA_RECT_AUX) {sources.push_back(DataSource::AUX_LUMA_RECTIFIED_RAW);}
126  if (source & wire::SOURCE_CHROMA_AUX) {sources.push_back(DataSource::AUX_CHROMA_RAW);}
127  if (source & wire::SOURCE_CHROMA_RECT_AUX) {sources.push_back(DataSource::AUX_CHROMA_RECTIFIED_RAW);}
128  if (source & wire::SOURCE_DISPARITY_COST) {sources.push_back(DataSource::COST_RAW);}
129  if (source & wire::SOURCE_IMU) {sources.push_back(DataSource::IMU);}
130 
131  return sources;
132 }
133 
134 
135 crl::multisense::details::wire::SourceType convert_sources(const std::vector<DataSource> &sources)
136 {
137  using namespace crl::multisense::details;
138 
139  wire::SourceType mask = 0;
140  for (const auto &source : sources)
141  {
142  switch(source)
143  {
144  case DataSource::LEFT_MONO_RAW: {mask |= wire::SOURCE_LUMA_LEFT; break;}
153  case DataSource::LEFT_DISPARITY_COMPRESSED: { CRL_DEBUG("Compressed disparity not supported"); break;}
156  case DataSource::AUX_LUMA_RAW: {mask |= wire::SOURCE_LUMA_AUX; break;}
162  case DataSource::COST_RAW: {mask |= wire::SOURCE_DISPARITY_COST; break;}
163  case DataSource::IMU: {mask |= wire::SOURCE_IMU; break;}
164  case DataSource::ALL: {mask |= all_sources; break;}
165  default: {CRL_DEBUG("Unsupported source %d", static_cast<int32_t>(source));}
166  }
167  }
168 
169  return mask;
170 }
171 
172 std::vector<DataSource> expand_source(const DataSource &source)
173 {
174  switch(source)
175  {
176  case DataSource::AUX_RAW:
177  {
178  return std::vector<DataSource>{DataSource::AUX_LUMA_RAW, DataSource::AUX_CHROMA_RAW};
179  }
181  {
183  }
184  default: {return std::vector<DataSource>{source};}
185  }
186 }
187 
190  const ImuSampleScalars &scalars)
191 {
192  using namespace crl::multisense::details;
193 
194 
195  switch(wire.type)
196  {
197  case wire::ImuSample::TYPE_ACCEL:
198  {
199  sample.accelerometer = ImuSample::Measurement{static_cast<float>(wire.x * scalars.accelerometer_scale),
200  static_cast<float>(wire.y * scalars.accelerometer_scale),
201  static_cast<float>(wire.z * scalars.accelerometer_scale)};
202  break;
203  }
204  case wire::ImuSample::TYPE_GYRO:
205  {
206  sample.gyroscope = ImuSample::Measurement{static_cast<float>(wire.x * scalars.gyroscope_scale),
207  static_cast<float>(wire.y * scalars.gyroscope_scale),
208  static_cast<float>(wire.z * scalars.gyroscope_scale)};
209  break;
210  }
211  case wire::ImuSample::TYPE_MAG:
212  {
213  sample.magnetometer = ImuSample::Measurement{static_cast<float>(wire.x * scalars.magnetometer_scale),
214  static_cast<float>(wire.y * scalars.magnetometer_scale),
215  static_cast<float>(wire.z * scalars.magnetometer_scale)};
216  break;
217  }
218  default:
219  {
220  CRL_EXCEPTION("Unknown IMU sample type");
221  }
222  }
223 
224  return sample;
225 }
226 
227 uint32_t get_rate_index(const std::vector<ImuRate> &rates, const ImuRate &rate)
228 {
229  return static_cast<uint32_t>(std::distance(std::begin(rates),
230  std::find_if(std::begin(rates), std::end(rates),
231  [&rate](const auto &e)
232  {
233  return (std::abs(e.sample_rate - rate.sample_rate) < 1e-6 &&
234  std::abs(e.bandwith_cutoff - rate.bandwith_cutoff) < 1e-6);
235  })));
236 }
237 
238 uint32_t get_range_index(const std::vector<ImuRange> &ranges, const ImuRange &range)
239 {
240  return static_cast<uint32_t>(std::distance(std::begin(ranges),
241  std::find_if(std::begin(ranges), std::end(ranges),
242  [&range](const auto &e)
243  {
244  return (std::abs(e.range - range.range) < 1e-6 &&
245  std::abs(e.resolution - range.resolution) < 1e-6);
246  })));
247 }
248 
249 double get_acceleration_scale(const std::string &units)
250 {
251  std::string lower_units = units;
252  std::transform(lower_units.begin(), lower_units.end(), lower_units.begin(),
253  [](unsigned char c){ return static_cast<char>(std::tolower(c));});
254 
255 
256  if (lower_units == "g" || lower_units == "gs")
257  {
258  return 1.0;
259  }
260  else if (lower_units == "millig" || lower_units == "milli-g")
261  {
262  return 1.0/1000.0;
263  }
264  else
265  {
266  CRL_DEBUG("Unknown acceleration units: %s\n", units.c_str());
267  }
268 
269  return 1.0;
270 }
271 
272 double get_gyroscope_scale(const std::string &units)
273 {
274  std::string lower_units = units;
275  std::transform(lower_units.begin(), lower_units.end(), lower_units.begin(),
276  [](unsigned char c){ return static_cast<char>(std::tolower(c));});
277 
278  if (lower_units == "dps" || lower_units == "degrees-per-second")
279  {
280  return 1.0;
281  }
282  else if (lower_units == "rps" || units == "radians-per-second")
283  {
284  return 1.0/1000.0;
285  }
286  else
287  {
288  CRL_DEBUG("Unknown gyroscope units: %s\n", units.c_str());
289  }
290 
291  return 1.0;
292 }
293 
294 double get_magnetometer_scale(const std::string &units)
295 {
296  std::string lower_units = units;
297  std::transform(lower_units.begin(), lower_units.end(), lower_units.begin(),
298  [](unsigned char c){ return static_cast<char>(std::tolower(c));});
299 
300  if (lower_units == "gauss")
301  {
302  return 1000.0;
303  }
304  else if (lower_units == "milligauss" || units == "milli-gauss")
305  {
306  return 1.0;
307  }
308  else
309  {
310  CRL_DEBUG("Unknown magnetometer units: %s\n", units.c_str());
311  }
312 
313  return 1.0;
314 }
315 
317 {
318  ImuSampleScalars output;
319 
320  for (const auto &mode : info.details)
321  {
322  if (mode.name == "accelerometer")
323  {
324  output.accelerometer_scale = get_acceleration_scale(mode.units);
325  continue;
326  }
327  else if (mode.name == "gyroscope")
328  {
329  output.gyroscope_scale = get_gyroscope_scale(mode.units);
330  continue;
331  }
332  else if (mode.name == "magnetometer")
333  {
334  output.magnetometer_scale = get_magnetometer_scale(mode.units);
335  continue;
336  }
337  else
338  {
339  CRL_EXCEPTION("Unknown IMU name: %s\n", mode.name.c_str());
340  }
341  }
342 
343  return output;
344 }
345 
346 }
347 
348 }
multisense::ImuSample::Measurement
A generic measurement for a 3-axis IMU.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:370
multisense::DataSource::RIGHT_RECTIFIED_COMPRESSED
@ RIGHT_RECTIFIED_COMPRESSED
crl::multisense::Status_Failed
static CRL_CONSTEXPR Status Status_Failed
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:102
multisense::DataSource::RIGHT_MONO_COMPRESSED
@ RIGHT_MONO_COMPRESSED
multisense::legacy::ImuSampleScalars::gyroscope_scale
double gyroscope_scale
Scale for the gyroscope_scale to convert wire samples into degrees/sec.
Definition: utilities.hh:91
multisense::Status::UNKNOWN
@ UNKNOWN
crl::multisense::Status_Ok
static CRL_CONSTEXPR Status Status_Ok
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:99
crl::multisense::details
Definition: Legacy/details/channel.cc:63
crl::multisense::Status_Error
static CRL_CONSTEXPR Status Status_Error
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:101
multisense::DataSource::AUX_RECTIFIED_RAW
@ AUX_RECTIFIED_RAW
crl::multisense::details::wire::ImuSample::type
uint16_t type
Definition: ImuDataMessage.hh:56
CRL_DEBUG
#define CRL_DEBUG(fmt,...)
Definition: Exception.hh:71
multisense::legacy::get_disparities
MultiSenseConfig::MaxDisparities get_disparities(size_t disparity)
Convert a disparity integer to a fixed disparity setting.
Definition: legacy/utilities.cc:94
multisense::Status
Status
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:67
crl::multisense::details::wire::SOURCE_CHROMA_AUX
static CRL_CONSTEXPR SourceType SOURCE_CHROMA_AUX
Definition: Protocol.hh:278
MultiSenseUtilities.hh
crl::multisense::details::wire::SOURCE_LUMA_AUX
static CRL_CONSTEXPR SourceType SOURCE_LUMA_AUX
Definition: Protocol.hh:276
multisense::DataSource::AUX_COMPRESSED
@ AUX_COMPRESSED
multisense::ImuSample::gyroscope
std::optional< Measurement > gyroscope
The rotational velocity in degrees-per-second. Depending on the IMU configuration of the sensor,...
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:397
multisense::ImuRate::bandwith_cutoff
float bandwith_cutoff
The bandwith cutoff for a given IMU mode in Hz.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:439
crl::multisense::details::wire::Ack::AckStatus
int32_t AckStatus
Definition: AckMessage.hh:52
utilities.hh
multisense::MultiSenseConfig::MaxDisparities
MaxDisparities
Predefined disparity pixel search windows. Larger values allows the camera to see objects closer to t...
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:776
multisense::ImuRate::sample_rate
float sample_rate
The sample rate for the sensor in Hz.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:434
multisense::DataSource::LEFT_RECTIFIED_RAW
@ LEFT_RECTIFIED_RAW
multisense::DataSource::AUX_LUMA_RAW
@ AUX_LUMA_RAW
crl::multisense::details::wire
Definition: constants.cc:115
multisense::DataSource::LEFT_DISPARITY_COMPRESSED
@ LEFT_DISPARITY_COMPRESSED
multisense::DataSource::AUX_LUMA_RECTIFIED_RAW
@ AUX_LUMA_RECTIFIED_RAW
multisense::DataSource::RIGHT_MONO_RAW
@ RIGHT_MONO_RAW
multisense::legacy::get_imu_scalars
ImuSampleScalars get_imu_scalars(const crl::multisense::details::wire::ImuInfo &info)
Get IMU scalars from the cameras's reported IMU info.
Definition: legacy/utilities.cc:316
multisense::DataSource::LEFT_MONO_RAW
@ LEFT_MONO_RAW
crl::multisense::details::wire::SOURCE_COMPRESSED_RECTIFIED_AUX
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_RECTIFIED_AUX
Definition: Protocol.hh:285
multisense::ImuRange
The range for each sensor along with the corresponding sampling resolution.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:453
multisense::legacy::get_rate_index
uint32_t get_rate_index(const std::vector< ImuRate > &rates, const ImuRate &rate)
Get the index of the rate in a vector of rates.
Definition: legacy/utilities.cc:227
crl::multisense::details::wire::SOURCE_COMPRESSED_RIGHT
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_RIGHT
Definition: Protocol.hh:281
multisense::legacy::add_wire_sample
ImuSample add_wire_sample(ImuSample sample, const crl::multisense::details::wire::ImuSample &wire, const ImuSampleScalars &scalars)
Add a wire sample to a ImuSample.
Definition: legacy/utilities.cc:188
multisense::legacy::all_sources
constexpr crl::multisense::details::wire::SourceType all_sources
All the supported wire source types created for convenience.
Definition: utilities.hh:57
multisense::ImuSample::accelerometer
std::optional< Measurement > accelerometer
The acceleration in units of Gs. Depending on the IMU configuration of the sensor,...
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:392
crl::multisense::Status_Unsupported
static CRL_CONSTEXPR Status Status_Unsupported
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:103
multisense::DataSource
DataSource
Identifies which camera or data source the image is from.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:83
CRL_EXCEPTION
#define CRL_EXCEPTION(fmt,...)
Definition: Exception.hh:85
crl::multisense::details::wire::SOURCE_LUMA_RECT_AUX
static CRL_CONSTEXPR SourceType SOURCE_LUMA_RECT_AUX
Definition: Protocol.hh:277
crl::multisense::Status_Unknown
static CRL_CONSTEXPR Status Status_Unknown
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:104
crl::multisense::details::wire::SOURCE_DISPARITY
static CRL_CONSTEXPR SourceType SOURCE_DISPARITY
Definition: Protocol.hh:262
multisense::legacy::get_gyroscope_scale
double get_gyroscope_scale(const std::string &units)
Get a scale for the gyroscope value based on a units string.
Definition: legacy/utilities.cc:272
crl::multisense::details::wire::SourceType
uint64_t SourceType
Definition: Protocol.hh:250
multisense::DataSource::ALL
@ ALL
multisense::MultiSenseConfig::MaxDisparities::D256
@ D256
256 pixels
multisense::ImuSample
A single IMU sample from the camera.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:365
crl::multisense::details::wire::ImuSample::x
float x
Definition: ImuDataMessage.hh:58
crl::multisense::details::wire::SOURCE_LUMA_RECT_LEFT
static CRL_CONSTEXPR SourceType SOURCE_LUMA_RECT_LEFT
Definition: Protocol.hh:257
multisense::legacy::get_status
Status get_status(const crl::multisense::details::wire::Ack::AckStatus &status)
Definition: legacy/utilities.cc:72
multisense::DataSource::COST_RAW
@ COST_RAW
crl::multisense::details::wire::VersionType
uint16_t VersionType
Definition: Protocol.hh:137
multisense::legacy::convert_sources
std::vector< DataSource > convert_sources(const crl::multisense::details::wire::SourceType &source)
Convert wire sources to a vector of DataSources.
Definition: legacy/utilities.cc:108
multisense::legacy::ImuSampleScalars::magnetometer_scale
double magnetometer_scale
Scale for the magnetometer to convert wire samples into milligauss.
Definition: utilities.hh:96
crl::multisense::details::wire::SOURCE_COMPRESSED_LEFT
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_LEFT
Definition: Protocol.hh:280
multisense::DataSource::LEFT_MONO_COMPRESSED
@ LEFT_MONO_COMPRESSED
crl::multisense::details::wire::SOURCE_LUMA_RIGHT
static CRL_CONSTEXPR SourceType SOURCE_LUMA_RIGHT
Definition: Protocol.hh:256
multisense::Status::EXCEPTION
@ EXCEPTION
multisense::Status::UNSUPPORTED
@ UNSUPPORTED
crl::multisense::details::wire::SOURCE_LUMA_RECT_RIGHT
static CRL_CONSTEXPR SourceType SOURCE_LUMA_RECT_RIGHT
Definition: Protocol.hh:258
multisense::ImuSample::magnetometer
std::optional< Measurement > magnetometer
The measured magnetic field in milligauss. Depending on the IMU configuration of the sensor,...
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:402
multisense::Status::OK
@ OK
multisense::ImuRate
A sample rate, and what impact it has on bandwidth.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:429
multisense::DataSource::AUX_CHROMA_RECTIFIED_RAW
@ AUX_CHROMA_RECTIFIED_RAW
multisense::DataSource::AUX_RAW
@ AUX_RAW
multisense::Status::TIMEOUT
@ TIMEOUT
multisense::legacy::ImuSampleScalars::accelerometer_scale
double accelerometer_scale
Scale for the accelerometer to convert wire samples into G's.
Definition: utilities.hh:86
multisense::legacy::ImuSampleScalars
Values to scale IMU samples from the MultiSense camera into standard units LibMultiSense expects.
Definition: utilities.hh:81
crl::multisense::Status_Exception
static CRL_CONSTEXPR Status Status_Exception
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:105
multisense::MultiSenseConfig::MaxDisparities::D128
@ D128
128 pixels
crl::multisense::details::wire::SOURCE_COMPRESSED_AUX
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_AUX
Definition: Protocol.hh:282
multisense
Definition: factory.cc:39
crl::multisense::details::wire::SOURCE_IMU
static CRL_CONSTEXPR SourceType SOURCE_IMU
Definition: Protocol.hh:273
multisense::legacy::get_version
MultiSenseInfo::Version get_version(const crl::multisense::details::wire::VersionType &version)
Convert a wire version to a API Version.
Definition: legacy/utilities.cc:89
multisense::Status::FAILED
@ FAILED
multisense::legacy::is_image_source
bool is_image_source(const DataSource &source)
Determine if a datasource is a image source.
Definition: legacy/utilities.cc:45
crl::multisense::details::wire::ImuSample::z
float z
Definition: ImuDataMessage.hh:58
crl::multisense::details::wire::SOURCE_LUMA_LEFT
static CRL_CONSTEXPR SourceType SOURCE_LUMA_LEFT
Definition: Protocol.hh:255
multisense::ImuRange::range
float range
The max value the sensor can return. This value is +/- units for the given source.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:458
multisense::legacy::get_acceleration_scale
double get_acceleration_scale(const std::string &units)
Get a scale for the acceleration value based on a units string.
Definition: legacy/utilities.cc:249
multisense::ImuRange::resolution
float resolution
The min resolution the sensor can return. In units per LSB.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:463
crl::multisense::details::wire::SOURCE_COMPRESSED_RECTIFIED_LEFT
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_RECTIFIED_LEFT
Definition: Protocol.hh:283
crl::multisense::Status_TimedOut
static CRL_CONSTEXPR Status Status_TimedOut
Definition: Legacy/include/MultiSense/MultiSenseTypes.hh:100
multisense::DataSource::RIGHT_RECTIFIED_RAW
@ RIGHT_RECTIFIED_RAW
multisense::DataSource::AUX_CHROMA_RAW
@ AUX_CHROMA_RAW
multisense::DataSource::AUX_RECTIFIED_COMPRESSED
@ AUX_RECTIFIED_COMPRESSED
multisense::MultiSenseConfig::MaxDisparities::D64
@ D64
64 pixels
multisense::legacy::get_range_index
uint32_t get_range_index(const std::vector< ImuRange > &ranges, const ImuRange &range)
Get the index of the range in a vector of ranges.
Definition: legacy/utilities.cc:238
crl::multisense::details::wire::SOURCE_DISPARITY_COST
static CRL_CONSTEXPR SourceType SOURCE_DISPARITY_COST
Definition: Protocol.hh:265
multisense::legacy::expand_source
std::vector< DataSource > expand_source(const DataSource &source)
Expand sources since some sources may represent multiple sources on the wire.
Definition: legacy/utilities.cc:172
crl::multisense::details::wire::ImuInfo::details
std::vector< imu::Details > details
Definition: ImuInfoMessage.hh:118
multisense::DataSource::IMU
@ IMU
multisense::MultiSenseInfo::Version
Convenience wrapper for a version number See https://semver.org/.
Definition: LibMultiSense/include/MultiSense/MultiSenseTypes.hh:1507
multisense::legacy::get_magnetometer_scale
double get_magnetometer_scale(const std::string &units)
Get a scale for the magnetometer value based on a units string.
Definition: legacy/utilities.cc:294
crl::multisense::details::wire::ImuSample
Definition: ImuDataMessage.hh:49
crl::multisense::details::wire::SOURCE_COMPRESSED_RECTIFIED_RIGHT
static CRL_CONSTEXPR SourceType SOURCE_COMPRESSED_RECTIFIED_RIGHT
Definition: Protocol.hh:284
crl::multisense::details::wire::ImuSample::y
float y
Definition: ImuDataMessage.hh:58
crl::multisense::details::wire::ImuInfo
Definition: ImuInfoMessage.hh:109
multisense::Status::INTERNAL_ERROR
@ INTERNAL_ERROR
multisense::DataSource::LEFT_RECTIFIED_COMPRESSED
@ LEFT_RECTIFIED_COMPRESSED
crl::multisense::details::wire::SOURCE_CHROMA_RECT_AUX
static CRL_CONSTEXPR SourceType SOURCE_CHROMA_RECT_AUX
Definition: Protocol.hh:261
multisense::DataSource::LEFT_DISPARITY_RAW
@ LEFT_DISPARITY_RAW


multisense_lib
Author(s):
autogenerated on Thu Apr 17 2025 02:49:09