288 lines
12 KiB
C#
288 lines
12 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// ???????????????? HardwareManager ??????????????????????????§Ö???????
|
|
/// </summary>
|
|
[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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// ??????????????????????
|
|
/// </summary>
|
|
public Task<ImageCaptureResult> 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// ?????????????????
|
|
/// ????????????????????????????????????????????????????????§¹??
|
|
/// </summary>
|
|
public Task<ImageCaptureResult> 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.");
|
|
}
|
|
}
|
|
}
|
|
}
|