tbf/TestBenchFramework/BenchControl/Network/Camera/CLP1611/Camera.cs

660 lines
18 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 Renci.SshNet;
using Config.Entities;
using TBF.BenchControl.Network.Telnet;
using TBF.Resources;
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}, S/N={2}, IPAddress={3}, Serial={4}, Image={5}",
this.GetType().Namespace.Substring(17),
CameraCfg.Name,
CameraCfg.HardwareAddress,
ipAddress == null ? "not detected" : ipAddress.ToString(),
string.IsNullOrEmpty(cpuSerialNr) ? "not detected" : cpuSerialNr,
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 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 int CameraIdx { get { return cameraIdx; } }
int cameraIdx;
///
static int nextCameraIdx = 0;
static int GetCameraIdx() { return nextCameraIdx++; } /// Used in Initialize()
public static new void ResetStaticProperties() { nextCameraIdx = 0; }
///
/// Telnet support
///
const string TelnetPrompt = "$ ";
const bool TelnetSkipFirstLine = true;
public Telnet.TelnetClient Telnet;
private TerminalDlg terminalDlg;
///
/// scp support
///
Thread scpThread;
PasswordConnectionInfo connectionInfo;
ScpClient scpClient;
bool scpConnected;
bool stopScpThreadFlag;
string scpSrcFileName;
string scpDstFileName;
enum ScpCommand
{
None,
Get,
}
ScpCommand scpCommand;
///
/// MJpeg RTP protocol support
///
const int RtpUdpPortBase = 20000;
int rtpUdpLocalPort;
UdpClient rtpUdpClient;
Thread rtpListenerThread;
static bool stopRtpListenerFlag;
///
/// 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()
{
cameraIdx = GetCameraIdx();
if (CameraCfg.DebugLevel == DebugMode.Simulate) return;
/// Detect a camera
bool cameraDetected = DetectCamera(CameraCfg.HardwareAddress % 100, ref ipAddress, true,
out cpuHardware, out cpuRevision, out cpuSerialNr, 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();
scpThread = new Thread(new ThreadStart(ScpWorker));
scpThread.Start();
rtpUdpLocalPort = RtpUdpPortBase + 2 * cameraIdx;
StartRtpListener(NetAdapter.IPAddress, rtpUdpLocalPort);
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()
{
stopScpThreadFlag = true;
stopRtpListenerFlag = true;
if (Telnet != null)
{
Telnet.Dispose();
Telnet = null;
}
if (scpThread != null) scpThread.Join(500);
if (rtpListenerThread != null) rtpListenerThread.Join(1000);
if (rtpUdpClient != null)
{
rtpUdpClient.Close();
rtpUdpClient = null;
}
running = false;
}
public void RunDeviceBefore()
{
}
public void RunDeviceAfter()
{
// if (running)
// {
// Console.WriteLine("Time={0} IP={1} scp={2}", StateMachine.Time, IPAddress, scpConnected ? "connected" : "disconnected");
// }
}
/// <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 setDateTime, out string hardware, out string revision, out string serial, out string sdCardVer)
{
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 ScpWorker()
{
try
{
connectionInfo = new PasswordConnectionInfo(IPAddress.ToString(), ClpUserName, ClpPassword);
scpClient = new ScpClient(connectionInfo);
scpClient.Connect();
scpConnected = scpClient.IsConnected;
}
catch (Exception)
{
scpConnected = false;
}
if (scpConnected)
{
while (!stopScpThreadFlag)
{
switch (scpCommand)
{
case ScpCommand.Get:
scpCommand = ScpCommand.None;
scpClient.Download(scpSrcFileName, new System.IO.FileInfo(scpDstFileName));
break;
default:
Thread.Sleep(250);
break;
}
}
scpClient.Disconnect();
scpConnected = false;
}
}
/// <summary>
/// Transfer a file via SCP
/// </summary>
/// <param name="srcFileName"></param>
/// <returns>0 (success), -1 (busy), -2 (no session)</returns>
public int TransferFileViaScp(string srcFileName, string dstFileName)
{
if (!scpConnected) return -2;
if (scpCommand != ScpCommand.None) return -1;
scpSrcFileName = srcFileName;
scpDstFileName = dstFileName;
scpCommand = ScpCommand.Get;
return 0;
}
private void StartRtpListener(IPAddress localIP, int localPort)
{
rtpUdpClient = new UdpClient(new IPEndPoint(localIP, localPort));
rtpListenerThread = new Thread(new ThreadStart(RtpListener));
rtpListenerThread.Start();
}
void RtpListener()
{
JpegFrame jpegFrame = new JpegFrame();
bool synced = false;
while (!stopRtpListenerFlag)
{
try
{
IPEndPoint endpoint = null;
Byte[] data = rtpUdpClient.Receive(ref endpoint);
if (data.Length > 20)
{
/// Process the packet
RtpPacket newPacket = new RtpPacket(data);
if (synced)
{
/// Sychronized: process the new packet
switch (jpegFrame.AddPacket(newPacket))
{
case RtpFrame.STATE.Complete:
UiBridge.Bridge.OnImage(this.cameraIdx, jpegFrame.ToImage());
jpegFrame.Clear();
break;
case RtpFrame.STATE.Error:
jpegFrame.Clear();
synced = false;
break;
default:
break;
}
}
else if (newPacket.Mark)
{
/// Synchronize when a packet with Mark occurs, process the next packet
jpegFrame.Clear();
synced = true;
}
else
{
/// Stay unsynchronized
}
}
}
catch (Exception exc)
{
string msg = string.Format("Exception in the listener thread: {0}", exc.Message);
log.Error(msg);
}
}
return;
}
public IOperation LiveStreamOp(bool hiRes)
{
int wid = hiRes ? 1280 : 640;
int hgh = hiRes ? 960 : 480;
string command = string.Format("/opt/vc/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.ToString(), rtpUdpLocalPort);
return new LiveStreamOp(this, Telnet, command);
}
public IOperation GrabImagesOp(string[] imgFileNames, bool blackAndWhite, bool lowResolution, ImageRotation imageRotation)
{
return new GrabImagesOp(this, imgFileNames, blackAndWhite, lowResolution, imageRotation);
}
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");
}
}
}
}