575 lines
16 KiB
C#
575 lines
16 KiB
C#
///
|
|
/// 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
|
|
{
|
|
/// <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}, 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<string> 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<Generic.IComponent> 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<string>();
|
|
|
|
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<MeasuredDataEventArgs>(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");
|
|
// }
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Detect the camera with specified hardware address (DIP switches)
|
|
/// </summary>
|
|
/// <param name="hwAddress">Hardware address (DIP switches)</param>
|
|
/// <param name="setDateTime">true = Broadcast 'SetDateTime' to all cameras</param>
|
|
/// <param name="ipAddress">Detected IP address</param>
|
|
/// <param name="hardware">Detected hardware</param>
|
|
/// <param name="revision">Detected HW revision</param>
|
|
/// <param name="serial">Detected serial number</param>
|
|
/// <param name="sdCardVer">Detected OS image</param>
|
|
/// <returns>true when camera detected successfully</returns>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transfer a file via SCP
|
|
/// </summary>
|
|
/// <param name="srcFileName"></param>
|
|
/// <returns>0 (success), -1 (busy), -2 (no session)</returns>
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
}
|