- Extended CJMS11 camera handling with new functionalities, including image grabbing, resolution configuration, and improved ROI support. - Added new `ToString` method implementations for enhanced debugging and logging in key classes like `JmsMessage`, `JmsPacket`, and `RoiCfg`. - Introduced additional commands (`start_stream_images`, `stop_stream_images`) in `CommandM` and its enum. - Implemented new resolution handling in `RoiCfg` with support for configurable image frames. - Refactored resolution-related UI elements in `RoiCfgCtrl` to add a dropdown for selecting resolution. - Made minor UX improvements by replacing inconsistent string formats with verbatim strings in console messages. - Updated project dependencies with new resolution-related utilities (`Frame` and `ResolutionFrames`). - Resolved camera-specific symbolic issues by transitioning to `CJMS11.Camera` over prior naming inconsistencies.
1596 lines
45 KiB
C#
1596 lines
45 KiB
C#
///
|
|
/// Copyright (c) 2017-2022 Sensus Slovensko a.s.
|
|
///
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using log4net;
|
|
using Renci.SshNet;
|
|
using Common;
|
|
using FluentNHibernate.Conventions;
|
|
using Newtonsoft.Json;
|
|
using TBF.Rig.Network.Telnet;
|
|
using TBF.Resources;
|
|
using TBF.Rig.Generic;
|
|
using TBF.Rig.Network.Camera.CJMS11.POJO;
|
|
using TBF.Rig.Network.Camera.common;
|
|
using TBF.Rig.Network.Camera.RoiForFixedStartCJMS11;
|
|
using TBF.UiBridge;
|
|
|
|
namespace TBF.Rig.Network.Camera.CJMS11
|
|
{
|
|
/// <summary>
|
|
/// This class implements: (1) Camera device, (2) Measurement operation
|
|
/// </summary>
|
|
public class Camera : ComponentBase, GenericDevices.ICamera, Generic.IDevice, IOperation
|
|
{
|
|
private static readonly ILog log = LogManager.GetLogger(typeof(Camera));
|
|
public override string ToString()
|
|
{
|
|
return string.Format("{0}: Name={1}, Addr={2}, IP={3}, s/n={4}, SD={5}",
|
|
this.GetType().Namespace.Substring(8),
|
|
CameraCfg.Name,
|
|
CameraCfg.HardwareAddress,
|
|
CameraCfg.DebugLevel == DebugMode.Simulate ? "simulated" : ((ipAddress == null) ? "not detected" : ipAddress.ToString()),
|
|
CameraCfg.DebugLevel == DebugMode.Simulate ? "simulated" : (string.IsNullOrEmpty(cpuSerialNr) ? "not detected" : cpuSerialNr),
|
|
CameraCfg.DebugLevel == DebugMode.Simulate ? "simulated" : (string.IsNullOrEmpty(sdCardVer) ? "not detected" : sdCardVer));
|
|
}
|
|
|
|
|
|
private const int iPort = 32456;
|
|
string ClpUserName = string.Empty; /// Either "tbf" or "pi" after a successful detection
|
|
const string ClpPassword = "C1ern4V0d4";
|
|
|
|
|
|
|
|
|
|
///
|
|
/// Properties
|
|
///
|
|
public readonly CameraCfg CameraCfg;
|
|
public readonly AdapterJMS.Netadapter NetAdapter;
|
|
|
|
private RoiCfg roiConfiguration;
|
|
public RoiCfg RoiConfiguration
|
|
{
|
|
get {
|
|
if (roiConfiguration!=null) {return roiConfiguration;}
|
|
else { roiConfiguration = GetFirstRoiChild(); return roiConfiguration; }
|
|
}
|
|
set { if (roiConfiguration == null) roiConfiguration = value;}
|
|
}
|
|
|
|
public IPAddress IPAddress { get { return ipAddress; } }
|
|
IPAddress ipAddress;
|
|
|
|
public string CpuHardware { get { return cpuHardware; } }
|
|
string cpuHardware;
|
|
|
|
public string CpuRevision { get { return cpuRevision; } }
|
|
string cpuRevision;
|
|
|
|
public string CpuSerialNr { get { return cpuSerialNr; } }
|
|
string cpuSerialNr;
|
|
|
|
public string SDCardVer { get { return sdCardVer; } }
|
|
string sdCardVer;
|
|
|
|
public bool Running { get { return running; } }
|
|
bool running;
|
|
|
|
public bool ShowOverlayRect { set { showOverlayRect = value; } }
|
|
bool showOverlayRect = false;
|
|
|
|
public Rectangle OverlayRect { set { overlayRect = value; } }
|
|
Rectangle overlayRect;
|
|
|
|
public int OverlayThickness { set { overlayThickness = value; } }
|
|
int overlayThickness;
|
|
|
|
public int CameraIdx { get { return cameraIdx; } }
|
|
int cameraIdx;
|
|
///
|
|
static int nextCameraIdx = 0;
|
|
|
|
static int GetCameraIdx() { return nextCameraIdx++; } /// Used in Initialize()
|
|
|
|
///
|
|
/// Telnet support
|
|
///
|
|
const string TelnetPrompt = "$ ";
|
|
const bool TelnetSkipFirstLine = true;
|
|
|
|
private TerminalDlg terminalDlg;
|
|
string sha1sumResponse;
|
|
JmsMessage jmsMessage;
|
|
bool sha1sumResponseProcessed;
|
|
|
|
///
|
|
/// scp support
|
|
///
|
|
|
|
PasswordConnectionInfo connectionInfo;
|
|
|
|
|
|
|
|
///
|
|
/// MJpeg RTP protocol support
|
|
///
|
|
public bool CameraConnected{ get {return cameraTcpClient != null && cameraTcpClient.Connected;} }
|
|
int cameraTcpLocalPort;
|
|
TcpClient cameraTcpClient;
|
|
private NetworkStream cameraStream = null;
|
|
private StreamWriter cameraWriter = null;
|
|
private StreamReader cameraReader = null;
|
|
private Image lastImage;
|
|
private bool lockCameraInitialisation = false;
|
|
|
|
Thread liveStreamListenerThread;
|
|
static bool stopLiveStreamListenerFlag;
|
|
|
|
public bool IsGrabImageListenerThreadAlive { get { return grabImageListenerThread != null && grabImageListenerThread.IsAlive; } }
|
|
Thread grabImageListenerThread;
|
|
static bool stopGrabImageListenerFlag;
|
|
public void SetStopGrabImageListenerFlag() { stopGrabImageListenerFlag = true; }
|
|
|
|
Thread stopUIListenerThread;
|
|
static bool stopUIListenerFlag;
|
|
|
|
Thread saveImageListenerThread;
|
|
static bool stopSaveImageListenerFlag;
|
|
public bool IsSaveImageListenerThreadAlive { get { return saveImageListenerThread != null && saveImageListenerThread.IsAlive; } }
|
|
|
|
///
|
|
/// ROI related parameters
|
|
///
|
|
RoisAndResults roisAndResults;
|
|
///
|
|
public void ClearRoiParams()
|
|
{
|
|
roisAndResults.ClearRoiParams();
|
|
}
|
|
|
|
public int RegisterRoi(string roiParams)
|
|
{
|
|
return roisAndResults.RegisterRoi(roiParams);
|
|
}
|
|
|
|
public int GetResult(int roiHandle, out long timeMs)
|
|
{
|
|
return roisAndResults.GetResult(roiHandle, out timeMs);
|
|
}
|
|
|
|
|
|
public Camera() { }
|
|
|
|
public Camera(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
|
: base(cfg)
|
|
{
|
|
CameraCfg = cfg as CameraCfg;
|
|
|
|
// NetAdapter = TbfComponents.FindComponent(cfg.ParentName, components) as TBF.Rig.Network.AdapterJMS.Netadapter;
|
|
//if (NetAdapter == null) throw new ArgumentNullException("no network adapter");
|
|
}
|
|
|
|
|
|
public override void Initialize()
|
|
{
|
|
cameraIdx = GetCameraIdx();
|
|
|
|
running = false;
|
|
terminalDlg = null;
|
|
roisAndResults = new RoisAndResults(); /// object for measurement results, writes/reads to/from this object are locked
|
|
|
|
// if (CameraCfg.DebugLevel == DebugMode.Simulate)
|
|
// {
|
|
// UiBridge.Bridge.OnCameraInfo(cameraIdx, string.Format("{0} s/n {1} si simulated", Name, CameraCfg.HardwareAddress));
|
|
// return;
|
|
// }
|
|
|
|
/// Detect a camera
|
|
CameraDetectionResult cameraDetectionResult = null;
|
|
var detectJmsCamera = DetectJMSCamera();
|
|
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));
|
|
|
|
//No Test
|
|
var completedTask = Task.WhenAny(detectJmsCamera, timeoutTask).Result;
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
cameraDetectionResult = new CameraDetectionResult();
|
|
cameraDetectionResult.IsDetected = false;
|
|
}
|
|
|
|
//test
|
|
// var detectJmsCamera1 = DetectJMSCamera("192.168.0.170",32456);
|
|
// var detectJmsCamera2 = DetectJMSCamera("192.168.0.168",32456);
|
|
// Task.WaitAll(detectJmsCamera, detectJmsCamera1, detectJmsCamera2);
|
|
|
|
if (cameraDetectionResult == null)
|
|
{
|
|
cameraDetectionResult = detectJmsCamera.Result;
|
|
}
|
|
|
|
if (CameraCfg.DebugLevel == DebugMode.AutoDetect)
|
|
{
|
|
CameraCfg.DebugLevel = cameraDetectionResult.IsDetected ? DebugMode.DetectedOn : DebugMode.DetectedOff;
|
|
}
|
|
else if (!cameraDetectionResult.IsDetected)
|
|
{
|
|
throw new Exception(string.Format("{0}={1}", Strings.Address, CameraCfg.HardwareAddress));
|
|
}
|
|
|
|
if (cameraDetectionResult.IsDetected)
|
|
{
|
|
UiBridge.Bridge.OnCameraInfo(cameraIdx, string.Format("{0} ver.{1} {2} s/n {3}", Name, sdCardVer, ipAddress, CameraCfg.HardwareAddress));
|
|
|
|
// start live stream, grab image, ... listener thread
|
|
UiBridge.Bridge.CameraUICmdHandler += HandleCameraUiCmd;
|
|
|
|
//PromptCameraReceivedHandler += OnPromptReceivedCamera;
|
|
|
|
ImageCameraHandler += OnPromptImageReceived;
|
|
}
|
|
else
|
|
{
|
|
UiBridge.Bridge.OnCameraInfo(this.cameraIdx, string.Format("{0} s/n {1} was not detected", Name, CameraCfg.HardwareAddress));
|
|
log.FatalFormat("'{0}' NOT detected: Id={1} addr={2}", Name, CameraIdx, CameraCfg.HardwareAddress);
|
|
}
|
|
}
|
|
|
|
private void OnPromptImageReceived(object sender, PromptReceivedImageEventArgs e)
|
|
{
|
|
if (e != null && e.image != null)
|
|
{
|
|
if (this.cameraIdx == e.idxCamera)
|
|
{
|
|
UiBridge.Bridge.OnImage(e.idxCamera, e.image);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StopDevice()
|
|
{
|
|
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
|
|
{
|
|
running = false;
|
|
|
|
|
|
stopLiveStreamListenerFlag = true;
|
|
stopGrabImageListenerFlag = true;
|
|
|
|
}
|
|
}
|
|
|
|
public void StopDevice2()
|
|
{
|
|
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
|
|
{
|
|
|
|
if (liveStreamListenerThread != null) liveStreamListenerThread.Join(50);
|
|
if (grabImageListenerThread != null) grabImageListenerThread.Join(50);
|
|
|
|
if (cameraTcpClient != null)
|
|
{
|
|
cameraTcpClient.Close();
|
|
cameraTcpClient = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RunDeviceBefore()
|
|
{
|
|
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
|
|
{
|
|
if (sha1sumResponse != null && !sha1sumResponseProcessed)
|
|
{
|
|
|
|
|
|
sha1sumResponseProcessed = true;
|
|
}
|
|
}
|
|
}
|
|
public void RunDeviceAfter() { }
|
|
|
|
|
|
void OnPromptReceived(object sndr, PromptReceivedJMSEventArgs a)
|
|
{
|
|
if (sha1sumResponse == null)
|
|
{
|
|
sha1sumResponse = a.Response;
|
|
jmsMessage = a.Message;
|
|
}
|
|
}
|
|
|
|
void OnReceivedImageX(object sndr, PromptReceivedImageEventArgs a)
|
|
{
|
|
if (a != null)
|
|
{
|
|
lastImage = a.image;
|
|
}
|
|
}
|
|
|
|
void OnPromptReceivedCamera(object sndr, PromptReceivedJMSEventArgs a)
|
|
{
|
|
try
|
|
{
|
|
JmsPacket packet = new JmsPacket(a.Response);
|
|
jmsMessage = packet.JmsMessage;
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error(exc.Message);
|
|
}
|
|
}
|
|
|
|
void OnReceivedPackage(object sndr, PromptReceivedEventArgs a)
|
|
{
|
|
if (sha1sumResponse == null)
|
|
{
|
|
sha1sumResponse = a.Response;
|
|
try
|
|
{
|
|
JmsPacket packet = new JmsPacket(a.Response);
|
|
jmsMessage = packet.JmsMessage;
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error(exc.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Configuration Change Handling
|
|
|
|
public static void OnCfgChange(object sender, CfgChangeArgs args)
|
|
{
|
|
if (CfgChangeHandler == null) return;
|
|
try { CfgChangeHandler(sender, args); }
|
|
catch (Exception e) { log.Error("CfgChangeHandler(...) failed", e); }
|
|
}
|
|
|
|
public static event EventHandler<CfgChangeArgs> CfgChangeHandler;
|
|
|
|
public override void StartChangeHandler()
|
|
{
|
|
CfgChangeHandler += delegate(object sender, CfgChangeArgs args)
|
|
{
|
|
CameraCfg tmpcfg = args.Cfg as CameraCfg;
|
|
if (tmpcfg != null && tmpcfg.Name.Equals(Name))
|
|
{
|
|
if (args.Command == CfgChangeCmd.CfgChange)
|
|
{
|
|
CameraCfg.TestImagesMode = tmpcfg.TestImagesMode;
|
|
CameraCfg.TestImagesCount = tmpcfg.TestImagesCount;
|
|
CameraCfg.IPAddressCJMS = tmpcfg.IPAddressCJMS;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#endregion Configuration Change Handling
|
|
|
|
|
|
public class CameraDetectionResult
|
|
{
|
|
public bool IsDetected { get; set; }
|
|
public IPAddress IpAddress { get; set; }
|
|
public string Hardware { get; set; }
|
|
public string Revision { get; set; }
|
|
public string Serial { get; set; }
|
|
public string SdCardVersion { get; set; }
|
|
public string Response { get; set; }
|
|
public double Duration_ms { get; set; }
|
|
}
|
|
|
|
async Task<CameraDetectionResult> DetectJMSCamera()
|
|
{
|
|
return await DetectJMSCamera(CameraCfg.IPAddressCJMS, iPort);
|
|
}
|
|
|
|
async Task<CameraDetectionResult> DetectJMSCamera(string ipAddressParam, int portParam)
|
|
{
|
|
CameraDetectionResult result = new CameraDetectionResult();
|
|
if (CameraCfg.IPAddressCJMS != null)
|
|
{
|
|
try
|
|
{
|
|
|
|
using (this.cameraTcpClient = new TcpClient())
|
|
{
|
|
var connectTask = this.cameraTcpClient.ConnectAsync(ipAddressParam, portParam);
|
|
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
|
|
var completedTask = Task.WhenAny(connectTask, timeoutTask).Result;
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
throw new TimeoutException("Connection attempt timed out after 1 second.");
|
|
}
|
|
//TcpClient tcpClient = await EstablishCameraConnection(CameraCfg.IPAddressCJMS, iPort);
|
|
log.Debug(string.Format("Camera connected to server {0}:{1}.", CameraCfg.IPAddressCJMS, iPort));
|
|
this.ipAddress = IPAddress.Parse(CameraCfg.IPAddressCJMS);
|
|
// Get network stream
|
|
|
|
|
|
using (NetworkStream stream = cameraTcpClient.GetStream())
|
|
using (StreamWriter writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true })
|
|
using (StreamReader reader = new StreamReader(stream, Encoding.ASCII))
|
|
{
|
|
stream.ReadTimeout = 1000;
|
|
|
|
// Send command
|
|
DateTime detectionStart = DateTime.Now;
|
|
|
|
// create config and send
|
|
string message = getConfigMessage();
|
|
JmsPacket answer = SendCommandAndWaitToAnswer(writer, reader, CommandM.type_camera_,message);
|
|
if (answer == null || answer.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
log.Error(answer);
|
|
}
|
|
//Prepare camera
|
|
JmsPacket answerPrepare = SendCommandAndWaitToAnswer(writer, reader, CommandM.prepare_camera_);
|
|
if (answerPrepare == null || answerPrepare.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
if (!(answerPrepare != null && answerPrepare.JmsMessage.Status == MessageStatus.NACK &&
|
|
answerPrepare.JmsMessage.Payload == "OPENED")) //correct if NACK & OPENED
|
|
{
|
|
log.Error(answerPrepare);
|
|
}
|
|
else
|
|
{
|
|
SendCommandAndWaitToAnswer(writer, reader, CommandM.close_);
|
|
var sendCommandAndWaitToAnswer = SendCommandAndWaitToAnswer(writer, reader, CommandM.prepare_camera_);
|
|
if (sendCommandAndWaitToAnswer == null || sendCommandAndWaitToAnswer.JmsMessage.Status == MessageStatus.NACK) //correct if NACK & OPENED
|
|
{
|
|
log.Error("Restart close, prepare camera not successfully! see: " + answerPrepare);
|
|
}
|
|
}
|
|
}
|
|
//Status
|
|
JmsPacket answerStatus = SendCommandAndWaitToAnswer(writer, reader, CommandM.status_);
|
|
if (answerStatus == null || answerStatus.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
log.Error(answerStatus);
|
|
}
|
|
//Get config
|
|
JmsPacket answerCfg = SendCommandAndWaitToAnswer(writer, reader, CommandM.get_cfg_);
|
|
if (answerCfg == null || answerCfg.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
log.Error(answerCfg);
|
|
}else{
|
|
result.IpAddress = IPAddress.Parse(ipAddressParam);
|
|
}
|
|
|
|
|
|
result.Duration_ms = (DateTime.Now - detectionStart).TotalMilliseconds;
|
|
|
|
result.Hardware = string.Empty;
|
|
result.Revision = string.Empty;
|
|
result.Serial = string.Empty;
|
|
result.SdCardVersion = string.Empty;
|
|
|
|
string msg = string.Format("Camera {0} detected in {1} ms: HWAddress={2} IPAddress={3} {4}",
|
|
CameraCfg.Name,
|
|
result.Duration_ms,
|
|
CameraCfg.HardwareAddress,
|
|
this.ipAddress == null ? "not detected" : this.ipAddress.ToString(),
|
|
answerCfg.MessageOrigin);
|
|
log.Debug(msg);
|
|
Console.WriteLine(msg);
|
|
|
|
cameraTcpClient.Dispose();
|
|
cameraTcpClient = null;
|
|
|
|
result.IsDetected = true;
|
|
return result; /// Camera detected
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.ErrorFormat("Camera {0} with HWAddress={1} not detected : {2}", CameraCfg.Name,
|
|
CameraCfg.HardwareAddress, exc.Message);
|
|
}
|
|
}
|
|
|
|
if (CameraCfg.DebugLevel == DebugMode.Simulate)
|
|
{
|
|
result.Hardware = null;
|
|
result.Revision = null;
|
|
result.Serial = null;
|
|
result.SdCardVersion = null;
|
|
result.IpAddress = null;
|
|
|
|
result.IsDetected = true;
|
|
return result;
|
|
}
|
|
|
|
result.Hardware = null;
|
|
result.Revision = null;
|
|
result.Serial = null;
|
|
result.SdCardVersion = null;
|
|
result.IpAddress = null;
|
|
|
|
result.IsDetected = false;
|
|
return result; /// No camera detected
|
|
}
|
|
|
|
class SensorConfig{
|
|
public string type { get; set; } = "all";
|
|
public int width { get; set; } = 640;
|
|
public int height { get; set; } = 480;
|
|
public int fps { get; set; } = 10;
|
|
public int exposure { get; set; } = 2000;
|
|
public float brightness { get; set; } = 0.5f;
|
|
public float contrast { get; set; } = 1.5f;
|
|
public int nBuffersOverload { get; set; } = 5;
|
|
|
|
public static string getJsonString(SensorConfig sensorConfig)
|
|
{
|
|
string returnStr = JsonConvert.SerializeObject(sensorConfig, Formatting.Indented);
|
|
|
|
returnStr = returnStr.Replace("\n", "");
|
|
returnStr = returnStr.Replace("\r", "");
|
|
return returnStr;
|
|
}
|
|
}
|
|
|
|
private RoiCfg GetFirstRoiChild()
|
|
{
|
|
/// Load the list of components from the database
|
|
var session = TBF.DB.CreateSession(DBKind.Config);
|
|
var cmptnEntities = session.QueryOver<Config.Entities.Component>().OrderBy(x => x.ItemNr).Asc.List();
|
|
|
|
|
|
List<RoiCfg> cfgs = new List<RoiCfg>();
|
|
IList<IComponent> components = new List<Rig.Generic.IComponent>();
|
|
foreach (var component in cmptnEntities)
|
|
{
|
|
if (String.Compare(component.Parent, Name, StringComparison.Ordinal) == 0)
|
|
{
|
|
IComponentFactory cmpntFactory = Rig.TbfComponents.CmpntFactoryFromClassName(component.ClassName);
|
|
if (cmpntFactory == null) continue;
|
|
|
|
IList<IComponent> tbfComponents = Rig.TbfComponents.LoadComponentsFromDB(cmptnEntities);
|
|
IComponentCfg cmpntCfgFromCmpntEntity = cmpntFactory.CmpntCfgFromCmpntEntity(component);
|
|
|
|
IComponent cmpnt = cmpntFactory.GetComponent(cmpntCfgFromCmpntEntity, components);
|
|
|
|
RoiForFixedStartCJMS11.RoiCfg roi = cmpntCfgFromCmpntEntity as RoiForFixedStartCJMS11.RoiCfg;
|
|
|
|
if (roi != null)
|
|
{
|
|
cfgs.Add(roi);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// get fist found configuration
|
|
return cfgs.First();
|
|
}
|
|
|
|
private string getConfigMessage()
|
|
{
|
|
//CameraCfg
|
|
SensorConfig sensorConfig = new SensorConfig();
|
|
sensorConfig.height = RoiConfiguration.ImageFrame.Height;
|
|
sensorConfig.width = RoiConfiguration.ImageFrame.Width;
|
|
return SensorConfig.getJsonString(sensorConfig);
|
|
}
|
|
|
|
|
|
void CameraInfoRequest(UdpClient udpClient, int hardwareAddress)
|
|
{
|
|
string strToSend = string.Format("getinfo {0}", hardwareAddress);
|
|
|
|
}
|
|
|
|
void SetDateTime(UdpClient udpClient, DateTime dateTime)
|
|
{
|
|
string strToSend = string.Format("setdatetime {0:yyMMddHHmmss}", dateTime);
|
|
|
|
}
|
|
|
|
|
|
private CameraUICmd lockBrich = CameraUICmd.None;
|
|
|
|
// Define the handler method
|
|
private void HandleCameraUiCmd(object sender, CameraUICmdEventArgs e)
|
|
{
|
|
if(lockBrich != CameraUICmd.None && e.CameraUICmd != CameraUICmd.Stop)
|
|
return;
|
|
|
|
if (!(e.CameraIdx == -1 || e.CameraIdx == cameraIdx))
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
//lock
|
|
lockBrich = e.CameraUICmd;
|
|
// Example reaction to event
|
|
if (e.CameraUICmd == CameraUICmd.Live)
|
|
{
|
|
if (stopLiveStreamListenerFlag == false && liveStreamListenerThread != null &&
|
|
liveStreamListenerThread.IsAlive)
|
|
return;
|
|
log.Debug("Handle CameraUICmd received - Live");
|
|
stopLiveStreamListenerFlag = false;
|
|
stopUIListenerFlag = true;
|
|
StartLiveStreamListener(IPAddress, iPort);
|
|
}
|
|
else if (e.CameraUICmd == CameraUICmd.Stop)
|
|
{
|
|
StopUiThreads();
|
|
stopUIListenerFlag = true;
|
|
log.Debug("Handle CameraUICmd received - Stop Live");
|
|
}
|
|
else if (e.CameraUICmd == CameraUICmd.Grab)
|
|
{
|
|
log.Debug($"Handle CameraUICmd received - GrabImage - camera idx: {cameraIdx}");
|
|
stopUIListenerFlag = true;
|
|
StopUiThreads();
|
|
StartGrabImageListener();
|
|
}
|
|
else if (e.CameraUICmd == CameraUICmd.SaveImage)
|
|
{
|
|
log.Debug("Handle CameraUICmd received - SaveImage - will end Live Stream");
|
|
StopUiThreads();
|
|
StartSaveImageListener();
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
//Unlock - if is not in live - live will finish only by CameraUICmd.Stop
|
|
if (lockBrich != CameraUICmd.Live)
|
|
lockBrich = CameraUICmd.None;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lockBrich = CameraUICmd.None; //Unlock - solve hard lock
|
|
stopUIListenerFlag = true;
|
|
}
|
|
|
|
}
|
|
|
|
void SaveImageToFile(Image imageToSave)
|
|
{
|
|
|
|
|
|
if (imageToSave == null)
|
|
{
|
|
log.Error("Nothing to save in SaveImageToFile");
|
|
return; // nothing to save
|
|
}
|
|
|
|
using (SaveFileDialog dialog = new SaveFileDialog())
|
|
{
|
|
dialog.Title = "Save Image As";
|
|
dialog.Filter = "PNG Image|*.png|JPEG Image|*.jpg|Bitmap Image|*.bmp";
|
|
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
|
|
dialog.FileName = "my_image.png";
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
// Choose format based on extension
|
|
var ext = System.IO.Path.GetExtension(dialog.FileName).ToLower();
|
|
System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Png;
|
|
if (ext == ".jpg") format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
|
else if (ext == ".bmp") format = System.Drawing.Imaging.ImageFormat.Bmp;
|
|
|
|
try
|
|
{
|
|
SaveImageToFile(imageToSave, dialog.FileName);
|
|
MessageBox.Show("Image saved to: " + dialog.FileName);
|
|
}catch(Exception exc)
|
|
{
|
|
MessageBox.Show("Error saving image: " + exc.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SaveImageToFile(Image imageToSave, string fileNamePath)
|
|
{
|
|
if (imageToSave == null)
|
|
{
|
|
log.Error("Nothing to save in SaveImageToFile");
|
|
return; // nothing to save
|
|
}
|
|
|
|
if (fileNamePath == null || fileNamePath.IsEmpty())
|
|
{
|
|
log.Error("Path to save missing!");
|
|
return; // nothing to save
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
string filePath = fileNamePath;
|
|
|
|
string path = Path.GetDirectoryName(filePath);
|
|
if (path != null && path.IsNotEmpty())
|
|
{
|
|
Directory.CreateDirectory(path);
|
|
}
|
|
|
|
using (var clonedImage = CloneImageToBitmap(imageToSave))
|
|
{
|
|
clonedImage.Save(filePath, ImageFormat.Png); // encoder, encoderParams);
|
|
}
|
|
log.Debug("Image saved to: " + filePath);
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error("Error saving image: " + exc.Message);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private static ImageCodecInfo GetEncoder(ImageFormat format)
|
|
{
|
|
return ImageCodecInfo.GetImageDecoders().FirstOrDefault(codec => codec.FormatID == format.Guid);
|
|
}
|
|
|
|
|
|
private Bitmap CloneImageToBitmap(Image originalImage)
|
|
{
|
|
return new Bitmap(originalImage);
|
|
}
|
|
private Image CloneImage(Image originalImage)
|
|
{
|
|
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
originalImage.Save(ms, ImageFormat.Png); // Use a safe format for copying
|
|
ms.Position = 0;
|
|
return Image.FromStream(ms);
|
|
}
|
|
}
|
|
|
|
public void StartSaveImageToFileListener(Image imageToSave, string fileName)
|
|
{
|
|
saveImageListenerThread = new Thread(() => SaveImageToFile(imageToSave, fileName));
|
|
saveImageListenerThread.Start();
|
|
}
|
|
|
|
private void StartSaveImageListener()
|
|
{
|
|
Task<Image> saveImageTask = Task.Run(() => SaveImageListener());
|
|
var timeoutAnswerTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var completedAnswerTask = Task.WhenAny(saveImageTask, timeoutAnswerTask).Result;
|
|
if (completedAnswerTask == timeoutAnswerTask)
|
|
{
|
|
log.Error("Connection attempt timed out after 1 second.");
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
SaveImageToFile(saveImageTask.Result);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
MessageBox.Show("Error saving image: " + exc.Message);
|
|
}
|
|
}
|
|
|
|
public void StartSaveImageListener(string filePath)
|
|
{
|
|
Task<Image> saveImageTask = Task.Run(() => SaveImageListener());
|
|
var timeoutAnswerTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var completedAnswerTask = Task.WhenAny(saveImageTask, timeoutAnswerTask).Result;
|
|
if (completedAnswerTask == timeoutAnswerTask)
|
|
{
|
|
log.Error("Connection attempt timed out after 1 second.");
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
SaveImageToFile(saveImageTask.Result);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
MessageBox.Show("Error saving image: " + exc.Message);
|
|
}
|
|
}
|
|
|
|
private void EstablishCameraConnection(ref TcpClient camTcpClient, string localIP, int localPort)
|
|
{
|
|
|
|
var connectTask = camTcpClient.ConnectAsync(localIP, localPort);
|
|
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
|
|
var completedTask = Task.WhenAny(connectTask, timeoutTask).Result;
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
throw new TimeoutException("Connection attempt timed out after 1 second.");
|
|
}
|
|
}
|
|
|
|
private void EstablishCameraConnectionRepeticaly(ref TcpClient camTcpClient, string localIP, int localPort)
|
|
{
|
|
int[] timeoutIntervals = new int[] { 500, 1000 };
|
|
|
|
foreach (int interval in timeoutIntervals)
|
|
{
|
|
// Dispose previous TcpClient if needed
|
|
//camTcpClient?.Close();
|
|
//camTcpClient = new TcpClient();
|
|
|
|
try
|
|
{
|
|
// Begin connection attempt
|
|
var connectTask = camTcpClient.ConnectAsync(localIP, localPort);
|
|
var timeoutTask = Task.Delay(interval);
|
|
|
|
var completedTask = Task.WhenAny(connectTask, timeoutTask).GetAwaiter().GetResult();
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
// Timed out
|
|
continue;
|
|
}
|
|
|
|
// Check if the connect task completed successfully
|
|
connectTask.GetAwaiter().GetResult(); // Throws if failed
|
|
|
|
if (camTcpClient.Connected)
|
|
{
|
|
// Connected successfully
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Ignore and continue to next retry interval
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// If we reach here, all attempts failed
|
|
throw new TimeoutException("Connection attempt timed out after multiple retries.");
|
|
}
|
|
private void EstablishCameraConnectionX(ref TcpClient camTcpClient, string localIP, int localPort)
|
|
{
|
|
Task connectTask = null;
|
|
Task timeoutTask = null;
|
|
Task completedTask = null;
|
|
|
|
int[] timeoutIntervals = new int[] {100, 300, 500, 1000};
|
|
|
|
foreach (int interval in timeoutIntervals)
|
|
{
|
|
if (camTcpClient.Connected)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
connectTask = camTcpClient.ConnectAsync(localIP, localPort);
|
|
timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(interval));
|
|
|
|
completedTask = Task.WhenAny(connectTask, timeoutTask).Result;
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
throw new TimeoutException("Connection attempt timed out after 1 second.");
|
|
}
|
|
|
|
if (connectTask == null || connectTask.IsFaulted || connectTask.IsCanceled)
|
|
{
|
|
throw new Exception("Connection attempt failed: " + connectTask.Exception.Message);
|
|
}
|
|
|
|
if (camTcpClient.Connected == false)
|
|
{
|
|
throw new Exception("Connection attempt failed: " + camTcpClient.Client.RemoteEndPoint.ToString());
|
|
}
|
|
|
|
}
|
|
|
|
public async Task<Image> SaveImageListener()
|
|
{
|
|
Image imageToReturn = null;
|
|
using (this.cameraTcpClient = new TcpClient())
|
|
{
|
|
try
|
|
{
|
|
EstablishCameraConnection(ref this.cameraTcpClient, CameraCfg.IPAddressCJMS, iPort);
|
|
|
|
log.Debug(string.Format("Camera connected to server {0}:{1}.", CameraCfg.IPAddressCJMS, iPort));
|
|
ipAddress = IPAddress.Parse(CameraCfg.IPAddressCJMS);
|
|
|
|
using (cameraStream = this.cameraTcpClient.GetStream())
|
|
using (cameraWriter = new StreamWriter(cameraStream, Encoding.ASCII) { AutoFlush = true })
|
|
using (cameraReader = new StreamReader(cameraStream, Encoding.ASCII))
|
|
{
|
|
cameraStream.ReadTimeout = 1000;
|
|
|
|
SendCommand(CommandM.prepare_camera_);
|
|
|
|
bool inError = false;
|
|
stopSaveImageListenerFlag = false;
|
|
while (!stopSaveImageListenerFlag)
|
|
{
|
|
try
|
|
{
|
|
SendCommand(CommandM.grab_image_);
|
|
Task<string> responseAnswerTask = cameraReader.ReadLineAsync();
|
|
var timeoutAnswerTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var completedAnswerTask = Task.WhenAny(responseAnswerTask, timeoutAnswerTask).Result;
|
|
|
|
if (completedAnswerTask == timeoutAnswerTask)
|
|
{
|
|
throw new TimeoutException("Answer response attempt timed out after 1 second.");
|
|
}
|
|
|
|
string responseAnswer = responseAnswerTask.Result;
|
|
if (responseAnswer.Length > 0)
|
|
{
|
|
/// Process the packet
|
|
JmsPacket newPacket = new JmsPacket(responseAnswer);
|
|
|
|
switch (newPacket.JmsMessage.Command)
|
|
{
|
|
case CommandM.grab_image_:
|
|
if (newPacket.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
if (inError)
|
|
{
|
|
return null; // camera in error - finish thread
|
|
}
|
|
SendCommand(CommandM.prepare_camera_);
|
|
inError = true;
|
|
}
|
|
ParsedImage parsedImage = newPacket.JmsMessage.getImage();
|
|
if (parsedImage.Encoding == ImageType.BASE_64)
|
|
{
|
|
Image image = parsedImage.Image;
|
|
|
|
|
|
if (showOverlayRect && overlayRect != null && overlayThickness > 0)
|
|
{
|
|
int penWidth = 1;
|
|
Pen pen = new Pen(Color.Green, penWidth);
|
|
using (var grph = Graphics.FromImage(image))
|
|
{
|
|
if (penWidth != overlayThickness)
|
|
{
|
|
penWidth = overlayThickness;
|
|
pen = new Pen(Color.Green, penWidth);
|
|
}
|
|
|
|
grph.DrawRectangle(pen, overlayRect);
|
|
}
|
|
}
|
|
|
|
imageToReturn = image;
|
|
stopSaveImageListenerFlag =
|
|
true; // mam obrazok ukoncim a zavriem thread
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string msg = string.Format("Exception in MJpeg RTP listener thread: {0}", exc.Message);
|
|
log.Error(msg);
|
|
}
|
|
}
|
|
|
|
stopGrabImageListenerFlag = false;
|
|
SendCommand(CommandM.close_);
|
|
SendCommand(CommandM.disconnect_);
|
|
|
|
CloseCameraResources();
|
|
|
|
return imageToReturn;
|
|
|
|
}
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error($"Save Image exception: {exc.Message}");
|
|
}
|
|
}
|
|
return imageToReturn;
|
|
}
|
|
|
|
|
|
void StopUiThreads()
|
|
{
|
|
stopLiveStreamListenerFlag = true;
|
|
stopGrabImageListenerFlag = true;
|
|
stopUIListenerFlag = true;
|
|
log.Debug("Handle CameraUICmd StopUIListener");
|
|
var taskStopUi = Task.Run(StopUiListener);
|
|
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
|
|
|
|
var completedTask = Task.WhenAny(taskStopUi, timeoutTask).Result;
|
|
|
|
if (completedTask == timeoutTask)
|
|
{
|
|
stopUIListenerFlag = true;
|
|
throw new TimeoutException("Connection attempt timed out after 5 second.");
|
|
}
|
|
CloseCameraResources();
|
|
}
|
|
|
|
void StopUiListener()
|
|
{
|
|
stopUIListenerFlag = false;
|
|
while (!stopUIListenerFlag)
|
|
{
|
|
stopLiveStreamListenerFlag = true;
|
|
stopGrabImageListenerFlag = true;
|
|
|
|
if ((liveStreamListenerThread != null && liveStreamListenerThread.IsAlive) ||
|
|
(grabImageListenerThread != null && grabImageListenerThread.IsAlive))
|
|
{
|
|
Thread.Sleep(100);
|
|
}
|
|
else
|
|
{
|
|
stopUIListenerFlag = true;
|
|
}
|
|
}
|
|
//stopLiveStreamListenerFlag = false;
|
|
//stopGrabImageListenerFlag = false;
|
|
}
|
|
|
|
public void StartGrabImageListener()
|
|
{
|
|
grabImageListenerThread = new Thread(GrabImageListener);
|
|
grabImageListenerThread.Start();
|
|
}
|
|
|
|
void GrabImageListener()
|
|
{
|
|
using (this.cameraTcpClient = new TcpClient())
|
|
{
|
|
try
|
|
{
|
|
EstablishCameraConnection(ref this.cameraTcpClient, CameraCfg.IPAddressCJMS, iPort);
|
|
|
|
log.Info(string.Format("Camera connected to server {0}:{1}.", CameraCfg.IPAddressCJMS, iPort));
|
|
ipAddress = IPAddress.Parse(CameraCfg.IPAddressCJMS);
|
|
// Get network stream
|
|
|
|
|
|
using (cameraStream = this.cameraTcpClient.GetStream())
|
|
using (cameraWriter = new StreamWriter(cameraStream, Encoding.ASCII) { AutoFlush = true })
|
|
using (cameraReader = new StreamReader(cameraStream, Encoding.ASCII))
|
|
{
|
|
cameraStream.ReadTimeout = 1000;
|
|
|
|
try
|
|
{
|
|
SendCommand(CommandM.prepare_camera_);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.Error($"Initialisation of connection readers failed: {exc.Message}");
|
|
return;
|
|
}
|
|
|
|
stopGrabImageListenerFlag = false;
|
|
int iCountOf_NACK = 0;
|
|
|
|
SendCommand(CommandM.grab_image_);
|
|
|
|
while (!stopGrabImageListenerFlag)
|
|
{
|
|
try
|
|
{
|
|
|
|
Task<string> responseAnswerTask = cameraReader.ReadLineAsync();
|
|
var timeoutAnswerTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var completedAnswerTask = Task.WhenAny(responseAnswerTask, timeoutAnswerTask).Result;
|
|
|
|
if (completedAnswerTask == timeoutAnswerTask)
|
|
{
|
|
throw new TimeoutException("Answer response attempt timed out after 1 second.");
|
|
}
|
|
|
|
string responseAnswer = responseAnswerTask.Result;
|
|
if (responseAnswer.Length > 0)
|
|
{
|
|
/// Process the packet
|
|
JmsPacket newPacket = new JmsPacket(responseAnswer);
|
|
|
|
if (newPacket.JmsMessage.Status != MessageStatus.ACK)
|
|
{
|
|
if (iCountOf_NACK < 5)
|
|
{
|
|
iCountOf_NACK++;
|
|
continue;
|
|
}
|
|
|
|
log.ErrorFormat("Error occured more as 5 time in GrabImageListener: {0}",
|
|
newPacket.JmsMessage.Status);
|
|
stopGrabImageListenerFlag = true; // mam obrazok ukoncim a zavriem thread
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
switch (newPacket.JmsMessage.Command)
|
|
{
|
|
case CommandM.grab_image_:
|
|
ParsedImage parsedImage = newPacket.JmsMessage.getImage();
|
|
if (parsedImage.Encoding == ImageType.BASE_64)
|
|
{
|
|
Image image = parsedImage.Image;
|
|
|
|
|
|
if (showOverlayRect && overlayRect != null && overlayThickness > 0)
|
|
{
|
|
int penWidth = 1;
|
|
Pen pen = new Pen(Color.Green, penWidth);
|
|
using (var grph = Graphics.FromImage(image))
|
|
{
|
|
if (penWidth != overlayThickness)
|
|
{
|
|
penWidth = overlayThickness;
|
|
pen = new Pen(Color.Green, penWidth);
|
|
}
|
|
|
|
grph.DrawRectangle(pen, overlayRect);
|
|
}
|
|
}
|
|
|
|
OnImageReceived(this, this.cameraIdx, image, RoiConfiguration.ImageRotation);
|
|
stopGrabImageListenerFlag =
|
|
true; // mam obrazok ukoncim a zavriem thread
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
log.Error($"Grab Image - Hardware Addr: {CameraCfg.HardwareAddress} Camera IP: {CameraCfg.IPAddressCJMS}, Port: {iPort} Exception in MJpeg RTP listener thread: { exc.Message}");
|
|
}
|
|
}
|
|
|
|
stopGrabImageListenerFlag = false;
|
|
SendCommandAndWaitToAnswer(cameraWriter, cameraReader, CommandM.close_);
|
|
SendCommandAndWaitToAnswer(cameraWriter, cameraReader, CommandM.disconnect_);
|
|
|
|
CloseCameraResources();
|
|
|
|
return;
|
|
}
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error($"Grab Image - Hardware Addr: {CameraCfg.HardwareAddress} Camera IP: {CameraCfg.IPAddressCJMS}, Port: {iPort} exception: {exc.Message}");
|
|
UiBridge.Bridge.OnImage(this.cameraIdx, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CloseCameraResources()
|
|
{
|
|
cameraReader?.Close();
|
|
cameraReader = null;
|
|
cameraWriter?.Close();
|
|
cameraWriter = null;
|
|
cameraStream?.Close();
|
|
cameraStream = null;
|
|
cameraTcpClient?.Close();
|
|
cameraTcpClient?.Dispose();
|
|
cameraTcpClient = null;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// listener for multiple - repetetive image receiving
|
|
/// </summary>
|
|
/// <detail>
|
|
/// method uses reader to receive data from camera
|
|
/// </detail>
|
|
/// <param name="localIP"></param>
|
|
/// <param name="localPort"></param>
|
|
|
|
private void StartLiveStreamListener(IPAddress localIP, int localPort)
|
|
{
|
|
liveStreamListenerThread = new Thread(new ThreadStart(LiveStreamListener));
|
|
liveStreamListenerThread.Start();
|
|
}
|
|
|
|
void LiveStreamListener()
|
|
{
|
|
bool synced = false;
|
|
|
|
using (this.cameraTcpClient = new TcpClient())
|
|
{
|
|
try
|
|
{
|
|
EstablishCameraConnection(ref this.cameraTcpClient, CameraCfg.IPAddressCJMS, iPort);
|
|
|
|
log.Debug(string.Format("Camera connected to server {0}:{1}.", CameraCfg.IPAddressCJMS, iPort));
|
|
ipAddress = IPAddress.Parse(CameraCfg.IPAddressCJMS);
|
|
// Get network stream
|
|
|
|
|
|
using (cameraStream = this.cameraTcpClient.GetStream())
|
|
using (cameraWriter = new StreamWriter(cameraStream, Encoding.ASCII) { AutoFlush = true })
|
|
using (cameraReader = new StreamReader(cameraStream, Encoding.ASCII))
|
|
{
|
|
cameraStream.ReadTimeout = 1000;
|
|
|
|
SendCommand(CommandM.prepare_camera_);
|
|
SendCommand(CommandM.start_stream_images_);
|
|
|
|
|
|
stopLiveStreamListenerFlag = false;
|
|
while (!stopLiveStreamListenerFlag)
|
|
{
|
|
try
|
|
{
|
|
|
|
//SendCommand(CommandM.grab_image_);
|
|
Task<string> responseAnswerTask = cameraReader.ReadLineAsync();
|
|
var timeoutAnswerTask = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var completedAnswerTask = Task.WhenAny(responseAnswerTask, timeoutAnswerTask).Result;
|
|
|
|
if (completedAnswerTask == timeoutAnswerTask)
|
|
{
|
|
throw new TimeoutException("Answer response attempt timed out after 1 second.");
|
|
}
|
|
|
|
string responseAnswer = responseAnswerTask.Result;
|
|
|
|
if (responseAnswer.Length > 0)
|
|
{
|
|
/// Process the packet
|
|
JmsPacket newPacket = new JmsPacket(responseAnswer);
|
|
// if (synced)
|
|
// {
|
|
/// Sychronized: process the new packet
|
|
switch (newPacket.JmsMessage.Command)
|
|
{
|
|
case CommandM.grab_image_:
|
|
ParsedImage parsedImage = newPacket.JmsMessage.getImage();
|
|
if (parsedImage.Encoding == ImageType.BASE_64)
|
|
{
|
|
Image image = parsedImage.Image;
|
|
|
|
|
|
if (showOverlayRect && overlayRect != null && overlayThickness > 0)
|
|
{
|
|
int penWidth = 1;
|
|
Pen pen = new Pen(Color.Green, penWidth);
|
|
using (var grph = Graphics.FromImage(image))
|
|
{
|
|
if (penWidth != overlayThickness)
|
|
{
|
|
penWidth = overlayThickness;
|
|
pen = new Pen(Color.Green, penWidth);
|
|
}
|
|
|
|
grph.DrawRectangle(pen, overlayRect);
|
|
}
|
|
}
|
|
|
|
OnImageReceived(this, this.cameraIdx, image, RoiConfiguration.ImageRotation);
|
|
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
string msg = string.Format("Exception in MJpeg RTP listener thread: {0}", exc.Message);
|
|
log.Error(msg);
|
|
}
|
|
}
|
|
|
|
stopLiveStreamListenerFlag = false;
|
|
//we need to wait to answer, it works on thread loop - properly access
|
|
var sendCommandAndWaitToAnswer = SendCommandAndWaitToAnswer(cameraWriter, cameraReader, CommandM.prepare_camera_);
|
|
if (sendCommandAndWaitToAnswer == null || sendCommandAndWaitToAnswer.JmsMessage.Status == MessageStatus.NACK) //correct if NACK & OPENED
|
|
{
|
|
log.Error("Stop streaming not successfully! see: " + sendCommandAndWaitToAnswer.JmsMessage.Payload);
|
|
}
|
|
|
|
//SendCommand(CommandM.close_);
|
|
//SendCommand(CommandM.disconnect_);
|
|
|
|
CloseCameraResources();
|
|
}
|
|
}catch(Exception exc)
|
|
{
|
|
log.Error($"Live Stream exception: {exc.Message}");
|
|
UiBridge.Bridge.OnImage(this.cameraIdx, null);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//public void OnMeasurementDataReceived(object sender, MeasuredDataEventArgs msrmtData)
|
|
//{
|
|
// string[] pulsesArr = msrmtData.MeasuredData.Split(new char[] { ';' });
|
|
|
|
// uint uiVal;
|
|
// if (result != null && result.Length + 1 == pulsesArr.Length && uint.TryParse(pulsesArr[0], out uiVal))
|
|
// {
|
|
// cameraTimeMs = (long)uiVal;
|
|
|
|
// for (int i = 0; i < result.Length; i++)
|
|
// {
|
|
// int val;
|
|
// if (int.TryParse(pulsesArr[i + 1], out val))
|
|
// {
|
|
// result[i] = Math.Abs(val);
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
|
|
public IOperation LiveStreamOp(bool hiRes)
|
|
{
|
|
int wid = hiRes ? 1280 : 640;
|
|
int hgh = hiRes ? 960 : 480;
|
|
|
|
//string command = string.Format("~/userland/build/bin/raspivid -t 0 -cd MJPEG -w {0} -h {1} -fps 30 -b 8000000 -o - | gst-launch-1.0 fdsrc ! \"image/jpeg,framerate=30/1\" ! jpegparse ! rtpjpegpay ! udpsink host={2} port={3}",
|
|
// wid, hgh, NetAdapter.IPAddress, rtpUdpLocalPort);
|
|
|
|
return new LiveStreamOp(this, command);
|
|
}
|
|
|
|
|
|
public IOperation GrabImagesOp(string[] imgFileNames, bool blackAndWhite, bool lowResolution, ImageRotation imageRotation)
|
|
{
|
|
return new GrabImagesOp(this, imgFileNames, blackAndWhite, lowResolution, imageRotation);
|
|
}
|
|
|
|
|
|
public IOperation MeasurementOp()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string command;
|
|
bool measurementCommandSent;
|
|
|
|
|
|
|
|
|
|
private void SendCommand(CommandM command)
|
|
{
|
|
try
|
|
{
|
|
if (cameraWriter != null && cameraReader != null && cameraStream!=null && cameraStream.CanWrite)
|
|
{
|
|
cameraWriter.WriteLineAsync(CommandMEnum.GetVal(command)).Wait();
|
|
cameraWriter.FlushAsync();
|
|
}
|
|
}catch(Exception exc)
|
|
{
|
|
log.ErrorFormat("{0} SendCommand: {1}", Name, exc.Message);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
private JmsPacket SendCommandAndWaitToAnswer(StreamWriter writer, StreamReader reader, CommandM command, string payload = null)
|
|
{
|
|
// Send command
|
|
String command_str = CommandMEnum.GetVal(command);
|
|
if (payload != null && payload.Length > 0)
|
|
{
|
|
command_str += "=" + payload;
|
|
}
|
|
|
|
command_str = command_str + " ";
|
|
writer.WriteLineAsync(command_str).Wait();
|
|
Console.WriteLine($@"Command '{command_str}' sent.");
|
|
|
|
JmsPacket result;
|
|
|
|
string responseAnswer = "";
|
|
try
|
|
{
|
|
int iReads = 0;
|
|
while (true)
|
|
{
|
|
//get config
|
|
var readLineAsync = reader.ReadLineAsync();
|
|
var timeoutTaskRead = Task.Delay(TimeSpan.FromSeconds(1));
|
|
var waitAny = Task.WhenAny(readLineAsync, timeoutTaskRead).Result;
|
|
if (waitAny == timeoutTaskRead)
|
|
{
|
|
log.Debug("Activation timeout.");
|
|
throw new TimeoutException("Activation timeout. No received response for command_CFG");
|
|
}
|
|
|
|
log.Debug(string.Format("received from camera: {0}", responseAnswer));
|
|
responseAnswer = readLineAsync.Result;
|
|
|
|
try
|
|
{
|
|
result = new JmsPacket(responseAnswer);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
iReads++;
|
|
continue;
|
|
}
|
|
|
|
if (result.JmsMessage.Command == command)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (iReads > 5)
|
|
{
|
|
log.Error($"Maximum Count of unexcepted answers excited!");
|
|
break;
|
|
}
|
|
|
|
iReads++;
|
|
}
|
|
}
|
|
catch (IOException ioEx)
|
|
{
|
|
log.Error($"Timeout or IO error while reading from camera: {ioEx.Message}");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
log.Error(string.Format("Error while reading from camera: {0}", e.Message));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
///Prepare communication with the camera
|
|
log.DebugFormat("Camera Start() - JMCameras.CameraCfg.IPAddressCJMS: {0}, CameraCfg.Port: {1}! ");
|
|
StopUiListener();
|
|
this.cameraTcpClient = new TcpClient();
|
|
lockCameraInitialisation = true;
|
|
|
|
try
|
|
{
|
|
EstablishCameraConnection(ref this.cameraTcpClient, CameraCfg.IPAddressCJMS, iPort);
|
|
}catch(Exception exc)
|
|
{
|
|
log.ErrorFormat("Camera Start() - JMCameras.CameraCfg.IPAddressCJMS: {0}, CameraCfg.Port: {1}! Exception: {2}", CameraCfg.IPAddressCJMS, iPort, exc.Message);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
public Event Run()
|
|
{
|
|
|
|
return Event.None;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
if (measurementCommandSent)
|
|
{
|
|
log.WarnFormat("{0} SEND_COMMAND: cancel", Name);
|
|
if (cameraStream.CanWrite)
|
|
{
|
|
SendCommand(CommandM.close_);
|
|
SendCommand(CommandM.disconnect_);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///
|
|
/// PromptReceviedEventHandler delegate and handler
|
|
///
|
|
public delegate void PromptCameraReceivedEventHandler(object sender, PromptReceivedJMSEventArgs e);
|
|
public static event PromptCameraReceivedEventHandler PromptCameraReceivedHandler;
|
|
|
|
/// <summary>
|
|
/// This method is called from within this class when
|
|
/// a prompt string was received from the telnet server.
|
|
/// </summary>
|
|
public static void OnPromptReceived(object sender, string response, JmsPacket package)
|
|
{
|
|
|
|
log.Info("Prompt received, response:" + Environment.NewLine + response);
|
|
|
|
if (null != PromptCameraReceivedHandler)
|
|
{
|
|
try
|
|
{
|
|
PromptCameraReceivedHandler(sender, new PromptReceivedJMSEventArgs(response, package.JmsMessage));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
log.Info("Internal error: PromptReceivedHandler exception: " + e.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
///
|
|
/// PromptReceviedEventHandler delegate and handler
|
|
///
|
|
public delegate void PromptImageReceivedEventHandler(object sender, PromptReceivedImageEventArgs e);
|
|
public static event EventHandler<PromptReceivedImageEventArgs> ImageCameraHandler;
|
|
|
|
/// <summary>
|
|
/// This method is called from within this class when
|
|
/// a prompt string was received from the telnet server.
|
|
/// </summary>
|
|
public static void OnImageReceived(object sender, int idxImage, Image image, ImageRotation imageRotation)
|
|
{
|
|
|
|
log.Info("Image received");
|
|
|
|
if (null != ImageCameraHandler)
|
|
{
|
|
try
|
|
{
|
|
//rotation
|
|
ImageUtils.Rotate(image, imageRotation);
|
|
|
|
//Send image to bridge
|
|
ImageCameraHandler(sender, new PromptReceivedImageEventArgs(idxImage, image));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
log.Info("Internal error: PromptReceivedHandler exception: " + ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
}
|