@@ -147,19 +147,21 @@ Status MultiChannelTask::ExposeFrame(int i_ch,
147147 return status;
148148}
149149
150- ImageData
150+ StatusOr< ImageData>
151151MultiChannelTask::GetFrame (int i_ch,
152152 std::chrono::system_clock::time_point *timestamp)
153153{
154154 Channel channel = channels[i_ch];
155155 Status status = dcam->WaitFrameReady (1000 );
156156 if (!status.ok ()) {
157- // This should not happen
158- // Log and then continue anyways to see whether it is possible to get
159- // frame data if there is no data, throw exception there
160- LOG_WARN (
161- " [{}][{}] WaitFrameReady returned false, which indicates ABORT" ,
162- ndimage_name, i_ch);
157+ // error DCAMERR_LOSTFRAME can happen here in ~1/5000 chance
158+ // Calling WaitFrameReady again won't help, and can only get
159+ // DCAMERR_TIMEOUT.
160+ // So it cannot be recovered here, and let's return
161+ // the error.
162+ LOG_ERROR (" [{}][{}] WaitFrameReady failed: {}" , ndimage_name, i_ch + 1 ,
163+ status.ToString ());
164+ return status;
163165 } else {
164166 LOG_DEBUG (" [{}][{}] Frame ready [{:.1f} ms after exposure end]" ,
165167 ndimage_name, i_ch + 1 , sw_exposure_end.Milliseconds ());
@@ -168,8 +170,11 @@ MultiChannelTask::GetFrame(int i_ch,
168170 utils::StopWatch sw;
169171 StatusOr<ImageData> frame = dcam->GetFrame (i_ch, timestamp);
170172 if (!frame.ok ()) {
171- throw std::runtime_error (
172- " GetFrame returned nullptr without throwing an exception" );
173+ std::string error_msg =
174+ fmt::format (" [{}][{}] GetFrame failed: {}" , ndimage_name, i_ch + 1 ,
175+ frame.status ().ToString ());
176+ LOG_ERROR (error_msg);
177+ return frame.status ();
173178 }
174179 LOG_DEBUG (" [{}][{}] Get frame [{:.1f} ms]" , ndimage_name, i_ch + 1 ,
175180 sw.Milliseconds ());
@@ -281,14 +286,22 @@ Status MultiChannelTask::Acquire(std::string ndimage_name,
281286 //
282287 utils::StopWatch sw_frame;
283288 utils::StopWatch sw_channel;
289+ int i_retry = 0 ;
284290 try {
285291 for (int i_ch = 0 ; i_ch < channels.size (); i_ch++) {
286- status = exp->Channels ()->WaitSwitchChannel ();
287- if (!status.ok ()) {
288- LOG_ERROR (" [{}][{}/{}] SwitchChannel failed: {}" , ndimage_name,
289- i_ch + 1 , channels.size (), status.ToString ());
290- StopAcqusition ();
291- return status;
292+ if (i_retry > 0 ) {
293+ LOG_INFO (" [{}][{}/{}] retry {} " , ndimage_name, i_ch + 1 ,
294+ channels.size (), i_retry);
295+ }
296+
297+ if (i_retry == 0 ) {
298+ status = exp->Channels ()->WaitSwitchChannel ();
299+ if (!status.ok ()) {
300+ LOG_ERROR (" [{}][{}/{}] SwitchChannel failed: {}" ,
301+ ndimage_name, i_ch + 1 , channels.size (),
302+ status.ToString ());
303+ goto cleanup;
304+ }
292305 }
293306
294307 channel = channels[i_ch];
@@ -307,8 +320,7 @@ Status MultiChannelTask::Acquire(std::string ndimage_name,
307320 if (!status.ok ()) {
308321 LOG_ERROR (" [{}][{}/{}] ExposeFrame failed: {}" , ndimage_name,
309322 i_ch + 1 , channels.size (), status.ToString ());
310- StopAcqusition ();
311- return status;
323+ goto cleanup;
312324 }
313325 if (i_ch + 1 < channels.size ()) {
314326 sw_channel.Reset ();
@@ -319,7 +331,34 @@ Status MultiChannelTask::Acquire(std::string ndimage_name,
319331 }
320332
321333 std::chrono::system_clock::time_point timestamp;
322- ImageData data = GetFrame (i_ch, ×tamp);
334+ StatusOr<ImageData> data = GetFrame (i_ch, ×tamp);
335+ status = data.status ();
336+ if (!status.ok ()) {
337+ if (absl::IsDataLoss (status)) {
338+ // This is a rare error (~1/5000 chance), try recovering
339+ if (i_retry < 2 ) {
340+ // Try recovering the error
341+ LOG_ERROR (" [{}][{}/{}] [Retry {}] GetFrame failed: {}. "
342+ " Reacquire the channel after 500 ms" ,
343+ ndimage_name, i_ch + 1 , channels.size (),
344+ i_retry, status.ToString ());
345+ std::this_thread::sleep_for (
346+ std::chrono::milliseconds (500 ));
347+ i_retry++;
348+ i_ch--;
349+ continue ;
350+ } else {
351+ LOG_ERROR (" [{}][{}/{}] [Retry {}] GetFrame failed: {}."
352+ " Max retries reached. Failed" ,
353+ ndimage_name, i_ch + 1 , channels.size (),
354+ i_retry, status.ToString ());
355+ goto cleanup;
356+ }
357+ }
358+ LOG_ERROR (" [{}][{}/{}] GetFrame failed: {}" , ndimage_name,
359+ i_ch + 1 , channels.size (), status.ToString ());
360+ goto cleanup;
361+ }
323362
324363 nlohmann::ordered_json new_metadata;
325364 new_metadata[" timestamp" ] =
@@ -343,15 +382,25 @@ Status MultiChannelTask::Acquire(std::string ndimage_name,
343382 new_metadata[" device_property" ][k.ToString ()] = v;
344383 }
345384
346- exp->Images ()->AddImage (ndimage_name, i_ch, i_z, i_t , data,
385+ exp->Images ()->AddImage (ndimage_name, i_ch, i_z, i_t , data. value () ,
347386 new_metadata);
348387 LOG_INFO (" [{}][{}] Frame completed [{:.0f} ms]" , ndimage_name,
349388 i_ch + 1 , sw_frame.Milliseconds ());
389+ i_retry = 0 ;
350390 }
351391 } catch (std::exception &e) {
352- LOG_ERROR (" Unexpected exception during acquisition : {}" , e.what ());
392+ status = absl::UnknownError (fmt::format (
393+ " Unexpected exception during acquisition: {}" , e.what ()));
394+ }
395+
396+ cleanup:
397+ // Clean up after failed acquisition
398+ if (!status.ok ()) {
399+ LOG_ERROR (" Stopping acquisition due to error: {}" , status.ToString ());
353400 StopAcqusition ();
354- throw ;
401+ double task_elapse_ms = sw_task.Milliseconds ();
402+ LOG_ERROR (" [{}] Task failed: {:.0f} ms" , ndimage_name, task_elapse_ms);
403+ return status;
355404 }
356405
357406 StopAcqusition ();
0 commit comments