using MainShell.Common;
using MainShell.Hardware;
using MainShell.Log;
using MainShell.Models;
using MaxwellFramework.Core.Attributes;
using MwFramework.Device;
using MwFramework.Device.Model;
using System;
using System.Threading;
using System.Threading.Tasks;
using AppCameraType = MainShell.Common.CameraType;
namespace MainShell.Vision
{
///
/// ???????????????? HardwareManager ??????????????????????????§Ö???????
///
[Singleton]
public class ImageCaptureService : IImageCaptureService
{
private readonly HardwareManager _hardwareManager;
private readonly object _upCameraCaptureLock = new object();
private readonly object _downCameraCaptureLock = new object();
private readonly object _mapCameraCaptureLock = new object();
private readonly object _upWsCameraCaptureLock = new object();
private readonly object _upWideCameraCaptureLock = new object();
public ImageCaptureService(HardwareManager hardwareManager)
{
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
}
///
/// ??????????????????????
///
public Task CaptureAsync(
AppCameraType source,
int timeoutMilliseconds,
CameraCaptureMode captureMode = CameraCaptureMode.Stream,
CancellationToken cancellationToken = default(CancellationToken))
{
CameraCaptureOptions options = new CameraCaptureOptions();
options.TimeoutMilliseconds = timeoutMilliseconds;
options.CaptureMode = captureMode;
return CaptureAsync(source, options, cancellationToken);
}
///
/// ?????????????????
/// ????????????????????????????????????????????????????????§¹??
///
public Task CaptureAsync(
AppCameraType source,
CameraCaptureOptions options,
CancellationToken cancellationToken = default(CancellationToken))
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
int timeoutMilliseconds = options.TimeoutMilliseconds;
if (timeoutMilliseconds <= 0)
{
timeoutMilliseconds = 5000;
}
MwCamera camera = GetCamera(source);
if (camera == null)
{
string message = string.Format("ImageCaptureService: camera '{0}' not found in HardwareManager.", source);
message.LogSysError();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.CameraNotFound,
VisionErrorCode.CameraNotFound,
VisionFailureCategory.Capture,
VisionAlarmIds.CameraNotFound,
MessageKey.VisionCameraNotFound,
source,
options.CaptureMode,
message));
}
if (!camera.IsOpen)
{
string message = string.Format("ImageCaptureService: camera '{0}' is not open.", source);
message.LogSysError();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.CameraNotOpen,
VisionErrorCode.CameraNotOpen,
VisionFailureCategory.Capture,
VisionAlarmIds.CameraNotOpen,
MessageKey.VisionCameraNotOpen,
source,
options.CaptureMode,
message));
}
if (!camera.IsGrabbing)
{
string message = string.Format(
"ImageCaptureService: camera '{0}' is not grabbing. Capture mode '{1}' requires grabbing to be prepared by caller.",
source,
options.CaptureMode);
message.LogSysError();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.CameraNotGrabbing,
VisionErrorCode.CameraNotGrabbing,
VisionFailureCategory.Capture,
VisionAlarmIds.CameraNotGrabbing,
MessageKey.VisionCameraNotGrabbing,
source,
options.CaptureMode,
message));
}
string.Format(
"ImageCaptureService: capturing from '{0}' (mode={1}, timeout={2}ms).",
source,
options.CaptureMode,
timeoutMilliseconds).LogInfo();
object captureLock = GetCaptureLock(source);
try
{
CameraData data;
lock (captureLock)
{
cancellationToken.ThrowIfCancellationRequested();
switch (options.CaptureMode)
{
case CameraCaptureMode.SoftTrigger:
data = ExecuteSoftTriggerSync(camera, source, timeoutMilliseconds, out bool softTriggerFailed);
if (softTriggerFailed)
{
string softTriggerFailureMessage = string.Format(
"ImageCaptureService: soft trigger capture failed for camera '{0}' (timeout={1}ms).",
source,
timeoutMilliseconds);
softTriggerFailureMessage.LogSysError();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.SoftTriggerFailed,
VisionErrorCode.SoftTriggerFailed,
VisionFailureCategory.Driver,
VisionAlarmIds.SoftTriggerFailed,
MessageKey.VisionSoftTriggerFailed,
source,
options.CaptureMode,
softTriggerFailureMessage));
}
break;
case CameraCaptureMode.Stream:
data = camera.SnapImage(timeoutMilliseconds);
break;
default:
throw new NotSupportedException(string.Format("ImageCaptureService: capture mode '{0}' is not supported.", options.CaptureMode));
}
}
cancellationToken.ThrowIfCancellationRequested();
if (data == null)
{
string message = string.Format(
"ImageCaptureService: no frame received from '{0}' with capture mode '{1}'.",
source,
options.CaptureMode);
message.LogSysError();
ImageCaptureStatus noFrameStatus = options.CaptureMode == CameraCaptureMode.SoftTrigger
? ImageCaptureStatus.Timeout
: ImageCaptureStatus.NoFrame;
VisionErrorCode noFrameErrorCode = options.CaptureMode == CameraCaptureMode.SoftTrigger
? VisionErrorCode.CaptureTimeout
: VisionErrorCode.NoFrame;
int? noFrameAlarmId = options.CaptureMode == CameraCaptureMode.SoftTrigger
? (int?)VisionAlarmIds.CaptureTimeout
: (int?)VisionAlarmIds.NoFrame;
MessageKey noFrameMessageKey = options.CaptureMode == CameraCaptureMode.SoftTrigger
? MessageKey.VisionCaptureTimeout
: MessageKey.VisionNoFrameReturned;
return Task.FromResult(ImageCaptureResult.Failure(
noFrameStatus,
noFrameErrorCode,
VisionFailureCategory.Capture,
noFrameAlarmId,
noFrameMessageKey,
source,
options.CaptureMode,
message));
}
return Task.FromResult(ImageCaptureResult.Success(source, options.CaptureMode, new MxImage(data)));
}
catch (OperationCanceledException ex)
{
string message = string.Format("ImageCaptureService: capture from '{0}' was cancelled by caller.", source);
message.LogInfo();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.Cancelled,
VisionErrorCode.OperationCancelled,
VisionFailureCategory.Cancelled,
null,
MessageKey.VisionOperationCancelled,
source,
options.CaptureMode,
message,
ex));
}
catch (Exception ex)
{
string message = string.Format("ImageCaptureService: capture from '{0}' failed. {1}", source, ex.Message);
message.LogSysError();
return Task.FromResult(ImageCaptureResult.Failure(
ImageCaptureStatus.DriverError,
VisionErrorCode.DriverError,
VisionFailureCategory.Driver,
VisionAlarmIds.DriverError,
MessageKey.VisionDriverError,
source,
options.CaptureMode,
message,
ex));
}
}
private static CameraData ExecuteSoftTriggerSync(MwCamera camera, AppCameraType source, int timeoutMilliseconds, out bool softTriggerFailed)
{
softTriggerFailed = false;
CameraData data = new CameraData();
DriverLibResult result = camera.ExcuteSoftTrigger(ref data);
if (result != DriverLibResult.DriverLibNoError)
{
softTriggerFailed = true;
string.Format(
"ImageCaptureService: soft trigger capture failed for camera '{0}' (timeout={1}ms), driver result={2}.",
source,
timeoutMilliseconds,
result).LogSysError();
return null;
}
if (data == null)
{
string.Format(
"ImageCaptureService: soft trigger capture returned null frame for camera '{0}' (timeout={1}ms).",
source,
timeoutMilliseconds).LogSysError();
return null;
}
return data;
}
private MwCamera GetCamera(AppCameraType source)
{
return _hardwareManager.GetCamera(source).Camera;
}
private object GetCaptureLock(AppCameraType source)
{
switch (source)
{
case AppCameraType.TopPositionCamera:
return _upCameraCaptureLock;
case AppCameraType.TopWideCamera:
return _mapCameraCaptureLock;
case AppCameraType.MapCamera:
return _downCameraCaptureLock;
case AppCameraType.TopWsCamera:
return _upWsCameraCaptureLock;
case AppCameraType.TopWideWsCamera:
return _upWideCameraCaptureLock;
default:
throw new ArgumentOutOfRangeException(nameof(source), source, "ImageCaptureService: unknown camera type for capture lock.");
}
}
}
}