/// /// Copyright (c) 2017 Sensus Metering Systems /// using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Timers; using log4net; using Config.Entities; using TBF.BenchControl.Network.Telnet; using TBF.Resources; using WinSCP; namespace TBF.BenchControl.Network.Camera.CLP1611 { /// /// 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}, HWAddress={2}, IPAddress={3}, Serial={4}, Image={5}", this.GetType().Namespace.Substring(17), CameraCfg.Name, CameraCfg.HardwareAddress, ipAddress == null ? "not detected" : ipAddress.ToString(), string.IsNullOrEmpty(serial) ? "not detected" : serial, string.IsNullOrEmpty(sdCardVer) ? "not detected" : sdCardVer); } const string ClpUserName = "tbf"; const string ClpPassword = "C1ern4V0d4"; /// /// Properties /// public readonly CameraCfg CameraCfg; public readonly GenericDevices.INetworkAdapter NetAdapter; public IPAddress IPAddress { get { return ipAddress; } } IPAddress ipAddress; public string Hardware { get { return hardware; } } string hardware; public string Revision { get { return revision; } } string revision; public string Serial { get { return serial; } } string serial; public string SDCardVer { get { return sdCardVer; } } string sdCardVer; public bool Running { get { return running; } } bool running; /// /// Telnet support /// const string TelnetPrompt = "$ "; const bool TelnetSkipFirstLine = true; public Telnet.TelnetClient Telnet; private TerminalDlg terminalDlg; /// /// WinSCP support /// Thread wscpThread; SessionOptions wscpSessionOptions; Session wscpSession; bool wscpOpened; bool closeWscpThread; string wscpSrcFileName; string wscpDstFileName; enum WscpCommand { None, Get, } WscpCommand wscpCommand; /// /// ROI related parameters /// IList roiParams; long cameraTimeMs; int[] result; /// public void ClearRoiParams() { roiParams.Clear(); } public int RegisterRoi(string rParams) { this.roiParams.Add(rParams); int newHandle = this.roiParams.Count; result = new int[newHandle]; return newHandle; } /// public int GetResult(int roiHandle, out long timeMs) { timeMs = cameraTimeMs; if (roiHandle > 0 && roiHandle <= roiParams.Count) { return result[roiHandle - 1]; } return 0; } /// /// UDP Port number for 'MeasurementOp' /// const int UdpPortRangeStart = 13800; const int UdpPortRangeEnd = 13850; static int nextUdpPortNr = UdpPortRangeStart; public static int GetNextUdpPortNr() { return nextUdpPortNr++; } /// readonly int measurementUdpPortNr; UdpClient measurementListener; public Camera() {} public Camera(Generic.IComponentCfg cfg, IList components) : base(cfg) { CameraCfg = cfg as CameraCfg; NetAdapter = TbfComponents.FindComponent(cfg.ParentName, components) as GenericDevices.INetworkAdapter; if (NetAdapter == null) throw new ArgumentNullException("no network adapter"); Telnet = null; terminalDlg = null; measurementUdpPortNr = GetNextUdpPortNr(); roiParams = new List(); running = false; log.Debug(this.ToString()); } public void Initialize() { if (CameraCfg.DebugLevel == DebugMode.Simulate) return; /// Detect a camera if (CameraCfg.UseIPAddress) ipAddress = IPAddress.Parse(CameraCfg.IPAddressStr); bool cameraDetected = DetectCamera(CameraCfg.HardwareAddress, ref ipAddress, CameraCfg.UseIPAddress, true, out hardware, out revision, out serial, out sdCardVer); if (CameraCfg.DebugLevel == DebugMode.AutoDetect) { CameraCfg.DebugLevel = cameraDetected ? DebugMode.DetectedOn : DebugMode.DetectedOff; } else if (!cameraDetected) { throw new Exception(string.Format("{0}={1}", Strings.Address, CameraCfg.HardwareAddress)); } if (cameraDetected) { /// Open telnet clint and start the log-in process Telnet = new Telnet.TelnetClient(this, CameraCfg.Name, ClpUserName, ClpPassword, TelnetPrompt, TelnetSkipFirstLine, CameraCfg.DisplayTerminal); if (CameraCfg.DisplayTerminal) { terminalDlg = new TerminalDlg(CameraCfg.Name, Telnet); terminalDlg.Show(); } Telnet.MeasurementDataReceivedHandler += delegate(object sender, MeasuredDataEventArgs msrmtData) { if (Program.MainWnd.InvokeRequired) { Program.MainWnd.Invoke(new EventHandler(OnMeasurementDataReceived), sender, msrmtData); } else { OnMeasurementDataReceived(sender, msrmtData); } }; Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.CONNECT, ipAddress.ToString(), 10, 30)); //measurementListener = new UdpClient(measurementUdpPortNr); //new Thread(new ThreadStart(MeasurementUdpListener)).Start(); wscpThread = new Thread(new ThreadStart(WscpWorker)); wscpThread.Start(); running = true; log.FatalFormat("'{0}' with address {1} detected, IP address = {2}", Name, CameraCfg.HardwareAddress, ipAddress); } else { log.FatalFormat("'{0}' with address {1} not detected", Name, CameraCfg.HardwareAddress); } } public void StopDevice() { closeWscpThread = true; if (Telnet != null) { Telnet.Dispose(); Telnet = null; } if (wscpThread != null) wscpThread.Join(500); running = false; } public void RunDeviceBefore() { } public void RunDeviceAfter() { // if (running) // { // Console.WriteLine("Time={0} IP={1} scp={2}", StateMachine.Time, IPAddress, wscpOpened ? "Opened" : "Closed"); // } } /// /// Detect the camera with specified hardware address (DIP switches) /// /// Hardware address (DIP switches) /// true = Broadcast 'SetDateTime' to all cameras /// Detected IP address /// Detected hardware /// Detected HW revision /// Detected serial number /// Detected OS image /// true when camera detected successfully bool DetectCamera(int hwAddress, ref IPAddress ipAddress, bool useIpAddress, bool setDateTime, out string hardware, out string revision, out string serial, out string sdCardVer) { if (useIpAddress) { hardware = "hw"; revision = "rev"; serial = "s/n"; sdCardVer = "img"; } for (int trials = 1; trials <= 3; trials++) { UdpClient udpClient = new UdpClient(); try { if (setDateTime) { SetDateTime(udpClient, DateTime.Now); } /// /// Send a request for camera information /// DateTime detectionStart = DateTime.Now; CameraInfoRequest(udpClient, hwAddress); /// /// Receive a response or timeout /// IAsyncResult asyncRslt = udpClient.BeginReceive(null, null); if (asyncRslt.AsyncWaitHandle.WaitOne(500)) { /// Response received within time limit IPEndPoint cameraIPEndpoint = new IPEndPoint(IPAddress.Any, 1852); byte[] inputBuffer = udpClient.EndReceive(asyncRslt, ref cameraIPEndpoint); double duration_ms = (DateTime.Now - detectionStart).TotalMilliseconds; ipAddress = cameraIPEndpoint.Address; udpClient.Close(); string response = Encoding.ASCII.GetString(inputBuffer, 0, inputBuffer.Length); string[] strArr = response.Split(new char[] { ' ', '=' }); if (strArr.Length == 10 && strArr[0] == "Address" && strArr[2] == "Hardware" && strArr[4] == "Revision" && strArr[6] == "Serial" && strArr[8] == "Image") { hardware = strArr[3]; revision = strArr[5]; serial = strArr[7]; sdCardVer = strArr[9]; } else if (strArr.Length == 8 && strArr[0] == "Address" && strArr[2] == "Hardware" && strArr[4] == "Revision" && strArr[6] == "Serial") { hardware = strArr[3]; revision = strArr[5]; serial = strArr[7]; sdCardVer = string.Empty; } else { continue; } string msg = string.Format("Camera {0} detected in {1} ms: HWAddress={2} IPAddress={3} {4}", CameraCfg.Name, duration_ms, CameraCfg.HardwareAddress, ipAddress == null ? "not detected" : ipAddress.ToString(), response); log.Info(msg); Console.WriteLine(msg); return true; /// Camera detected } } catch (Exception exc) { log.ErrorFormat("Camera {0} with HWAddress={1} not detected : {2}", CameraCfg.Name, CameraCfg.HardwareAddress, exc.Message); } udpClient.Close(); } ipAddress = null; hardware = null; revision = null; serial = null; sdCardVer = null; return false; /// No camera detected } void CameraInfoRequest(UdpClient udpClient, int hardwareAddress) { string strToSend = string.Format("getinfo {0}", hardwareAddress); byte[] dataToSend = Encoding.ASCII.GetBytes(strToSend); udpClient.Send(dataToSend, dataToSend.Length, new IPEndPoint(NetAdapter.BroadcastAddress, 1852)); } void SetDateTime(UdpClient udpClient, DateTime dateTime) { string strToSend = string.Format("setdatetime {0:yyMMddHHmmss}", dateTime); byte[] dataToSend = Encoding.ASCII.GetBytes(strToSend); udpClient.Send(dataToSend, dataToSend.Length, new IPEndPoint(NetAdapter.BroadcastAddress, 1852)); } void WscpWorker() { wscpSessionOptions = new SessionOptions(); wscpSessionOptions.HostName = IPAddress.ToString(); wscpSessionOptions.UserName = ClpUserName; wscpSessionOptions.Password = ClpPassword; wscpSessionOptions.Protocol = Protocol.Scp; wscpSessionOptions.GiveUpSecurityAndAcceptAnySshHostKey = true; wscpSession = new WinSCP.Session(); wscpSession.Open(wscpSessionOptions); TransferOptions transferOptions = new TransferOptions(); transferOptions.TransferMode = TransferMode.Binary; TransferOperationResult transferResult; wscpOpened = wscpSession.Opened; if (wscpOpened) { while (!closeWscpThread) { switch (wscpCommand) { case WscpCommand.Get: wscpCommand = WscpCommand.None; transferResult = wscpSession.GetFiles(wscpSrcFileName, wscpDstFileName, false, transferOptions); ///transferResult.Check(); break; default: break; } Thread.Sleep(250); } wscpSession.Close(); wscpOpened = false; } } /// /// Transfer a file via SCP /// /// /// 0 (success), -1 (busy), -2 (no session) public int WscpTransferFile(string srcFileName, string dstFileName) { if (!wscpOpened) return -2; if (wscpCommand != WscpCommand.None) return -1; wscpSrcFileName = srcFileName; wscpDstFileName = dstFileName; wscpCommand = WscpCommand.Get; return 0; } public IOperation LiveStreamOp(bool hiRes) { return new LiveStreamOp(this, Telnet, hiRes ? "clp/hrlivestream.sh" : "clp/livestream.sh"); } public IOperation GrabImageOp() { return null; } public IOperation MeasurementOp() { if (Telnet != null) { //new MeasurementOp(this, NetAdapter.IPAddress.ToString(), measurementUdpPortNr, roiParams); return this; } else { return null; } } string command; bool measurementCommandSent; bool connectionEstablished; public void Start() { /// Prepare the telent command StringBuilder sb = new StringBuilder(); foreach (var s in roiParams) sb.AppendFormat(" {0}", s); command = string.Format("clp/Measurement -udp {0} {1}{2}{3} 1 7 0 0 0", NetAdapter.IPAddress, measurementUdpPortNr, CameraCfg.UseTestImages ? (" -l " + CameraCfg.TestImagesCount.ToString()) : string.Empty, sb); measurementCommandSent = false; connectionEstablished = false; /// If ready send (=enqueue) the command if (Telnet.State == TelnetClient.TelnetState.Inactive) { Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_MSRMNT_CMD, command)); measurementCommandSent = true; } } public Event Run() { if (!measurementCommandSent) { /// When ready send (=enqueue) the command if (Telnet.State == TelnetClient.TelnetState.Inactive) { Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_MSRMNT_CMD, command)); measurementCommandSent = true; } } else if (!connectionEstablished) { connectionEstablished = true; } return Event.None; } public void Stop() { if (measurementCommandSent) { Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_COMMAND, TelnetClient.CtrlCCommand)); } } 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); } } } } void MeasurementUdpListener() { StringBuilder toBeProcessed = new StringBuilder(); IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, measurementUdpPortNr); try { while (true) { byte[] byteArray = measurementListener.Receive(ref ipEndPoint); toBeProcessed.Append(Encoding.ASCII.GetString(byteArray, 0, byteArray.Length)); log.DebugFormat("MeasurementUdpListener() ... toBeProcessed = {0}", toBeProcessed); while (true) { int from = toBeProcessed.ToString().IndexOf('['); if (from < 0) break; int len = toBeProcessed.ToString(from + 1, toBeProcessed.Length - from - 1).IndexOf(']'); if (len < 0) break; string[] pulsesArr = toBeProcessed.ToString(from + 1, len).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); } } } toBeProcessed.Remove(0, from + len + 2); } } } catch { log.FatalFormat("Camera : MeasurementUdpListener() thread failed"); } } } }