/// /// 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 { /// /// This class implements: (1) Camera device, (2) Measurement operation /// 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 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 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 DetectJMSCamera() { return await DetectJMSCamera(CameraCfg.IPAddressCJMS, iPort); } async Task 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().OrderBy(x => x.ItemNr).Asc.List(); List cfgs = new List(); IList components = new List(); 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 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 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 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 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 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 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; } /// /// listener for multiple - repetetive image receiving /// /// /// method uses reader to receive data from camera /// /// /// 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 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; /// /// This method is called from within this class when /// a prompt string was received from the telnet server. /// 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 ImageCameraHandler; /// /// This method is called from within this class when /// a prompt string was received from the telnet server. /// 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); } } } } }