Refactorization : BenchControl -> Rig

This commit is contained in:
Milan Hanajik
2021-03-05 16:12:24 +01:00
parent 84c8ec26b6
commit 6cf3bd6160
1461 changed files with 6330 additions and 6330 deletions
+839
View File
@@ -0,0 +1,839 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Timers;
using log4net;
using Renci.SshNet;
using Config.Entities;
using TBF.Rig.Network.Telnet;
using TBF.Resources;
namespace TBF.Rig.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}, 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));
}
string ClpUserName = string.Empty; /// Either "tbf" or "pi" after a successful detection
const string ClpPassword = "C1ern4V0d4";
private static Object fileUploadLock = new Object();
///
/// 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;
string sha1sumResponse;
bool sha1sumResponseProcessed;
///
/// scp support
///
Thread scpThread;
PasswordConnectionInfo connectionInfo;
bool scpConnected;
bool stopScpThreadFlag;
string scpRemoteFileName; /// Camera file name
string scpLocalFileName; /// Local PC file name
enum ScpCommand
{
None,
Get,
Put,
}
ScpCommand scpCommand;
const int UdpPortBase = 20000; /// Port base for all UDP protocols
///
/// MJpeg RTP protocol support
///
int rtpUdpLocalPort;
UdpClient rtpUdpClient;
Thread rtpListenerThread;
static bool stopRtpListenerFlag;
///
/// RTCP protocol (reserved)
///
int rtcpUdpLocalPort;
///
/// Measurement results protocol
///
int msrmntUdpLocalPort;
UdpClient msrmntUdpClient; /// If != null msrmntListenerThread
Thread msrmntListenerThread;
static bool stopMsrmntListenerFlag;
///
/// 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 GenericDevices.INetworkAdapter;
if (NetAdapter == null) throw new ArgumentNullException("no network adapter");
Telnet = null;
terminalDlg = null;
roisAndResults = new RoisAndResults(); /// object for measurement results, writes/reads to/from this object are locked
running = false;
}
public void Initialize()
{
cameraIdx = GetCameraIdx();
if (CameraCfg.DebugLevel == DebugMode.Simulate)
{
UiBridge.Bridge.OnCameraInfo(this.cameraIdx, string.Format("{0} s/n {1} si simulated", Name, CameraCfg.HardwareAddress));
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)
{
UiBridge.Bridge.OnCameraInfo(this.cameraIdx, string.Format("{0} ver.{1} {2} s/n {3}", Name, sdCardVer, ipAddress, CameraCfg.HardwareAddress));
ClpUserName = (sdCardVer.Length > 0 && sdCardVer[0] == '1') ? "tbf" : "pi";
rtpUdpLocalPort = UdpPortBase + 4 * cameraIdx;
rtcpUdpLocalPort = UdpPortBase + 4 * cameraIdx + 1;
msrmntUdpLocalPort = UdpPortBase + 4 * cameraIdx + 2;
StartRtpListener(NetAdapter.IPAddress, rtpUdpLocalPort);
StartMsrmntListener(NetAdapter.IPAddress, msrmntUdpLocalPort);
connectionInfo = new PasswordConnectionInfo(IPAddress.ToString(), ClpUserName, ClpPassword);
/// Open telnet clint and start the log-in process
Telnet = new Telnet.TelnetClient(this, CameraCfg.Name, ClpUserName, ClpPassword, TelnetPrompt, TelnetSkipFirstLine, CameraCfg.DisplayTerminal);
Telnet.promptReceivedHandler += delegate(object sndr, PromptReceivedEventArgs a)
{
OnPromptReceived(sndr, a);
};
if (CameraCfg.DisplayTerminal)
{
terminalDlg = new TerminalDlg(CameraCfg.Name, Telnet);
terminalDlg.Show();
}
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.CONNECT, ipAddress.ToString(), 10, 30));
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.CLEAR_RESPONSE));
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.SEND_COMMAND, "sha1sum clp/*"));
log.FatalFormat("'{0}' with address {1} detected, IP = {2}, SD = {3}", Name, CameraCfg.HardwareAddress, ipAddress, sdCardVer);
}
else
{
UiBridge.Bridge.OnCameraInfo(this.cameraIdx, string.Format("{0} s/n {1} was not detected", Name, CameraCfg.HardwareAddress));
log.FatalFormat("'{0}' with address {1} not detected", Name, CameraCfg.HardwareAddress);
}
}
public void StopDevice()
{
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
{
running = false;
stopScpThreadFlag = true;
stopRtpListenerFlag = true;
stopMsrmntListenerFlag = true;
if (Telnet != null)
{
Telnet.Dispose();
Telnet = null;
}
}
}
public void StopDevice2()
{
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
{
if (scpThread != null) scpThread.Join(50);
if (rtpListenerThread != null) rtpListenerThread.Join(50);
if (msrmntListenerThread != null) msrmntListenerThread.Join(50);
if (rtpUdpClient != null)
{
rtpUdpClient.Close();
rtpUdpClient = null;
}
if (msrmntUdpClient != null)
{
msrmntUdpClient.Close();
msrmntUdpClient = null;
}
}
}
public void RunDeviceBefore()
{
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
{
if (sha1sumResponse != null && !sha1sumResponseProcessed)
{
scpThread = new Thread(new ThreadStart(ScpWorker));
scpThread.Start();
sha1sumResponseProcessed = true;
}
}
}
public void RunDeviceAfter() { }
void OnPromptReceived(object sndr, PromptReceivedEventArgs a)
{
if (sha1sumResponse == null)
{
sha1sumResponse = a.Response;
}
}
#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;
}
}
};
}
#endregion Configuration Change Handling
/// <summary>
/// Detect the camera with specified hardware address (DIP switches).
/// Optionally set camera date and time.
/// </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.Debug(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
{
using (var scpClient = new ScpClient(connectionInfo))
{
scpClient.Connect();
DirectoryInfo dirInfo = null;
if (sdCardVer.Length > 0)
{
switch (sdCardVer[0])
{
case '1':
dirInfo = new DirectoryInfo(Path.Combine(System.Windows.Forms.Application.StartupPath, "CameraBinaryFiles"));
break;
case '2':
dirInfo = new DirectoryInfo(Path.Combine(System.Windows.Forms.Application.StartupPath, "CameraBinaryFiles2"));
break;
}
}
if (dirInfo != null)
{
///
/// Synchronize files in camera /home/tbf/clp directory with the files in "TBF/CameraBinaryFiles" project folder
///
using (var sshClient = new SshClient(connectionInfo))
{
sshClient.Connect();
SHA1 sha1calculator = SHA1.Create();
StringBuilder sha1str = new StringBuilder();
FileInfo[] fileInfos = dirInfo.GetFiles();
foreach (FileInfo fi in fileInfos)
{
lock (fileUploadLock)
{
FileStream fs = fi.Open(FileMode.Open);
fs.Position = 0;
byte[] sha1 = sha1calculator.ComputeHash(fs);
fs.Close();
sha1str.Clear();
foreach (var b in sha1) sha1str.Append(b.ToString("x2"));
if (!sha1sumResponse.Contains(string.Format("{0} clp/{1}", sha1str, fi.Name)))
{
/// Copy a file to the camera if SHA1 sum is different of the file is missing
log.InfoFormat("{0}, IP={1}, Uploading file {2}", Name, IPAddress, fi.Name);
scpClient.Upload(fi, string.Format("~/clp/{0}", fi.Name));
}
}
if (!sha1sumResponse.Contains(fi.Name))
{
/// Change file properties if it was a new file
string command = string.Format("chmod 755 ~/clp/{0}", fi.Name);
log.InfoFormat("{0}, IP={1}, Executing command '{2}'", Name, IPAddress, command);
sshClient.CreateCommand(command).Execute();
//if (fi.Name.Equals("runmeonce"))
//{
// log.InfoFormat("{0}, IP={1}, Executing command 'sudo clp/runmeonce'", Name, IPAddress);
// sshClient.CreateCommand("sudo clp/runmeonce").Execute();
//}
}
}
}
}
scpConnected = scpClient.IsConnected;
running = true;
///
/// Run SCP command loop
///
while (scpConnected && !stopScpThreadFlag)
{
switch (scpCommand)
{
case ScpCommand.Get:
scpCommand = ScpCommand.None;
scpClient.Download(scpRemoteFileName, new System.IO.FileInfo(scpLocalFileName));
break;
case ScpCommand.Put:
scpCommand = ScpCommand.None;
scpClient.Upload(new System.IO.FileInfo(scpLocalFileName), scpRemoteFileName);
break;
default:
Thread.Sleep(250);
break;
}
scpConnected = scpClient.IsConnected;
}
running = false;
scpClient.Disconnect();
scpConnected = false;
}
}
catch (Exception exc)
{
log.ErrorFormat( "Exception in {0} ScpWorker(): {1}", Name, exc.Message);
if (exc.InnerException != null)
{
log.ErrorFormat(" Inner exception: {0}", exc.InnerException.Message);
}
scpConnected = false;
}
}
/// <summary>
/// Download a file from the camera via SCP
/// </summary>
/// <param name="srcFileName"></param>
/// <returns>0 (success), -1 (busy), -2 (no session)</returns>
public int DownloadFile(string srcFileName, string dstFileName)
{
if (!scpConnected) return -2;
if (scpCommand != ScpCommand.None) return -1;
scpRemoteFileName = srcFileName;
scpLocalFileName = dstFileName;
scpCommand = ScpCommand.Get;
return 0;
}
/// <summary>
/// Upload a file to the camera via SCP
/// </summary>
/// <param name="srcFileName"></param>
/// <returns>0 (success), -1 (busy), -2 (no session)</returns>
public int UploadFile(string srcFileName, string dstFileName)
{
if (!scpConnected) return -2;
if (scpCommand != ScpCommand.None) return -1;
scpLocalFileName = srcFileName;
scpRemoteFileName = dstFileName;
scpCommand = ScpCommand.Put;
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 MJpeg RTP listener thread: {0}", exc.Message);
log.Error(msg);
}
}
return;
}
private void StartMsrmntListener(IPAddress localIP, int localPort)
{
msrmntUdpClient = new UdpClient(new IPEndPoint(localIP, localPort));
msrmntListenerThread = new Thread(new ThreadStart(MsrmntListener));
msrmntListenerThread.Start();
}
void MsrmntListener()
{
StringBuilder toBeProcessed = new StringBuilder();
int[] angles = new int[RoisAndResults.MaxRegisteredRois];
while (!stopMsrmntListenerFlag)
{
try
{
IPEndPoint endpoint = null;
Byte[] data = msrmntUdpClient.Receive(ref endpoint);
toBeProcessed.Append(Encoding.ASCII.GetString(data, 0, data.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[] { ';' });
bool fmtError = false;
long timeMs;
if ((pulsesArr.Length >= 2) &&
(pulsesArr.Length <= RoisAndResults.MaxRegisteredRois + 1) &&
long.TryParse(pulsesArr[0], out timeMs))
{
for (int i = 1; i < pulsesArr.Length; i++)
{
int val;
if (int.TryParse(pulsesArr[i], out val))
{
angles[i - 1] = Math.Abs(val); /// TODO: pozerat CW/CCW a podla toho dat +/-
}
else
{
fmtError = true;
}
}
if (!fmtError) roisAndResults.SetResults(timeMs, angles);
}
toBeProcessed.Remove(0, from + len + 2);
}
}
catch (Exception exc)
{
string msg = string.Format("Exception in the measurement listener thread: {0}", exc.Message);
log.Error(msg);
}
}
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("/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, rtpUdpLocalPort);
//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, 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)
{
return this;
}
else
{
return null;
}
}
string command;
bool measurementCommandSent;
public void Start()
{
/// Prepare the telent command
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= roisAndResults.RegisteredRoisCount; i++)
{
sb.Append(" ");
sb.Append(roisAndResults.GetRoiParams(i));
}
int logImagesArg;
switch (CameraCfg.TestImagesMode)
{
default:
case TestImagesMode.None:
case TestImagesMode.LoadImages:
logImagesArg = 0;
break;
case TestImagesMode.SaveFirstImages:
logImagesArg = CameraCfg.TestImagesCount;
break;
case TestImagesMode.SaveLastImages:
logImagesArg = -CameraCfg.TestImagesCount;
break;
}
command = string.Format("clp/Measurement -udp {0} {1}{2}{3} 1 7 0 0 {4}",
NetAdapter.IPAddress,
msrmntUdpLocalPort,
(CameraCfg.TestImagesMode == TestImagesMode.LoadImages) ? (" -l " + CameraCfg.TestImagesCount.ToString()) : string.Empty,
sb,
logImagesArg);
measurementCommandSent = false;
/// If ready send (=enqueue) the command
if (Telnet.State == TelnetClient.TelnetState.Inactive)
{
log.WarnFormat("{0} SEND_MSRMNT_CMD: {1}", Name, command);
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)
{
log.WarnFormat("{0} SEND_MSRMNT_CMD: {1}", Name, command);
Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_MSRMNT_CMD, command));
measurementCommandSent = true;
}
}
return Event.None;
}
public void Stop()
{
if (measurementCommandSent)
{
log.WarnFormat("{0} SEND_COMMAND: CTRL-Q", Name);
Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_COMMAND, TelnetClient.Q_Command));
}
}
}
}
@@ -0,0 +1,70 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Xml.Serialization;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Resources;
namespace TBF.Rig.Network.Camera.CLP1611
{
public enum TestImagesMode
{
None,
SaveFirstImages,
SaveLastImages,
LoadImages,
Count,
Invalid,
}
public class CameraCfg : ComponentCfgBase, IChildComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(CameraCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl(IList<Config.Entities.Component> cmpntEntities) { return new CameraCfgCtrl(); }
///
/// Serialized parameters
///
public int HardwareAddress;
public bool DisplayTerminal;
[XmlIgnore]
public TestImagesMode TestImagesMode;
[XmlIgnore]
public int TestImagesCount;
/// Private parameterless constructor invoked by all other (public) constructors
CameraCfg() { }
public CameraCfg(string name, IComponentFactory factory)
: this()
{
Name = name;
Factory = factory;
ParentName = "Network.Adapter";
HardwareAddress = 1;
TestImagesMode = TestImagesMode.None;
TestImagesCount = 3000;
DebugLevel = Config.Entities.DebugMode.AutoDetect;
}
public string ToString(int i)
{
return string.Format("Name={0}, s/n={1}, Terminal={2}, TestImagesMode={3}, TestImagesCount={4}, Parent={5}",
Name,
HardwareAddress,
DisplayTerminal ? Strings.yes : Strings.no,
TestImagesMode,
TestImagesCount,
ParentName);
}
}
}
@@ -0,0 +1,181 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.Rig.Generic;
using TBF.Resources;
using TBF.UI.Bench.Components;
namespace TBF.Rig.Network.Camera.CLP1611
{
public partial class CameraCfgCtrl : UserControl, IComponentCfgCtrl
{
ComponentParametersDlg parent;
public bool ShowMore { get { return false; } }
CameraCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as CameraCfg;
Redraw();
}
}
public CameraCfgCtrl()
{
InitializeComponent();
}
private void PumpCfgCtrl_Load(object sender, EventArgs e)
{
Localize();
parent = ParentForm as ComponentParametersDlg;
if (parent == null) return;
if (parent.CmpntEntities != null)
{
foreach (var cmpnt in parent.CmpntEntities)
{
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is TBF.Rig.Network.Adapter.Factory)
{
parentNameComboBox.Items.Add(cmpnt.Name);
}
}
}
for (TestImagesMode mode = 0; mode < TestImagesMode.Count; mode++)
{
testImagesModeComboBox.Items.Add(mode.ToString());
}
Redraw();
}
void Localize()
{
nameLabel.Text = Strings.Name;
parentNameLabel.Text = Strings.Parent_name;
hwAddressLabel.Text = Strings.Serial_Number;
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
parentNameComboBox.Text = string.IsNullOrEmpty(config.ParentName) ? "---" : config.ParentName;
hwAddressTextBox.Text = config.HardwareAddress.ToString();
displayTerminalCheckBox.Checked = config.DisplayTerminal;
testImagesModeComboBox.Text = config.TestImagesMode.ToString();
testImagesCountTextBox.Text = config.TestImagesCount.ToString();
}
public void Unlock()
{
nameTextBox.Enabled = true;
parentNameComboBox.Enabled = true;
hwAddressTextBox.Enabled = true;
displayTerminalCheckBox.Enabled = true;
testImagesModeComboBox.Enabled = true;
testImagesCountTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
int dummy;
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, parentNameLabel.Text);
}
if (!int.TryParse(hwAddressTextBox.Text, out dummy) || dummy % 100 > 63)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, hwAddressLabel.Text);
}
TestImagesMode newTestImagesMode = TestImagesMode.Invalid;
for (TestImagesMode mode = 0; mode < TestImagesMode.Count; mode++)
{
if (testImagesModeComboBox.Text == mode.ToString()) newTestImagesMode = mode;
}
if (newTestImagesMode == TestImagesMode.Invalid)
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, testImagesModeLabel.Text);
}
if (!int.TryParse(testImagesCountTextBox.Text, out dummy) || dummy < 0 || dummy > 3000
|| ((dummy == 0) && (newTestImagesMode != TestImagesMode.None)))
{
flags |= CfgUpdateFlags.Error;
message += Environment.NewLine + string.Format(Strings.Invalid_0, testImagesCountLabel.Text);
}
return flags;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
string newParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
int newHWAddress = int.Parse(hwAddressTextBox.Text);
TestImagesMode newTestImagesMode = 0;
for (TestImagesMode mode = 0; mode < TestImagesMode.Count; mode++)
{
if (testImagesModeComboBox.Text == mode.ToString()) newTestImagesMode = mode;
}
int newTestImagesCount = int.Parse(testImagesCountTextBox.Text);
if (config.Name != nameTextBox.Text ||
config.ParentName != newParentName ||
config.HardwareAddress != newHWAddress ||
config.DisplayTerminal != displayTerminalCheckBox.Checked)
{
config.Name = nameTextBox.Text;
config.ParentName = newParentName;
config.HardwareAddress = newHWAddress;
config.DisplayTerminal = displayTerminalCheckBox.Checked;
flags |= (CfgUpdateFlags.RestartRqrd | CfgUpdateFlags.AnyChange);
}
if (config.TestImagesMode != newTestImagesMode ||
config.TestImagesCount != newTestImagesCount)
{
config.TestImagesMode = newTestImagesMode;
config.TestImagesCount = newTestImagesCount;
flags |= (CfgUpdateFlags.InvokeCfgChange | CfgUpdateFlags.VolatileChange);
}
if ((flags & CfgUpdateFlags.InvokeCfgChange) != 0)
{
Camera.OnCfgChange(this, new CfgChangeArgs(CfgChangeCmd.CfgChange, config));
}
return flags;
}
}
}
+194
View File
@@ -0,0 +1,194 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
namespace TBF.Rig.Network.Camera.CLP1611
{
partial class CameraCfgCtrl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.hwAddressTextBox = new System.Windows.Forms.TextBox();
this.hwAddressLabel = new System.Windows.Forms.Label();
this.parentNameLabel = new System.Windows.Forms.Label();
this.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.parentNameComboBox = new System.Windows.Forms.ComboBox();
this.displayTerminalCheckBox = new System.Windows.Forms.CheckBox();
this.testImagesCountTextBox = new System.Windows.Forms.TextBox();
this.testImagesCountLabel = new System.Windows.Forms.Label();
this.testImagesModeComboBox = new System.Windows.Forms.ComboBox();
this.testImagesModeLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// hwAddressTextBox
//
this.hwAddressTextBox.Enabled = false;
this.hwAddressTextBox.Location = new System.Drawing.Point(132, 92);
this.hwAddressTextBox.Name = "hwAddressTextBox";
this.hwAddressTextBox.Size = new System.Drawing.Size(130, 20);
this.hwAddressTextBox.TabIndex = 6;
//
// hwAddressLabel
//
this.hwAddressLabel.AutoSize = true;
this.hwAddressLabel.Location = new System.Drawing.Point(28, 95);
this.hwAddressLabel.Name = "hwAddressLabel";
this.hwAddressLabel.Size = new System.Drawing.Size(71, 13);
this.hwAddressLabel.TabIndex = 5;
this.hwAddressLabel.Text = "Serial number";
//
// parentNameLabel
//
this.parentNameLabel.AutoSize = true;
this.parentNameLabel.Location = new System.Drawing.Point(28, 69);
this.parentNameLabel.Name = "parentNameLabel";
this.parentNameLabel.Size = new System.Drawing.Size(67, 13);
this.parentNameLabel.TabIndex = 3;
this.parentNameLabel.Text = "Parent name";
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(132, 41);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(130, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(28, 44);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(129, 17);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// parentNameComboBox
//
this.parentNameComboBox.Enabled = false;
this.parentNameComboBox.FormattingEnabled = true;
this.parentNameComboBox.Location = new System.Drawing.Point(132, 66);
this.parentNameComboBox.Name = "parentNameComboBox";
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
this.parentNameComboBox.TabIndex = 4;
//
// displayTerminalCheckBox
//
this.displayTerminalCheckBox.AutoSize = true;
this.displayTerminalCheckBox.Enabled = false;
this.displayTerminalCheckBox.Location = new System.Drawing.Point(133, 122);
this.displayTerminalCheckBox.Name = "displayTerminalCheckBox";
this.displayTerminalCheckBox.Size = new System.Drawing.Size(99, 17);
this.displayTerminalCheckBox.TabIndex = 7;
this.displayTerminalCheckBox.Text = "Display terminal";
this.displayTerminalCheckBox.UseVisualStyleBackColor = true;
//
// testImagesCountTextBox
//
this.testImagesCountTextBox.Enabled = false;
this.testImagesCountTextBox.Location = new System.Drawing.Point(132, 174);
this.testImagesCountTextBox.Name = "testImagesCountTextBox";
this.testImagesCountTextBox.Size = new System.Drawing.Size(46, 20);
this.testImagesCountTextBox.TabIndex = 12;
//
// testImagesCountLabel
//
this.testImagesCountLabel.AutoSize = true;
this.testImagesCountLabel.Location = new System.Drawing.Point(28, 177);
this.testImagesCountLabel.Name = "testImagesCountLabel";
this.testImagesCountLabel.Size = new System.Drawing.Size(94, 13);
this.testImagesCountLabel.TabIndex = 11;
this.testImagesCountLabel.Text = "Test images count";
//
// testImagesModeComboBox
//
this.testImagesModeComboBox.Enabled = false;
this.testImagesModeComboBox.FormattingEnabled = true;
this.testImagesModeComboBox.Location = new System.Drawing.Point(132, 148);
this.testImagesModeComboBox.Name = "testImagesModeComboBox";
this.testImagesModeComboBox.Size = new System.Drawing.Size(130, 21);
this.testImagesModeComboBox.TabIndex = 14;
//
// testImagesModeLabel
//
this.testImagesModeLabel.AutoSize = true;
this.testImagesModeLabel.Location = new System.Drawing.Point(28, 151);
this.testImagesModeLabel.Name = "testImagesModeLabel";
this.testImagesModeLabel.Size = new System.Drawing.Size(93, 13);
this.testImagesModeLabel.TabIndex = 13;
this.testImagesModeLabel.Text = "Test images mode";
//
// CameraCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.testImagesModeComboBox);
this.Controls.Add(this.testImagesModeLabel);
this.Controls.Add(this.hwAddressTextBox);
this.Controls.Add(this.hwAddressLabel);
this.Controls.Add(this.testImagesCountTextBox);
this.Controls.Add(this.testImagesCountLabel);
this.Controls.Add(this.displayTerminalCheckBox);
this.Controls.Add(this.parentNameComboBox);
this.Controls.Add(this.parentNameLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "CameraCfgCtrl";
this.Size = new System.Drawing.Size(402, 254);
this.Load += new System.EventHandler(this.PumpCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox hwAddressTextBox;
private System.Windows.Forms.Label hwAddressLabel;
private System.Windows.Forms.Label parentNameLabel;
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.ComboBox parentNameComboBox;
private System.Windows.Forms.CheckBox displayTerminalCheckBox;
private System.Windows.Forms.TextBox testImagesCountTextBox;
private System.Windows.Forms.Label testImagesCountLabel;
private System.Windows.Forms.ComboBox testImagesModeComboBox;
private System.Windows.Forms.Label testImagesModeLabel;
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+27
View File
@@ -0,0 +1,27 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System.Collections.Generic;
using TBF.Rig.Generic;
namespace TBF.Rig.Network.Camera.CLP1611
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(8); } }
public override string ToString() { return ClassName; }
public void ResetStaticProperties() { Camera.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Camera(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Camera(cfg, components); }
public IComponentCfg DefaultConfig() { return new CameraCfg(this.GetType().Namespace.Substring(8), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(CameraCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,223 @@
///
/// Copyright (c) 2017 Sensus Slovensko a.s.
///
using System;
using System.Diagnostics;
using log4net;
using Config.Entities;
using TBF.Rig.Network.Telnet;
using System.IO;
namespace TBF.Rig.Network.Camera.CLP1611
{
public class GrabImagesOp : IOperation
{
/// TODO: Implement support for grabbing multiple images, now imgFileNames.Lenght should be 1
private static readonly ILog log = LogManager.GetLogger(typeof(GrabImagesOp));
public override string ToString() { return string.Format("GrabImageOp()"); }
readonly Camera camera;
readonly Telnet.TelnetClient telnet;
readonly string[] imgFileNames;
readonly bool blackAndWhite;
readonly bool lowResolution;
readonly ImageRotation imageRotation;
string command;
bool grabImageCommandSent;
string response;
bool grabPassed;
bool grabFailed;
bool transferringGrabbedImage;
/// <summary>
/// Events: Event.None or Event.Error
/// </summary>
/// <param name="camera">CLP1611.Camera reference</param>
public GrabImagesOp(Camera camera, string[] imgFileNames, bool blackAndWhite, bool lowResolution, ImageRotation imageRotation)
{
/// TODO: Implement support for grabbing multiple images, now imgFileNames.Lenght should be 1
this.camera = camera;
this.telnet = camera.Telnet;
this.imgFileNames = imgFileNames;
this.blackAndWhite = blackAndWhite;
this.lowResolution = lowResolution;
this.imageRotation = imageRotation;
grabImageCommandSent = false;
transferringGrabbedImage = false;
if (camera.DebugLevel == DebugMode.Normal || camera.DebugLevel == DebugMode.DetectedOn)
{
telnet.promptReceivedHandler += delegate(object sndr, PromptReceivedEventArgs a)
{
OnPromptReceived(sndr, a);
};
}
}
void OnPromptReceived(object sndr, PromptReceivedEventArgs a)
{
response = a.Response;
/// TODO
}
public void Start()
{
grabImageCommandSent = false;
transferringGrabbedImage = false;
if ((imgFileNames != null) && (imgFileNames.Length > 0) && File.Exists(imgFileNames[0]))
{
///
/// An image specified, (1) delete previous image, (2) check if this is a simulation
///
File.Delete(imgFileNames[0]);
if (camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.Simulate || camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.DetectedOff)
{
///
/// Camera is in simulation mode => create a simulated image
///
File.Copy(string.Format("{0}\\Pictures\\sample.jpg", Program.ExecutableDir), imgFileNames[0]);
}
}
}
public Event Run()
{
if ((imgFileNames == null) || (imgFileNames.Length < 1) || (imgFileNames[0] == null))
{
///
/// No images to be grabbed => Done
///
return Event.GrabPassed;
}
else if (camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.Simulate ||
camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.DetectedOff)
{
///
/// Camera is in simulation mode => create a simulated image and complete
///
return Event.GrabPassed;
}
else if (!grabImageCommandSent)
{
///
/// Normal operation, no command sent yet => (1) wait until telnet state = Inactive, (2) send a command
///
if (camera.Running && (telnet.State == TelnetClient.TelnetState.Inactive))
{
///
/// State variables
///
response = null;
///
/// Prepare a command
///
int rotation = 0;
if (imageRotation == ImageRotation.Deg90)
rotation = 90;
else if (imageRotation == ImageRotation.Deg180)
rotation = 180;
else if (imageRotation == ImageRotation.Deg270)
rotation = 270;
command = string.Format("clp/GrabImage {0} {1} -r {2} {3} -n 1 {4}",
blackAndWhite ? "-bmp" : "-bmp", /// 0 ... file format and quality
blackAndWhite ? "-y8" : "-rgb", /// 1 ... B&W / color
rotation.ToString(), /// 2 ... roration
lowResolution ? "-lr" : "-hr", /// 4 ... resolution
"grabbed.bmp"); /// 5 ... filename
//
// Send (or enqueue) command
//
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.CLEAR_RESPONSE));
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_COMMAND, command));
grabImageCommandSent = true;
log.WarnFormat("{0} IP={1} command={2}", camera.Name, camera.IPAddress, command);
}
return Event.CameraBusy;
}
else if (grabPassed)
{
///
/// Normal operation, grab passed => transfer/transferring the image
///
if (transferringGrabbedImage)
{
/// Grab passed and image transfer is in progress
return Event.GrabPassed;
}
else if (0 == camera.DownloadFile(blackAndWhite ? "grabbed.jpg" : "grabbed.bmp", imgFileNames[0]))
{
/// File transfer successfully started
transferringGrabbedImage = true;
return Event.GrabPassed;
}
else
{
/// Wait until the previous image transfer completes
return Event.CameraBusy;
}
}
else if (grabFailed)
{
///
/// Normal operation, grab failed => there in no image to transfer
///
return Event.GrabFailed;
}
else if (response != null)
{
///
/// Normal operation
///
if (response.Contains("completed"))
{
grabPassed = true;
///
/// Start the file transfer
///
if (0 == camera.DownloadFile(blackAndWhite ? "grabbed.jpg" : "grabbed.bmp", imgFileNames[0]))
{
/// File transfer successfully started
transferringGrabbedImage = true;
return Event.GrabPassed;
}
else
{
return Event.CameraBusy; /// File transfer not started yet
}
}
else
{
grabFailed = true;
return Event.GrabFailed;
}
}
else
{
return Event.CameraBusy;
}
}
public void Stop()
{
if (camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return;
if (grabImageCommandSent)
{
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_COMMAND, Telnet.TelnetClient.CtrlCCommand));
log.WarnFormat("{0} IP={1} command=CTRL-C", camera.Name, camera.IPAddress);
}
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Diagnostics;
using log4net;
using TBF.Rig.Network.Telnet;
namespace TBF.Rig.Network.Camera.CLP1611
{
public class LiveStreamOp : IOperation
{
private static readonly ILog log = LogManager.GetLogger(typeof(LiveStreamOp));
readonly Camera camera;
readonly Telnet.TelnetClient telnet;
readonly string command;
bool liveStreamCommandSent;
/// <summary>
/// Events: Event.None or Event.Error
/// </summary>
/// <param name="camera">CLP1611.Camera reference</param>
public LiveStreamOp(Camera camera, Telnet.TelnetClient telnet, string command)
{
this.camera = camera;
this.telnet = telnet;
this.command = command;
}
public void Start()
{
liveStreamCommandSent = false;
}
public Event Run()
{
if (camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return Event.None;
log.DebugFormat("Run(): telnet.State = {0}, liveStreamCommandSent = {1}", telnet.State, liveStreamCommandSent);
if (!liveStreamCommandSent)
{
if (camera.Running && (telnet.State == TelnetClient.TelnetState.Inactive))
{
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_STRING, command));
liveStreamCommandSent = true;
log.WarnFormat("{0} IP={1} command={2}", camera.Name, camera.IPAddress, command);
}
}
return Event.None;
}
public void Stop()
{
if (camera.CameraCfg.DebugLevel == Config.Entities.DebugMode.Simulate) return;
log.DebugFormat("Stop(): telnet.State = {0}, liveStreamCommandSent = {1}", telnet.State, liveStreamCommandSent);
if (liveStreamCommandSent)
{
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_COMMAND, Telnet.TelnetClient.CtrlCCommand));
log.WarnFormat("{0} IP={1} command=CTRL-C", camera.Name, camera.IPAddress);
}
}
}
}
@@ -0,0 +1,382 @@
using System;
using System.Collections.Generic;
using log4net;
namespace TBF.Rig.Network.Camera
{
/// <summary>
/// Implements RFC2435
/// </summary>
public class JpegFrame : RtpFrame
{
static readonly ILog log = LogManager.GetLogger(typeof(TBF.UI.MainWnd));
#region Statics
static byte[] CreateStartOfInformation()
{
return new byte[] { 0xff, 0xd8 };
}
static byte[] CreateJFIFHeader(uint type, uint width, uint height, ArraySegment<byte> tables, uint dri)
{
List<byte> result = new List<byte>();
result.AddRange(CreateStartOfInformation());
result.Add(0xff);
result.Add(0xe0);//AppFirst
result.Add(0x00);
result.Add(0x10);//length
result.Add((byte)'J');
result.Add((byte)'F');
result.Add((byte)'I');
result.Add((byte)'F');
result.Add(0x00);
result.Add(0x01);//Version Major
result.Add(0x01);//Version Minor
result.Add(0x00);//Units
result.Add(0x00);//Horizontal
result.Add(0x01);
result.Add(0x00);//Vertical
result.Add(0x01);
result.Add(0x00);//No thumb
result.Add(0x00);
if (dri > 0)
{
result.AddRange(CreateDataRestartIntervalMarker(dri));
}
result.AddRange(CreateQuantizationTablesMarker(tables));
result.Add(0xff);
result.Add(0xc0);//SOF
result.Add(0x00);
result.Add(0x11);
result.Add(0x08);
result.Add((byte)(height >> 8));
result.Add((byte)height);
result.Add((byte)(width >> 8));
result.Add((byte)width);
result.Add(0x03);
result.Add(0x01);
result.Add((byte)(type > 0 ? 0x22 : 0x21));
result.Add(0x00);
result.Add(0x02);
result.Add(0x11);
result.Add(0x01);
result.Add(0x03);
result.Add(0x11);
result.Add(0x01);
//Huffman Tables
result.AddRange(CreateHuffmanTableMarker(lum_dc_codelens, lum_dc_symbols, 0, 0));
result.AddRange(CreateHuffmanTableMarker(lum_ac_codelens, lum_ac_symbols, 0, 1));
result.AddRange(CreateHuffmanTableMarker(chm_dc_codelens, chm_dc_symbols, 1, 0));
result.AddRange(CreateHuffmanTableMarker(chm_ac_codelens, chm_ac_symbols, 1, 1));
result.Add(0xff);
result.Add(0xda);//Marker SOS
result.Add(0x00);
result.Add(0x0c);
result.Add(0x03);
result.Add(0x01);
result.Add(0x00);
result.Add(0x02);
result.Add(0x11);
result.Add(0x03);
result.Add(0x11);
result.Add(0x00);
result.Add(0x3f);
result.Add(0x00);
return result.ToArray();
}
// The default 'luma' and 'chroma' quantizer tables, in zigzag order:
static byte[] defaultQuantizers = new byte[]
{
// luma table:
16, 11, 12, 14, 12, 10, 16, 14,
13, 14, 18, 17, 16, 19, 24, 40,
26, 24, 22, 22, 24, 49, 35, 37,
29, 40, 58, 51, 61, 60, 57, 51,
56, 55, 64, 72, 92, 78, 64, 68,
87, 69, 55, 56, 80, 109, 81, 87,
95, 98, 103, 104, 103, 62, 77, 113,
121, 112, 100, 120, 92, 101, 103, 99,
// chroma table:
17, 18, 18, 24, 21, 24, 47, 26,
26, 47, 99, 66, 56, 66, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
};
/// <summary>
/// Creates a Luma and Chroma Table using the default quantizer
/// </summary>
/// <param name="Q">The quality</param>
/// <returns>64 luma bytes and 64 chroma</returns>
static byte[] CreateQuantizationTables(uint Q)
{
int factor = (int)Q;
int q;
if (Q < 1) factor = 1;
else if (Q > 99) factor = 99;
if (Q < 50)
{
q = 5000 / factor;
}
else
{
q = 200 - factor * 2;
}
byte[] resultTables = new byte[128];
for (int i = 0; i < 128; ++i)
{
int newVal = (defaultQuantizers[i] * q + 50) / 100;
if (newVal < 1) newVal = 1;
else if (newVal > 255) newVal = 255;
resultTables[i] = (byte)newVal;
}
return resultTables;
}
static byte[] CreateQuantizationTablesMarker(ArraySegment<byte> tables)
{
List<byte> result = new List<byte>();
int tableSize = tables.Count / 2;
//Luma
result.Add(0xff);
result.Add(0xdb);
result.Add(0x00);
result.Add((byte)(tableSize + 3));
result.Add(0x00);
for (int i = 0, e = tableSize; i < e; ++i)
{
result.Add(tables.Array[tables.Offset + i]);
}
//Chroma
result.Add(0xff);
result.Add(0xdb);
result.Add(0x00);
result.Add((byte)(tableSize + 3));
result.Add(0x01);
for (int i = tableSize, e = tables.Count; i < e; ++i)
{
result.Add(tables.Array[tables.Offset + i]);
}
return result.ToArray();
}
static byte[] lum_dc_codelens = { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
static byte[] lum_dc_symbols = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static byte[] lum_ac_codelens = { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d, };
static byte[] lum_ac_symbols = {
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};
static byte[] chm_dc_codelens = { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
static byte[] chm_dc_symbols = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
static byte[] chm_ac_codelens = { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
static byte[] chm_ac_symbols = {
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
};
static byte[] CreateHuffmanTableMarker(byte[] codeLens, byte[] symbols, int tableNo, int tableClass)
{
List<byte> result = new List<byte>();
result.Add(0xff);
result.Add(0xc4);
result.Add(0x00);
result.Add((byte)(3 + codeLens.Length + symbols.Length));
result.Add((byte)((tableClass << 4) | tableNo));
result.AddRange(codeLens);
result.AddRange(symbols);
return result.ToArray();
}
static byte[] CreateDataRestartIntervalMarker(uint dri)
{
return new byte[] { 0xff, 0xdd, 0x00, 0x04, (byte)(dri >> 8), (byte)(dri) };
}
#endregion
public JpegFrame() : base(26) { }
/// <summary>
/// Writes packets to a memory stream and created the default header and quantization tables if necessary.
/// </summary>
void ProcessPackets(System.IO.MemoryStream buffer)
{
ArraySegment<byte> tables = default(ArraySegment<byte>);
uint FragmentOffset, TypeSpecific, Type, Quality, Width, Height, DataRestartInterval = 0;
for (int i = 0, e = this.Packets.Count, last = e - 1; i < e; ++i)
{
int offset = 0;
RtpPacket packet = this.Packets[i];
TypeSpecific = (uint)(packet.Payload[offset++]);
//FragmentOffset = (uint)(packet.Payload[offset++] | packet.Payload[offset++] << 8 | packet.Payload[offset++] << 16);
FragmentOffset = (uint)(packet.Payload[offset++] << 16 | packet.Payload[offset++] << 8 | packet.Payload[offset++]);
//Ensure start packet
if (i == 0 && FragmentOffset != 0) continue;
Type = (uint)(packet.Payload[offset++]);
Quality = (uint)packet.Payload[offset++];
Width = (uint)(packet.Payload[offset++] * 8);
Height = (uint)(packet.Payload[offset++] * 8);
//Only occur in the first packet
if (FragmentOffset == 0)
{
//If There is already a StartOfInformation present just copy
if (packet.Payload[offset] == 0xff && packet.Payload[offset + 1] == 0xd8)
{
goto WritePacket;
}
//Get the restart interval is present
if (Type > 63)
{
DataRestartInterval = (uint)(packet.Payload[offset++] << 8 | packet.Payload[offset++]);
}
//Get the Q Tables if present
if (Quality > 127)
{
uint MBZ = (uint)(packet.Payload[offset++]);//Should only proceed if MBZ > 0?
uint Precision = (uint)(packet.Payload[offset++]);//Wasted read
uint Length = (uint)(packet.Payload[offset++] << 8 | packet.Payload[offset++]);
if(Length > 0)
{
tables = new ArraySegment<byte>(packet.Payload, offset, (int)Length);
offset += (int)Length;
}
else
{
tables = new ArraySegment<byte>(CreateQuantizationTables(Quality));
}
}
//Write the header to the buffer
byte[] header = CreateJFIFHeader(Type, Width, Height, tables, DataRestartInterval);
buffer.Write(header, 0, header.Length);
}
WritePacket: //Copy rest of data to buffer
buffer.Write(packet.Payload, offset, packet.Payload.Length - offset);
//Check to see if EOI is present or needs to be added on the last packet
if (i == last && packet.Payload[packet.Payload.Length - 2] != 0xff && packet.Payload[packet.Payload.Length - 1] != 0xd9)
{
buffer.WriteByte(0xff);
buffer.WriteByte(0xd9);
}
}
//Go back to the beginning
buffer.Seek(0, System.IO.SeekOrigin.Begin);
}
/// <summary>
/// Creates a image from the processed packets in the memory stream
/// </summary>
/// <returns>The image created from the packets</returns>
public System.Drawing.Image ToImage()
{
try
{
using (System.IO.MemoryStream buffer = new System.IO.MemoryStream())
{
ProcessPackets(buffer);
return System.Drawing.Image.FromStream(buffer, false, true);
}
}
catch (Exception exc)
{
log.ErrorFormat("Exception in ToImage(): {0}", exc.Message);
return null;
}
}
}
}
@@ -0,0 +1,91 @@
///
/// Copyright (c) 2017 Sensus Metering Systems
///
using System;
using System.Collections.Generic;
namespace TBF.Rig.Network.Camera.CLP1611
{
public class RoisAndResults
{
public const int MaxRegisteredRois = 4; /// Max. count of registered (and measured) ROI-s
public long CameraTimeMs;
public int[] Angles;
private IList<string> roiParams;
public int RegisteredRoisCount { get { return roiParams.Count; } }
public RoisAndResults()
{
Angles = new int[MaxRegisteredRois];
roiParams = new List<string>();
}
public void ClearRoiParams()
{
lock (this)
{
roiParams.Clear();
}
}
public int RegisterRoi(string roiParam)
{
lock (this)
{
if (this.roiParams.Count >= MaxRegisteredRois) return 0;
this.roiParams.Add(roiParam);
return this.roiParams.Count; /// return a handle 1 .. MaxRegisteredRois
}
}
public string GetRoiParams(int roiHandle)
{
lock (this)
{
if (roiHandle > 0 && roiHandle <= roiParams.Count)
{
return roiParams[roiHandle - 1];
}
else
{
return string.Empty;
}
}
}
public void SetResults(long timeMs, int[] angles)
{
lock (this)
{
CameraTimeMs = timeMs;
for (int i = 0; i < Math.Min(angles.Length, Angles.Length); i++)
{
Angles[i] = angles[i];
}
}
}
public int GetResult(int roiHandle, out long timeMs)
{
lock (this)
{
if (roiHandle > 0 && roiHandle <= roiParams.Count)
{
timeMs = CameraTimeMs;
return Angles[roiHandle - 1];
}
else
{
timeMs = 0;
return 0;
}
}
}
}
}
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TBF.Rig.Network.Camera
{
public class RtpFrame
{
public enum STATE
{
Empty, /// Initial state after being constructed
OK, /// The frame is not empty, but it's not complete yet. It's without any error
Error, /// An error occured
Complete, /// The frame is complete, consequent AddPacket() calls will be ignored
}
public readonly int PayloadType;
public IList<RtpPacket> Packets;
public STATE State { get { return state; } }
STATE state;
public RtpFrame(int payloadType)
{
PayloadType = payloadType;
Packets = new List<RtpPacket>();
state = STATE.Empty;
}
public STATE AddPacket(RtpPacket packet)
{
if (state == STATE.Error || packet.PayloadType != PayloadType)
{
return (state = STATE.Error); /// Already in error or wrong payload type
}
else if (state == STATE.Complete)
{
return STATE.Complete; /// Already complete
}
else if (state != STATE.Empty && packet.SequenceNumber != Packets.Last<RtpPacket>().SequenceNumber + 1)
{
return (state = STATE.Error); /// Packet out of order
}
/// Going to add a new packet previous ones
Packets.Add(packet);
if (packet.Mark)
{
return (state = STATE.Complete); /// Complete now
}
else
{
return (state = STATE.OK); /// OK, not complete yet
}
}
public void Clear()
{
Packets.Clear();
state = STATE.Empty;
}
}
}
@@ -0,0 +1,47 @@
using System;
namespace TBF.Rig.Network.Camera
{
public class RtpPacket
{
public readonly int Version;
public readonly bool P;
public readonly bool X;
public readonly int CC;
public readonly bool Mark;
public readonly int PayloadType;
public readonly int SequenceNumber;
public readonly int Timestamp;
public readonly int SsrcId;
public readonly Byte[] Payload; /// Data without RTP header
public RtpPacket(Byte[] data)
{
if (data.Length < 12) throw new Exception("Packet too short");
Version = (data[0] >> 6) & 0x02; /// 1 RTP Version
P = ((data[0] & 0x20) != 0); /// 2 RTP P
X = ((data[0] & 0x10) != 0); /// 3 RTP X
CC = (data[0] & 0x0F); /// 4 RTP CC
Mark = ((data[1] & 0x80) != 0); /// 5 RTP M
PayloadType = (data[1] & 0x7F); /// 6 RTP PT
SequenceNumber = data[2] * 256 + data[3]; /// 7 RTP Seq#
Timestamp = ((data[4] * 256 + data[5]) * 256 + data[6]) * 256 + data[7]; /// 8 RTP Timestamp
SsrcId = ((data[8] * 256 + data[9]) * 256 + data[10]) * 256 + data[11]; /// 9 RTP SSRC Id
int ExtensionHeaderSize = 0;
if (X && data.Length >= 16 + 4*CC)
{
ExtensionHeaderSize = data[14 + 4*CC] * 256 + data[15 + 4*CC] + 4;
}
int payloadDataOffset = 12 + 4 * CC + ExtensionHeaderSize;
int payloadDataCount = data.Length - 12 - 4 * CC - ExtensionHeaderSize;
if (payloadDataCount < 0) throw new Exception("Invalid packet");
Payload = new byte[payloadDataCount];
Array.Copy(data, payloadDataOffset, Payload, 0, payloadDataCount);
}
}
}
+62
View File
@@ -0,0 +1,62 @@
namespace TBF.Rig.Network.Camera.CLP1611
{
partial class TerminalDlg
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.vtTextBox = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// vtTextBox
//
this.vtTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.vtTextBox.Location = new System.Drawing.Point(0, 0);
this.vtTextBox.Multiline = true;
this.vtTextBox.Name = "vtTextBox";
this.vtTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.vtTextBox.Size = new System.Drawing.Size(737, 437);
this.vtTextBox.TabIndex = 0;
//
// TerminalDlg
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(737, 437);
this.Controls.Add(this.vtTextBox);
this.Name = "TerminalDlg";
this.Text = "Terminal";
this.Load += new System.EventHandler(this.Terminal_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox vtTextBox;
}
}
@@ -0,0 +1,39 @@
using System;
using System.Windows.Forms;
using TBF.Rig.Network.Telnet;
namespace TBF.Rig.Network.Camera.CLP1611
{
public partial class TerminalDlg : Form
{
TelnetClient telnet;
bool dlgLoaded;
public TerminalDlg()
{
InitializeComponent();
}
public TerminalDlg(string name, TelnetClient telnet)
{
InitializeComponent();
Text = name;
this.telnet = telnet;
}
private void Terminal_Load(object sender, EventArgs e)
{
telnet.vtTextChangedHandler += delegate(object sndr, VtTextChangedEventArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<VtTextChangedEventArgs>(OnTextChanged), sndr, args); }
else OnTextChanged(sndr, args);
};
dlgLoaded = true;
}
void OnTextChanged(object sndr, VtTextChangedEventArgs args)
{
vtTextBox.Text = args.VtText;
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>