Network.Adapter, Network.Camera.CLP1611, Network.Camera.RoI Network.Tftp and Network.Telnet components added. Camera detection and live strean work OK.
This commit is contained in:
parent
ad51719d92
commit
254afc3978
@ -271,6 +271,7 @@ namespace DeviceTest
|
||||
operation4 = null;
|
||||
workerThreadRunning = false;
|
||||
|
||||
string initializedDeviceName = "none";
|
||||
try
|
||||
{
|
||||
if (parentFactory != null && parentCfg != null)
|
||||
@ -291,8 +292,8 @@ namespace DeviceTest
|
||||
|
||||
foreach (var d in tbfDevices)
|
||||
{
|
||||
initializedDeviceName = d.Name;
|
||||
d.Initialize();
|
||||
Debug.WriteLine("{0}.Initialize()", d.Name);
|
||||
}
|
||||
|
||||
SaveSettings(); /// Save settings after successful initialization
|
||||
@ -313,8 +314,10 @@ namespace DeviceTest
|
||||
workerThreadRunning = false;
|
||||
workerThread = null;
|
||||
|
||||
MessageBox.Show(string.Format("Exception: {0}", exc.Message), "Initialization failed",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
||||
MessageBox.Show(exc.Message,
|
||||
string.Format("'{0}' initialization failed", initializedDeviceName),
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Exclamation);
|
||||
|
||||
startButton.Enabled = true;
|
||||
stopButton.Enabled = false;
|
||||
@ -334,6 +337,10 @@ namespace DeviceTest
|
||||
{
|
||||
operation1 = (tbfComponent4Op as TBF.BenchControl.Modbus.PressureMeter.Meret.PressureMeter).ReadPressureOp(ref floatBox);
|
||||
}
|
||||
else if (tbfComponent4Op is TBF.BenchControl.Network.Camera.CLP1611.Camera)
|
||||
{
|
||||
operation1 = (tbfComponent4Op as TBF.BenchControl.Network.Camera.CLP1611.Camera).LiveStreamOp();
|
||||
}
|
||||
|
||||
while (workerThreadRunning)
|
||||
{
|
||||
@ -341,7 +348,7 @@ namespace DeviceTest
|
||||
|
||||
if (workerThreadRunning)
|
||||
{
|
||||
foreach (var d in tbfDevices) { d.RunDeviceBefore(); Debug.WriteLine("{0}.RunDeviceBefore()", d.Name); }
|
||||
foreach (var d in tbfDevices) d.RunDeviceBefore();
|
||||
|
||||
if (tbfComponent4Op != null)
|
||||
{
|
||||
@ -380,11 +387,11 @@ namespace DeviceTest
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var d in tbfDevices) { d.RunDeviceAfter(); Debug.WriteLine("{0}.RunDeviceAfter()", d.Name); }
|
||||
foreach (var d in tbfDevices) d.RunDeviceAfter();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var d in tbfDevices) { d.StopDevice(); Debug.WriteLine("{0}.StopDevice()", d.Name); }
|
||||
foreach (var d in tbfDevices) d.StopDevice();
|
||||
}
|
||||
|
||||
private void stopButton_Click(object sender, EventArgs e)
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
using System.Net;
|
||||
|
||||
namespace TBF.BenchControl.GenericDevices
|
||||
{
|
||||
public interface INetworkAdapter : TBF.BenchControl.Generic.IComponent
|
||||
{
|
||||
IPAddress IPAddress { get; }
|
||||
IPAddress NetMask { get; }
|
||||
IPAddress BroadcastAddress { get; }
|
||||
}
|
||||
}
|
||||
208
TestBenchFramework/BenchControl/Network/Adapter/AdapterInfo.cs
Normal file
208
TestBenchFramework/BenchControl/Network/Adapter/AdapterInfo.cs
Normal file
@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for the storing information about a network adapter.
|
||||
/// </summary>
|
||||
public class AdapterInfo
|
||||
{
|
||||
public string Description; /// Description of the network adapter.
|
||||
public IPAddress IPAddress; /// IP address of the network adapter.
|
||||
public IPAddress NetMask; /// Mask of the network adapter.
|
||||
|
||||
/// Constructor
|
||||
public AdapterInfo(string description)
|
||||
{
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public IPAddress GetBroadcastAddress()
|
||||
{
|
||||
byte[] ipAdressBytes = IPAddress.GetAddressBytes();
|
||||
byte[] subnetMaskBytes = NetMask.GetAddressBytes();
|
||||
|
||||
if (ipAdressBytes.Length != subnetMaskBytes.Length)
|
||||
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
|
||||
|
||||
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
|
||||
for (int i = 0; i < broadcastAddress.Length; i++)
|
||||
{
|
||||
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
|
||||
}
|
||||
|
||||
return new IPAddress(broadcastAddress);
|
||||
}
|
||||
|
||||
///------------------------------------------------------
|
||||
/// Static members and functions
|
||||
///------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Private list of the available network adapters.
|
||||
/// </summary>
|
||||
static List<AdapterInfo> netAdapters;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of network adapters.
|
||||
/// Never returns 'null', calls RefreshNetAdaptersInfo() the first time it is used.
|
||||
/// If you want to refresh the list of the network adapters later, explicitly call
|
||||
/// the RefreshNetAdaptersInfo() method.
|
||||
/// </summary>
|
||||
public static List<AdapterInfo> NetAdapters
|
||||
{
|
||||
get
|
||||
{
|
||||
if (netAdapters == null) RefreshNetAdaptersInfo();
|
||||
return netAdapters;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the information about network adapters stored in the netAdapters list.
|
||||
/// </summary>
|
||||
public static void RefreshNetAdaptersInfo()
|
||||
{
|
||||
if (netAdapters == null) netAdapters = new List<AdapterInfo>();
|
||||
else netAdapters.Clear();
|
||||
|
||||
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in nics)
|
||||
{
|
||||
AdapterInfo info = new AdapterInfo(adapter.Description);
|
||||
netAdapters.Add(info);
|
||||
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
if (properties == null)
|
||||
continue;
|
||||
UnicastIPAddressInformationCollection uniCast = properties.UnicastAddresses;
|
||||
if (uniCast == null)
|
||||
continue;
|
||||
foreach (UnicastIPAddressInformation uni in uniCast)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
info = new AdapterInfo(adapter.Description);
|
||||
netAdapters.Add(info);
|
||||
}
|
||||
info.IPAddress = uni.Address;
|
||||
if (uni.IPv4Mask != null) info.NetMask = uni.IPv4Mask;
|
||||
info = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the loopback network adapter.
|
||||
/// </summary>
|
||||
public static AdapterInfo LoopbackAdapter
|
||||
{
|
||||
get
|
||||
{
|
||||
List<AdapterInfo> adapters = NetAdapters;
|
||||
foreach (AdapterInfo a in adapters)
|
||||
{
|
||||
if (a.IPAddress != null && a.IPAddress.Equals(IPAddress.Loopback)) return a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default network adapter - the first one which his not a loopback adapter.
|
||||
/// Network adapters with IP address have preference, adapters without IP address
|
||||
/// (like an unconnected wireless adapter) are used just when there is no adapter with IP.
|
||||
///
|
||||
/// Default adapter is used when none was specified in the configuration file
|
||||
/// and it is used to initialize Options-General dialog-tab.
|
||||
/// </summary>
|
||||
public static AdapterInfo DefaultAdapter
|
||||
{
|
||||
get
|
||||
{
|
||||
List<AdapterInfo> adapters = NetAdapters; /// Make a copy to avoid interference
|
||||
AdapterInfo adapterWithoutIP = null; /// Use this one if there is no other better adapter
|
||||
foreach (AdapterInfo a in adapters)
|
||||
{
|
||||
if (!a.IPAddress.Equals(IPAddress.Loopback))
|
||||
{
|
||||
if (a.IPAddress != null) return a;
|
||||
else if (adapterWithoutIP == null) adapterWithoutIP = a;
|
||||
}
|
||||
}
|
||||
return adapterWithoutIP == null ? LoopbackAdapter : adapterWithoutIP;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get network adapter info from the description string.
|
||||
/// </summary>
|
||||
/// <param name="description">Description</param>
|
||||
/// <returns>AdapterInfo object reference</returns>
|
||||
public static AdapterInfo GetNetAdapter(string description)
|
||||
{
|
||||
List<AdapterInfo> adapters = NetAdapters;
|
||||
|
||||
foreach (AdapterInfo a in adapters)
|
||||
{
|
||||
if (a.Description != description ||
|
||||
a.IPAddress == null ||
|
||||
a.IPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6 ||
|
||||
a.IPAddress.Equals(IPAddress.Loopback) ||
|
||||
a.NetMask == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
return DefaultAdapter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the given string as URL parameter.
|
||||
/// </summary>
|
||||
/// <param name="pathToEncode">String to be encoded.</param>
|
||||
/// <returns>String encoded as the URL parameter.</returns>
|
||||
public static string UrlPathEncode(string pathToEncode)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(pathToEncode.Length * 3);
|
||||
|
||||
sb.Append(pathToEncode);
|
||||
|
||||
// % must be first!!!
|
||||
sb.Replace("%", "%" + Convert.ToInt32('%').ToString("X2"));
|
||||
// ?, & and / are not convertable by HttpUtility.UrlPathEncode
|
||||
sb.Replace("?", "%" + Convert.ToInt32('?').ToString("X2"));
|
||||
sb.Replace("&", "%" + Convert.ToInt32('&').ToString("X2"));
|
||||
sb.Replace("/", "%" + Convert.ToInt32('/').ToString("X2"));
|
||||
// Additional chars. E.g.: # didn't work in the path passed to the Uri class. "c:\\sour#ce\\my # proj".
|
||||
sb.Replace("#", "%" + Convert.ToInt32('#').ToString("X2"));
|
||||
// Backslash must be removed because it is not accepted by Uri class when passing path into it. E.g.: "C:%5Csource" is not acceptable.
|
||||
//sb.Replace("\\", "%" + Convert.ToInt32('\\').ToString("X2"));
|
||||
//// I removed following chars because I do not know if it is good idea to replace them (see previous line with '\\' char).
|
||||
sb.Replace("\r", "%" + Convert.ToInt32('\r').ToString("X2"));
|
||||
sb.Replace("\n", "%" + Convert.ToInt32('\n').ToString("X2"));
|
||||
sb.Replace("\t", "%" + Convert.ToInt32('\t').ToString("X2"));
|
||||
|
||||
string s = sb.ToString();
|
||||
s = HttpUtility.UrlPathEncode(s);
|
||||
//sb.Length = 0;
|
||||
//sb.Append(HttpUtility.UrlPathEncode(s));
|
||||
//for (int i = 0; i < sb.Length; i += 3)
|
||||
//{
|
||||
// char c = sb[i];
|
||||
// if (c == '%')
|
||||
// continue;
|
||||
// sb[i] = '%';
|
||||
// sb.Insert(i + 1, Convert.ToUInt64(c).ToString("X2"));
|
||||
//}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
TestBenchFramework/BenchControl/Network/Adapter/Factory.cs
Normal file
26
TestBenchFramework/BenchControl/Network/Adapter/Factory.cs
Normal file
@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
|
||||
|
||||
public void ResetStaticProperties() { Netadapter.ResetStaticProperties(); }
|
||||
|
||||
public IComponent DummyComponent() { return new Netadapter(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Netadapter(cfg); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new NetadapterCfg(this.GetType().Namespace.Substring(17), this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(typeof(NetadapterCfg), component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Net;
|
||||
using log4net;
|
||||
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
public class Netadapter : ComponentBase, TBF.BenchControl.Generic.IDevice, GenericDevices.INetworkAdapter
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(Netadapter));
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Component={0} IPAddress={1} NetMask={2} Description={3}", Cfg.Name, IPAddress, NetMask, (Cfg as NetadapterCfg).Description);
|
||||
}
|
||||
|
||||
readonly NetadapterCfg netadapterCfg;
|
||||
readonly IPAddress ipAddress;
|
||||
readonly IPAddress netMask;
|
||||
readonly IPAddress broadcastAddress;
|
||||
|
||||
public IPAddress IPAddress { get { return ipAddress; } }
|
||||
public IPAddress NetMask { get { return netMask; } }
|
||||
public IPAddress BroadcastAddress { get { return broadcastAddress; } }
|
||||
|
||||
Tftp.TftpServer tftpServer;
|
||||
|
||||
public Netadapter()
|
||||
{
|
||||
}
|
||||
|
||||
public Netadapter(Generic.IComponentCfg cfg)
|
||||
: base(cfg)
|
||||
{
|
||||
netadapterCfg = cfg as NetadapterCfg;
|
||||
AdapterInfo.RefreshNetAdaptersInfo();
|
||||
AdapterInfo netadapter = AdapterInfo.GetNetAdapter(netadapterCfg.Description);
|
||||
ipAddress = netadapter.IPAddress;
|
||||
netMask = netadapter.NetMask;
|
||||
broadcastAddress = netadapter.GetBroadcastAddress();
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (netadapterCfg.DebugLevel != Config.Entities.DebugMode.Simulate)
|
||||
{
|
||||
if (netadapterCfg.TftpServerEnabled)
|
||||
{
|
||||
tftpServer = new Tftp.TftpServer();
|
||||
tftpServer.Start(netadapterCfg.TftpServerDirectory, ipAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
tftpServer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
if (netadapterCfg.DebugLevel != Config.Entities.DebugMode.Simulate)
|
||||
{
|
||||
if (tftpServer != null) tftpServer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceBefore() {}
|
||||
public void RunDeviceAfter() {}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
public class NetadapterCfg : ComponentCfgBase, Generic.IComponentCfg
|
||||
{
|
||||
public IComponentCfgCtrl GetControl() { return new NetadapterCfgCtrl(); }
|
||||
|
||||
|
||||
public string Description; /// Description string of the selected network adapter
|
||||
public bool TftpServerEnabled;
|
||||
public string TftpServerDirectory;
|
||||
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
NetadapterCfg() {}
|
||||
|
||||
public NetadapterCfg(string name, IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
Factory = factory;
|
||||
ParentName = string.Empty;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("Name={0}, Description={1}", Name, Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
public partial class NetadapterCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(NetadapterCfgCtrl));
|
||||
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
NetadapterCfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as NetadapterCfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public NetadapterCfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void EntryFormCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (ParentForm == null) return; /// Return is executed when tab page is open in Designer
|
||||
if (config == null) return; /// Control was not loaded, settings were not changed
|
||||
|
||||
Localize();
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void Redraw()
|
||||
{
|
||||
classNameLabel.Text = config.Factory.ClassName;
|
||||
nameTextBox.Text = config.Name;
|
||||
tftpEnabledCheckBox.Checked = config.TftpServerEnabled;
|
||||
tftpDirectoryTextBox.Text = config.TftpServerDirectory;
|
||||
|
||||
AdapterInfo.RefreshNetAdaptersInfo();
|
||||
IList<AdapterInfo> adapters = AdapterInfo.NetAdapters;
|
||||
|
||||
string cfgAdapter = string.Empty;
|
||||
foreach (AdapterInfo ai in adapters)
|
||||
{
|
||||
string record;
|
||||
|
||||
if (ai.IPAddress == null)
|
||||
{
|
||||
/// This happens with network adapters that currently have no IP address,
|
||||
/// for instance not connected wireless or dial-up adapters
|
||||
record = "???.???.???.???";
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Do not consider IPv6 adapters as well as "Any", "Broadcast", "Loopback" or "None" addresses
|
||||
if ((ai.IPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) ||
|
||||
ai.IPAddress.Equals(IPAddress.Any) ||
|
||||
ai.IPAddress.Equals(IPAddress.Broadcast) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6Any) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6Loopback) ||
|
||||
ai.IPAddress.Equals(IPAddress.IPv6None) ||
|
||||
ai.IPAddress.Equals(IPAddress.Loopback) ||
|
||||
ai.IPAddress.Equals(IPAddress.None))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
record = ai.IPAddress.ToString();
|
||||
}
|
||||
|
||||
record += " - " + ai.Description;
|
||||
int i = adapterComboBox.Items.Add(record);
|
||||
if (ai.Description == config.Description)
|
||||
{
|
||||
/// Select the adapter currently in the configuration
|
||||
adapterComboBox.SelectedIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select the first one if the adapter from the configuration does not exist on the system
|
||||
if (adapterComboBox.SelectedIndex < 0 && adapterComboBox.Items.Count > 0)
|
||||
{
|
||||
adapterComboBox.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Localize()
|
||||
{
|
||||
}
|
||||
|
||||
public void Closing()
|
||||
{
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
adapterComboBox.Enabled = true;
|
||||
tftpEnabledCheckBox.Enabled = true;
|
||||
tftpDirectoryTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
if (!adapterComboBox.Items.Contains(adapterComboBox.Text))
|
||||
{
|
||||
flags = CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "Invalid 'Parent Name'";
|
||||
}
|
||||
|
||||
if (tftpEnabledCheckBox.Checked && !Directory.Exists(tftpDirectoryTextBox.Text))
|
||||
{
|
||||
flags = CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "TFTP Directory does not exist";
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
|
||||
/// Network adapter
|
||||
string strAdapter = adapterComboBox.Text;
|
||||
int iDash = strAdapter.IndexOf(" - ");
|
||||
config.Description = iDash < 0 ? "" : strAdapter.Substring(iDash + 3);
|
||||
|
||||
config.TftpServerEnabled = tftpEnabledCheckBox.Checked;
|
||||
config.TftpServerDirectory = tftpDirectoryTextBox.Text;
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
145
TestBenchFramework/BenchControl/Network/Adapter/NetadapterCfgCtrl.designer.cs
generated
Normal file
145
TestBenchFramework/BenchControl/Network/Adapter/NetadapterCfgCtrl.designer.cs
generated
Normal file
@ -0,0 +1,145 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.BenchControl.Network.Adapter
|
||||
{
|
||||
partial class NetadapterCfgCtrl
|
||||
{
|
||||
/// <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.nameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.nameLabel = new System.Windows.Forms.Label();
|
||||
this.classNameLabel = new System.Windows.Forms.Label();
|
||||
this.adapterLabel = new System.Windows.Forms.Label();
|
||||
this.adapterComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.tftpEnabledCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.tftpDirectoryLabel = new System.Windows.Forms.Label();
|
||||
this.tftpDirectoryTextBox = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(101, 50);
|
||||
this.nameTextBox.Name = "nameTextBox";
|
||||
this.nameTextBox.Size = new System.Drawing.Size(114, 20);
|
||||
this.nameTextBox.TabIndex = 5;
|
||||
//
|
||||
// nameLabel
|
||||
//
|
||||
this.nameLabel.AutoSize = true;
|
||||
this.nameLabel.Location = new System.Drawing.Point(9, 53);
|
||||
this.nameLabel.Name = "nameLabel";
|
||||
this.nameLabel.Size = new System.Drawing.Size(35, 13);
|
||||
this.nameLabel.TabIndex = 4;
|
||||
this.nameLabel.Text = "Name";
|
||||
//
|
||||
// classNameLabel
|
||||
//
|
||||
this.classNameLabel.AutoSize = true;
|
||||
this.classNameLabel.Location = new System.Drawing.Point(98, 24);
|
||||
this.classNameLabel.Name = "classNameLabel";
|
||||
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
|
||||
this.classNameLabel.TabIndex = 3;
|
||||
this.classNameLabel.Text = "ComonentName";
|
||||
//
|
||||
// adapterLabel
|
||||
//
|
||||
this.adapterLabel.AutoSize = true;
|
||||
this.adapterLabel.Location = new System.Drawing.Point(9, 80);
|
||||
this.adapterLabel.Name = "adapterLabel";
|
||||
this.adapterLabel.Size = new System.Drawing.Size(44, 13);
|
||||
this.adapterLabel.TabIndex = 6;
|
||||
this.adapterLabel.Text = "Adapter";
|
||||
//
|
||||
// adapterComboBox
|
||||
//
|
||||
this.adapterComboBox.Location = new System.Drawing.Point(101, 77);
|
||||
this.adapterComboBox.Name = "adapterComboBox";
|
||||
this.adapterComboBox.Size = new System.Drawing.Size(333, 21);
|
||||
this.adapterComboBox.TabIndex = 7;
|
||||
//
|
||||
// tftpEnabledCheckBox
|
||||
//
|
||||
this.tftpEnabledCheckBox.AutoSize = true;
|
||||
this.tftpEnabledCheckBox.Enabled = false;
|
||||
this.tftpEnabledCheckBox.Location = new System.Drawing.Point(101, 115);
|
||||
this.tftpEnabledCheckBox.Name = "tftpEnabledCheckBox";
|
||||
this.tftpEnabledCheckBox.Size = new System.Drawing.Size(121, 17);
|
||||
this.tftpEnabledCheckBox.TabIndex = 12;
|
||||
this.tftpEnabledCheckBox.Text = "Enable TFTP server";
|
||||
this.tftpEnabledCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tftpDirectoryLabel
|
||||
//
|
||||
this.tftpDirectoryLabel.AutoSize = true;
|
||||
this.tftpDirectoryLabel.Location = new System.Drawing.Point(9, 144);
|
||||
this.tftpDirectoryLabel.Name = "tftpDirectoryLabel";
|
||||
this.tftpDirectoryLabel.Size = new System.Drawing.Size(79, 13);
|
||||
this.tftpDirectoryLabel.TabIndex = 13;
|
||||
this.tftpDirectoryLabel.Text = "TFTP Directory";
|
||||
//
|
||||
// tftpDirectoryTextBox
|
||||
//
|
||||
this.tftpDirectoryTextBox.Enabled = false;
|
||||
this.tftpDirectoryTextBox.Location = new System.Drawing.Point(101, 141);
|
||||
this.tftpDirectoryTextBox.Name = "tftpDirectoryTextBox";
|
||||
this.tftpDirectoryTextBox.Size = new System.Drawing.Size(333, 20);
|
||||
this.tftpDirectoryTextBox.TabIndex = 14;
|
||||
//
|
||||
// NetadapterCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.tftpDirectoryTextBox);
|
||||
this.Controls.Add(this.tftpDirectoryLabel);
|
||||
this.Controls.Add(this.tftpEnabledCheckBox);
|
||||
this.Controls.Add(this.adapterComboBox);
|
||||
this.Controls.Add(this.adapterLabel);
|
||||
this.Controls.Add(this.nameTextBox);
|
||||
this.Controls.Add(this.nameLabel);
|
||||
this.Controls.Add(this.classNameLabel);
|
||||
this.Name = "NetadapterCfgCtrl";
|
||||
this.Size = new System.Drawing.Size(450, 300);
|
||||
this.Load += new System.EventHandler(this.EntryFormCfgCtrl_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox nameTextBox;
|
||||
private System.Windows.Forms.Label nameLabel;
|
||||
private System.Windows.Forms.Label classNameLabel;
|
||||
private System.Windows.Forms.Label adapterLabel;
|
||||
private System.Windows.Forms.ComboBox adapterComboBox;
|
||||
private System.Windows.Forms.CheckBox tftpEnabledCheckBox;
|
||||
private System.Windows.Forms.Label tftpDirectoryLabel;
|
||||
private System.Windows.Forms.TextBox tftpDirectoryTextBox;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
220
TestBenchFramework/BenchControl/Network/Camera/CLP1611/Camera.cs
Normal file
220
TestBenchFramework/BenchControl/Network/Camera/CLP1611/Camera.cs
Normal file
@ -0,0 +1,220 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using log4net;
|
||||
using Config.Entities;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.CLP1611
|
||||
{
|
||||
public class Camera : ComponentBase, Generic.IDevice
|
||||
{
|
||||
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(image) ? "not detected" : image);
|
||||
}
|
||||
|
||||
|
||||
readonly CameraCfg cameraCfg;
|
||||
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 Image { get { return image; } }
|
||||
string image;
|
||||
|
||||
|
||||
Telnet.TelnetClient telnet;
|
||||
TerminalDlg terminalDlg;
|
||||
|
||||
|
||||
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");
|
||||
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (cameraCfg.DebugLevel == DebugMode.Simulate) return;
|
||||
|
||||
bool cameraDetected = DetectCamera(cameraCfg.HardwareAddress, true,
|
||||
out ipAddress, out hardware, out revision, out serial, out image);
|
||||
if (!cameraDetected) throw new Exception("No camera detected");
|
||||
|
||||
telnet = new Telnet.TelnetClient(this, cameraCfg.Name, "pi", "raspberry", "$ ");
|
||||
|
||||
if (cameraCfg.DisplayTerminal)
|
||||
{
|
||||
terminalDlg = new TerminalDlg(cameraCfg.Name, telnet);
|
||||
terminalDlg.Show();
|
||||
}
|
||||
|
||||
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.CONNECT, ipAddress.ToString(), 10, 30));
|
||||
|
||||
log.FatalFormat("Successfully initialized device {0}", ToString());
|
||||
}
|
||||
|
||||
public void StopDevice()
|
||||
{
|
||||
if (terminalDlg != null)
|
||||
{
|
||||
terminalDlg.CloseDlg();
|
||||
terminalDlg = null;
|
||||
}
|
||||
|
||||
if (telnet != null)
|
||||
{
|
||||
telnet.Dispose();
|
||||
telnet = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void RunDeviceBefore() {}
|
||||
public void RunDeviceAfter() {}
|
||||
|
||||
|
||||
|
||||
public IOperation LiveStreamOp()
|
||||
{
|
||||
return new LiveStreamOp(this, telnet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <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="image">Detected OS image</param>
|
||||
/// <returns>true when camera detected successfully</returns>
|
||||
bool DetectCamera(int hwAddress, bool setDateTime, out IPAddress ipAddress, out string hardware, out string revision, out string serial, out string image)
|
||||
{
|
||||
for (int trials = 1; trials <= 3; trials++)
|
||||
{
|
||||
UdpClient udpClient = new UdpClient();
|
||||
|
||||
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];
|
||||
image = 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];
|
||||
image = 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
|
||||
}
|
||||
|
||||
udpClient.Close();
|
||||
}
|
||||
|
||||
ipAddress = null;
|
||||
hardware = null;
|
||||
revision = null;
|
||||
serial = null;
|
||||
image = 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.CLP1611
|
||||
{
|
||||
public class CameraCfg : ComponentCfgBase, IChildComponentCfg
|
||||
{
|
||||
public IComponentCfgCtrl GetControl() { return new CameraCfgCtrl(); }
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int HardwareAddress;
|
||||
public bool DisplayTerminal;
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("Name={0}, HWAddr={1}, Parent={2}", Name, HardwareAddress, ParentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.CLP1611
|
||||
{
|
||||
public partial class CameraCfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(CameraCfgCtrl));
|
||||
|
||||
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)
|
||||
{
|
||||
parent = ParentForm as ComponentParametersDlg;
|
||||
if (parent == null) return;
|
||||
|
||||
if (parent.TbfComponents != null)
|
||||
{
|
||||
foreach (var cmpnt in parent.TbfComponents)
|
||||
{
|
||||
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is TBF.BenchControl.Network.Adapter.Factory)
|
||||
{
|
||||
parentNameComboBox.Items.Add(cmpnt.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
parentNameComboBox.Enabled = true;
|
||||
hwAddressTextBox.Enabled = true;
|
||||
displayTerminalCheckBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
|
||||
config.HardwareAddress = int.Parse(hwAddressTextBox.Text);
|
||||
config.DisplayTerminal = displayTerminalCheckBox.Checked;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "Invalid 'Parent Name'";
|
||||
}
|
||||
if (!int.TryParse(hwAddressTextBox.Text, out dummy) || dummy < 0 || dummy > 63)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'HW Address' should be between 0 and 63";
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
147
TestBenchFramework/BenchControl/Network/Camera/CLP1611/CameraCfgCtrl.designer.cs
generated
Normal file
147
TestBenchFramework/BenchControl/Network/Camera/CLP1611/CameraCfgCtrl.designer.cs
generated
Normal file
@ -0,0 +1,147 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.BenchControl.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.bitPositionLabel = 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.SuspendLayout();
|
||||
//
|
||||
// hwAddressTextBox
|
||||
//
|
||||
this.hwAddressTextBox.Enabled = false;
|
||||
this.hwAddressTextBox.Location = new System.Drawing.Point(122, 99);
|
||||
this.hwAddressTextBox.Name = "hwAddressTextBox";
|
||||
this.hwAddressTextBox.Size = new System.Drawing.Size(46, 20);
|
||||
this.hwAddressTextBox.TabIndex = 6;
|
||||
//
|
||||
// bitPositionLabel
|
||||
//
|
||||
this.bitPositionLabel.AutoSize = true;
|
||||
this.bitPositionLabel.Location = new System.Drawing.Point(36, 102);
|
||||
this.bitPositionLabel.Name = "bitPositionLabel";
|
||||
this.bitPositionLabel.Size = new System.Drawing.Size(67, 13);
|
||||
this.bitPositionLabel.TabIndex = 5;
|
||||
this.bitPositionLabel.Text = "HW Address";
|
||||
//
|
||||
// parentNameLabel
|
||||
//
|
||||
this.parentNameLabel.AutoSize = true;
|
||||
this.parentNameLabel.Location = new System.Drawing.Point(36, 76);
|
||||
this.parentNameLabel.Name = "parentNameLabel";
|
||||
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
|
||||
this.parentNameLabel.TabIndex = 3;
|
||||
this.parentNameLabel.Text = "Parent Name";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(122, 47);
|
||||
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(36, 50);
|
||||
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(119, 21);
|
||||
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(122, 73);
|
||||
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(122, 128);
|
||||
this.displayTerminalCheckBox.Name = "displayTerminalCheckBox";
|
||||
this.displayTerminalCheckBox.Size = new System.Drawing.Size(99, 17);
|
||||
this.displayTerminalCheckBox.TabIndex = 13;
|
||||
this.displayTerminalCheckBox.Text = "Display terminal";
|
||||
this.displayTerminalCheckBox.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// CameraCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.displayTerminalCheckBox);
|
||||
this.Controls.Add(this.parentNameComboBox);
|
||||
this.Controls.Add(this.hwAddressTextBox);
|
||||
this.Controls.Add(this.bitPositionLabel);
|
||||
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(300, 200);
|
||||
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 bitPositionLabel;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.CLP1611
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
|
||||
|
||||
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(17), this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(typeof(CameraCfg), component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
using TBF.BenchControl.Network.Telnet;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.CLP1611
|
||||
{
|
||||
public class LiveStreamOp : IOperation
|
||||
{
|
||||
readonly Camera camera;
|
||||
readonly Telnet.TelnetClient telnet;
|
||||
|
||||
bool liveStreamCommandSent;
|
||||
|
||||
/// <summary>
|
||||
/// Events: Event.None or Event.Error
|
||||
/// </summary>
|
||||
/// <param name="camera">CLP1611.Camera reference</param>
|
||||
public LiveStreamOp(Camera camera, Telnet.TelnetClient telnet)
|
||||
{
|
||||
this.camera = camera;
|
||||
this.telnet = telnet;
|
||||
}
|
||||
|
||||
|
||||
public void Start()
|
||||
{
|
||||
liveStreamCommandSent = false;
|
||||
}
|
||||
|
||||
public Event Run()
|
||||
{
|
||||
if (!liveStreamCommandSent)
|
||||
{
|
||||
if (telnet.State == TelnetClient.TelnetState.Inactive)
|
||||
{
|
||||
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_STRING, "clp/livestream.sh"));
|
||||
liveStreamCommandSent = true;
|
||||
}
|
||||
}
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (liveStreamCommandSent)
|
||||
{
|
||||
telnet.Enqueue(new Telnet.Command(Telnet.CmdAction.SEND_COMMAND, Telnet.TelnetClient.CtrlCCommand));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
TestBenchFramework/BenchControl/Network/Camera/CLP1611/TerminalDlg.Designer.cs
generated
Normal file
62
TestBenchFramework/BenchControl/Network/Camera/CLP1611/TerminalDlg.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
||||
namespace TBF.BenchControl.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,55 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using TBF.BenchControl.Network.Telnet;
|
||||
|
||||
namespace TBF.BenchControl.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;
|
||||
}
|
||||
|
||||
|
||||
delegate void CloseDlgDlgt(); /// Delegate of void Fn(void) function
|
||||
|
||||
public void CloseDlg()
|
||||
{
|
||||
if (dlgLoaded)
|
||||
{
|
||||
Invoke(new CloseDlgDlgt(OnCloseDlg));
|
||||
}
|
||||
}
|
||||
|
||||
void OnCloseDlg()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -0,0 +1,26 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System.Collections.Generic;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.RoI
|
||||
{
|
||||
public class Factory : IComponentFactory
|
||||
{
|
||||
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
|
||||
|
||||
public void ResetStaticProperties() { RoI.ResetStaticProperties(); }
|
||||
|
||||
public IComponent DummyComponent() { return new RoI(); }
|
||||
|
||||
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new RoI(cfg, components); }
|
||||
|
||||
public IComponentCfg DefaultConfig() { return new RoICfg(this.GetType().Namespace.Substring(17), this); }
|
||||
|
||||
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
|
||||
{
|
||||
return ComponentCfgBase.CreateFromDbEntity(typeof(RoICfg), component, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
TestBenchFramework/BenchControl/Network/Camera/RoI/RoI.cs
Normal file
32
TestBenchFramework/BenchControl/Network/Camera/RoI/RoI.cs
Normal file
@ -0,0 +1,32 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using log4net;
|
||||
using Config.Entities;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.RoI
|
||||
{
|
||||
public class RoI : ComponentBase
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(RoI));
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}({1})", this.GetType().Namespace.Substring(17), Cfg.ToString(1));
|
||||
}
|
||||
|
||||
protected readonly RoICfg roiCfg;
|
||||
|
||||
public RoI()
|
||||
{
|
||||
}
|
||||
|
||||
public RoI(Generic.IComponentCfg cfg, IList<Generic.IComponent> components)
|
||||
: base(cfg)
|
||||
{
|
||||
roiCfg = cfg as RoICfg;
|
||||
log.Debug(this.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
34
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfg.cs
Normal file
34
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfg.cs
Normal file
@ -0,0 +1,34 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.RoI
|
||||
{
|
||||
public class RoICfg : ComponentCfgBase, IChildComponentCfg
|
||||
{
|
||||
public IComponentCfgCtrl GetControl() { return new RoICfgCtrl(); }
|
||||
|
||||
///
|
||||
/// Serialized parameters
|
||||
///
|
||||
public int HardwareAddress;
|
||||
|
||||
/// Private parameterless constructor invoked by all other (public) constructors
|
||||
RoICfg() { }
|
||||
|
||||
public RoICfg(string name, IComponentFactory factory)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
Factory = factory;
|
||||
ParentName = "Network.Camera";
|
||||
HardwareAddress = 1;
|
||||
}
|
||||
|
||||
public string ToString(int i)
|
||||
{
|
||||
return string.Format("Name={0}, HWAddr={1}", Name, HardwareAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
106
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfgCtrl.cs
Normal file
106
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfgCtrl.cs
Normal file
@ -0,0 +1,106 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using TBF.BenchControl.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Camera.RoI
|
||||
{
|
||||
public partial class RoICfgCtrl : UserControl, IComponentCfgCtrl
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger(typeof(RoICfgCtrl));
|
||||
|
||||
ComponentParametersDlg parent;
|
||||
|
||||
public bool ShowMore { get { return false; } }
|
||||
|
||||
RoICfg config;
|
||||
public IComponentCfg Config
|
||||
{
|
||||
get { return config as IComponentCfg; }
|
||||
set
|
||||
{
|
||||
config = value as RoICfg;
|
||||
Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
public RoICfgCtrl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void PumpCfgCtrl_Load(object sender, EventArgs e)
|
||||
{
|
||||
parent = ParentForm as ComponentParametersDlg;
|
||||
if (parent == null) return;
|
||||
|
||||
if (parent.TbfComponents != null)
|
||||
{
|
||||
foreach (var cmpnt in parent.TbfComponents)
|
||||
{
|
||||
if (TbfComponents.CmpntFactoryFromClassName(cmpnt.ClassName) is TBF.BenchControl.Network.Camera.CLP1611.Factory)
|
||||
{
|
||||
parentNameComboBox.Items.Add(cmpnt.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public void Unlock()
|
||||
{
|
||||
nameTextBox.Enabled = true;
|
||||
parentNameComboBox.Enabled = true;
|
||||
hwAddressTextBox.Enabled = true;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags UpdateCfg()
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.RestartRqrd;
|
||||
|
||||
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
|
||||
|
||||
config.Name = nameTextBox.Text;
|
||||
config.ParentName = parentNameComboBox.Text.Equals("---") ? string.Empty : parentNameComboBox.Text;
|
||||
config.HardwareAddress = int.Parse(hwAddressTextBox.Text);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public CfgUpdateFlags VerifyCfg(ref string message)
|
||||
{
|
||||
CfgUpdateFlags flags = CfgUpdateFlags.None;
|
||||
|
||||
int dummy;
|
||||
if (!parentNameComboBox.Items.Contains(parentNameComboBox.Text))
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "Invalid 'Parent Name'";
|
||||
}
|
||||
if (!int.TryParse(hwAddressTextBox.Text, out dummy) || dummy < 1 || dummy > 63)
|
||||
{
|
||||
flags |= CfgUpdateFlags.Error;
|
||||
message += Environment.NewLine + "'HW Address' should be between 1 and 63";
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
133
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfgCtrl.designer.cs
generated
Normal file
133
TestBenchFramework/BenchControl/Network/Camera/RoI/RoICfgCtrl.designer.cs
generated
Normal file
@ -0,0 +1,133 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
namespace TBF.BenchControl.Network.Camera.RoI
|
||||
{
|
||||
partial class RoICfgCtrl
|
||||
{
|
||||
/// <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.bitPositionLabel = 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.SuspendLayout();
|
||||
//
|
||||
// hwAddressTextBox
|
||||
//
|
||||
this.hwAddressTextBox.Enabled = false;
|
||||
this.hwAddressTextBox.Location = new System.Drawing.Point(122, 99);
|
||||
this.hwAddressTextBox.Name = "hwAddressTextBox";
|
||||
this.hwAddressTextBox.Size = new System.Drawing.Size(46, 20);
|
||||
this.hwAddressTextBox.TabIndex = 6;
|
||||
//
|
||||
// bitPositionLabel
|
||||
//
|
||||
this.bitPositionLabel.AutoSize = true;
|
||||
this.bitPositionLabel.Location = new System.Drawing.Point(36, 102);
|
||||
this.bitPositionLabel.Name = "bitPositionLabel";
|
||||
this.bitPositionLabel.Size = new System.Drawing.Size(67, 13);
|
||||
this.bitPositionLabel.TabIndex = 5;
|
||||
this.bitPositionLabel.Text = "HW Address";
|
||||
//
|
||||
// parentNameLabel
|
||||
//
|
||||
this.parentNameLabel.AutoSize = true;
|
||||
this.parentNameLabel.Location = new System.Drawing.Point(36, 76);
|
||||
this.parentNameLabel.Name = "parentNameLabel";
|
||||
this.parentNameLabel.Size = new System.Drawing.Size(69, 13);
|
||||
this.parentNameLabel.TabIndex = 3;
|
||||
this.parentNameLabel.Text = "Parent Name";
|
||||
//
|
||||
// nameTextBox
|
||||
//
|
||||
this.nameTextBox.Enabled = false;
|
||||
this.nameTextBox.Location = new System.Drawing.Point(122, 47);
|
||||
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(36, 50);
|
||||
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(119, 21);
|
||||
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(122, 73);
|
||||
this.parentNameComboBox.Name = "parentNameComboBox";
|
||||
this.parentNameComboBox.Size = new System.Drawing.Size(130, 21);
|
||||
this.parentNameComboBox.TabIndex = 4;
|
||||
//
|
||||
// CameraCfgCtrl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.parentNameComboBox);
|
||||
this.Controls.Add(this.hwAddressTextBox);
|
||||
this.Controls.Add(this.bitPositionLabel);
|
||||
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(300, 200);
|
||||
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 bitPositionLabel;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
124
TestBenchFramework/BenchControl/Network/Telnet/Command.cs
Normal file
124
TestBenchFramework/BenchControl/Network/Telnet/Command.cs
Normal file
@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace TBF.BenchControl.Network.Telnet
|
||||
{
|
||||
/// <summary>
|
||||
/// One part of the telnet client command, which consists of a pair CmdAction action and string str.
|
||||
/// </summary>
|
||||
public enum CmdAction
|
||||
{
|
||||
VOID = 0, /// Blank (uninitialized) action. 'str' is not used.
|
||||
CONNECT, /// Connect (=open a TCP socket and log in). 'str'=hostname. Notify by 'Connected' event.
|
||||
SET_PROMPT, /// Set a prompt string used in comparisons when executing ..._WAIT4PROMPT. 'str'=prompt.
|
||||
CLEAR_RESPONSE, /// Clear received response buffer. 'str' is not used. Note: Response buffer is cleared also after a detected prompt.
|
||||
SEND_STRING, /// Send string and do nothing else. 'str'=string to be sent.
|
||||
SEND_COMMAND, /// Send string and WAIT for a PROMPT. 'str'=string to be sent. Notify by 'PromptReceived' event.
|
||||
REBOOT_RECONNECT, /// Send 'reboot' command (if connected), wait a while and reconect. 'str' is not used. Notify by 'Connected' event.
|
||||
EXIT_RECONNECT, /// Send 'exit' (terminate telnet session) and reconect. 'str' is not used. Notify using 'Connected' event.
|
||||
DISCONNECT, /// Send 'exit' to disconnect, do not reconnect. 'str' is not used.
|
||||
TERMINATE, /// Terminate worker thread (should be done once before TelnetClient destruction. 'str' is not used.
|
||||
LABEL, /// Label marking the start of item commands, 'str' identifies the item.
|
||||
NOTIFICATION, /// Notify by 'Notification' event when this command is processed. 'str'=notification ID-string
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Telnet client command. Consists of a pair 'action', 'str'
|
||||
/// CmdAction 'action' specifies the action to be taken.
|
||||
/// string 'str' is (in most cases) the string to be sent, however it might be a hostname or a prompt.
|
||||
/// </summary>
|
||||
public struct Command
|
||||
{
|
||||
/// Private fields
|
||||
CmdAction action; /// Telnet client action to be taken, e.g. 'send a command'
|
||||
string str; /// String argument, e.g. a Linux command to be sent.
|
||||
int duration; /// Expected duration of the command in [s], 0 = immediate, -1 = unknown
|
||||
int timeout; /// Timeout period for the command in [s], 0 = no timeout
|
||||
Regex fatalRegex; /// A compiled regular expression for a fatal error, or null (null=no fatal error detection)
|
||||
Regex errorRegex; /// A compiled regular expression for an error, or null (null=no error detection)
|
||||
Regex warningRegex; /// A compiled regular expression for a warning, or null (null=no warning detection)
|
||||
Regex successRegex; /// A compiled regular expression for a success, or null (null=no success detection)
|
||||
|
||||
/// Public read only properties
|
||||
public CmdAction Action { get { return action; } }
|
||||
public string Str { get { return str; } }
|
||||
public int Duration { get { return duration; } }
|
||||
public int Timeout { get { return timeout; } }
|
||||
public Regex FatalRegex { get { return fatalRegex; } }
|
||||
public Regex ErrorRegex { get { return errorRegex; } }
|
||||
public Regex WarningRegex { get { return warningRegex; } }
|
||||
public Regex SuccessRegex { get { return successRegex; } }
|
||||
|
||||
///
|
||||
/// Various constructors:
|
||||
/// - duration and timeout are in seconds
|
||||
/// - if timeout and duration is not supplied, timeout=0, duration=0 (timeout switched off)
|
||||
/// - if string is not supplied, null is used
|
||||
///
|
||||
public Command(CmdAction action, string str, int duration, int timeout,
|
||||
Regex fatalRegex, Regex errorRegex, Regex warningRegex, Regex successRegex)
|
||||
{
|
||||
this.action = action;
|
||||
this.str = str;
|
||||
this.duration = duration;
|
||||
this.timeout = timeout;
|
||||
this.fatalRegex = fatalRegex;
|
||||
this.errorRegex = errorRegex;
|
||||
this.warningRegex = warningRegex;
|
||||
this.successRegex = successRegex;
|
||||
}
|
||||
|
||||
public Command(CmdAction action, string str, int duration, int timeout)
|
||||
: this(action, str, duration, timeout, null, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public Command(CmdAction action, string str)
|
||||
: this(action, str, 0, 0, null, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public Command(CmdAction action, int duration, int timeout)
|
||||
: this(action, null, duration, timeout, null, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public Command(CmdAction action)
|
||||
: this(action, null, 0, 0, null, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For debugging purposes.
|
||||
/// </summary>
|
||||
/// <returns>A name of Command.action</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
string result = action.ToString();
|
||||
|
||||
if (str != null)
|
||||
{
|
||||
result += ", \"" + str + "\"";
|
||||
}
|
||||
|
||||
if (action == CmdAction.CONNECT ||
|
||||
action == CmdAction.REBOOT_RECONNECT ||
|
||||
action == CmdAction.EXIT_RECONNECT ||
|
||||
action == CmdAction.SEND_COMMAND)
|
||||
{
|
||||
result += ", timeout=" + timeout.ToString() + "s";
|
||||
}
|
||||
|
||||
if (action == CmdAction.SEND_COMMAND)
|
||||
{
|
||||
if (fatalRegex != null) { result += ", fatal=" + fatalRegex.ToString(); }
|
||||
if (errorRegex != null) { result += ", error=" + errorRegex.ToString(); }
|
||||
if (warningRegex != null) { result += ", warning=" + warningRegex.ToString(); }
|
||||
if (successRegex != null) { result += ", success=" + successRegex.ToString(); }
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TBF.BenchControl.Network.Telnet
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of argument of FatalEventHandler
|
||||
/// </summary>
|
||||
public class FatalEventArgs : EventArgs
|
||||
{
|
||||
public string FatalErrorText; /// Fatal error description messages.
|
||||
|
||||
public FatalEventArgs(string text)
|
||||
{
|
||||
FatalErrorText = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Type of argument of NotificationEventHandler
|
||||
/// </summary>
|
||||
public class NotificationEventArgs : EventArgs
|
||||
{
|
||||
public string NotificationText; /// String identifying this notification more closely.
|
||||
|
||||
public NotificationEventArgs(string text)
|
||||
{
|
||||
NotificationText = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Type of argument of PromptReceviedEventHandler
|
||||
/// </summary>
|
||||
public class PromptReceivedEventArgs : EventArgs
|
||||
{
|
||||
public string Response; /// Response to a command from the telnet server ...
|
||||
/// ... without the terminal prompt string.
|
||||
|
||||
public PromptReceivedEventArgs(string text)
|
||||
{
|
||||
Response = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Type of argument of VtTextChangedEventHandler
|
||||
/// </summary>
|
||||
public class VtTextChangedEventArgs : EventArgs
|
||||
{
|
||||
public string VtText; // Virtual terminal text.
|
||||
|
||||
public VtTextChangedEventArgs(string text)
|
||||
{
|
||||
VtText = text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used as a part of AuxBrdUpgItemMessage
|
||||
/// </summary>
|
||||
public enum Category
|
||||
{
|
||||
Error,
|
||||
Warning,
|
||||
Success,
|
||||
}
|
||||
/// <summary>
|
||||
/// A pair containing Aux Board Upgrade item identification and a message
|
||||
/// (fatal error, error, warning or success message).
|
||||
/// </summary>
|
||||
public class AuxBrdUpgItemMessage
|
||||
{
|
||||
public Category Category; /// Error, Warning or Success
|
||||
public string Label; /// Identifies the aux.board upgrade item
|
||||
public string Message; /// The message
|
||||
|
||||
public AuxBrdUpgItemMessage(Category category, string label, string message)
|
||||
{
|
||||
Category = category;
|
||||
Label = label;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Type of argument of SummaryEventArgs
|
||||
/// </summary>
|
||||
public class SummaryEventArgs : EventArgs
|
||||
{
|
||||
public IList<AuxBrdUpgItemMessage> SummaryMessages; /// Event description messages.
|
||||
|
||||
public SummaryEventArgs(IList<AuxBrdUpgItemMessage> summaryMessages)
|
||||
{
|
||||
this.SummaryMessages = summaryMessages;
|
||||
}
|
||||
}
|
||||
}
|
||||
1300
TestBenchFramework/BenchControl/Network/Telnet/TelnetClient.cs
Normal file
1300
TestBenchFramework/BenchControl/Network/Telnet/TelnetClient.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,233 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TBF.BenchControl.Network.Telnet
|
||||
{
|
||||
/// <summary>
|
||||
/// Virtual terminal (an array of characters).
|
||||
/// This class is thread safe under these circumstances:
|
||||
/// - ClearScreen() and WriteVt() methods called from one thread only
|
||||
/// - properties Text, etc. can be safely read from an arbitrary thread
|
||||
/// </summary>
|
||||
public class VirtualTerminal
|
||||
{
|
||||
const uint DefaultVtRowsCount = 80; /// Default VT height (number of rows)
|
||||
const uint DefaultVtColumnsCount = 132; /// Default VT width (number of columns)
|
||||
|
||||
/// <summary>
|
||||
/// Virtual terminal special characters.
|
||||
/// <seealso cref = http://support.microsoft.com/kb/231866 />
|
||||
/// </summary>
|
||||
enum SpecialChar
|
||||
{
|
||||
BS = 8, /// 8 = Backspace (move one position to the left)
|
||||
HT, /// 9 = Horizontal tab
|
||||
LF, /// 10 = Line feed
|
||||
VT, /// 11 = Vertical tab
|
||||
FF, /// 12 = Form feed (on visual displays most commonly clears the screen)
|
||||
CR /// 13 = Carriage return
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Public properties
|
||||
///
|
||||
public uint Rows { get { return vtRows; } }
|
||||
public uint Columns { get { return vtColumns; } }
|
||||
public uint CurRow { get { return curRow; } }
|
||||
public uint CurColumn { get { return curColumn; } }
|
||||
|
||||
/// <summary>
|
||||
/// Virtual terminal text buffer as a single string. To be printed out using monospaced font.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
string result = "";
|
||||
char[] oneRow = new char[vtColumns];
|
||||
|
||||
for (int row = 0; row < vtRows; row++)
|
||||
{
|
||||
for (int column = 0; column < vtColumns; column++)
|
||||
{
|
||||
oneRow[column] = vt[row, column];
|
||||
}
|
||||
result += new String(oneRow);
|
||||
|
||||
/// New line at the end of each line except of the last one
|
||||
if (row < vtRows - 1) result += System.Environment.NewLine;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Private fields
|
||||
///
|
||||
char[,] vt; /// Virtual terminal text buffer
|
||||
uint vtRows = 0; /// VT height (number of rows)
|
||||
uint vtColumns = 0; /// VT width (number of columns)
|
||||
uint curRow = 0; /// Current row (cursor position)
|
||||
uint curColumn = 0; /// Current column (cursor position)
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
public VirtualTerminal()
|
||||
{
|
||||
vt = new char[DefaultVtRowsCount, DefaultVtColumnsCount];
|
||||
if (vt != null)
|
||||
{
|
||||
vtRows = DefaultVtRowsCount;
|
||||
vtColumns = DefaultVtColumnsCount;
|
||||
ClearScreen();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary VT size constructor.
|
||||
/// </summary>
|
||||
public VirtualTerminal(uint nrRows, uint nrColumns)
|
||||
{
|
||||
vt = new char[nrRows, nrColumns];
|
||||
if (vt != null)
|
||||
{
|
||||
vtRows = nrRows;
|
||||
vtColumns = nrColumns;
|
||||
ClearScreen();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear VT.
|
||||
/// </summary>
|
||||
public void ClearScreen()
|
||||
{
|
||||
for (uint row = 0; row < vtRows; row++)
|
||||
{
|
||||
for (uint column = 0; column < vtColumns; column++)
|
||||
{
|
||||
vt[row, column] = ' ';
|
||||
}
|
||||
}
|
||||
curRow = 0;
|
||||
curColumn = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scroll VT one line up and clear the bottom line.
|
||||
/// </summary>
|
||||
void ScrollUp()
|
||||
{
|
||||
for (uint row = 0; row < vtRows - 1; row++)
|
||||
{
|
||||
for (uint column = 0; column < vtColumns; column++)
|
||||
{
|
||||
vt[row, column] = vt[row + 1, column];
|
||||
}
|
||||
}
|
||||
for (uint column = 0; column < vtColumns; column++)
|
||||
{
|
||||
vt[vtRows - 1, column] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write one regular printable character to VC.
|
||||
/// </summary>
|
||||
void WritePrintableChar(char c)
|
||||
{
|
||||
vt[curRow, curColumn] = c;
|
||||
if (curColumn < vtColumns - 1)
|
||||
{
|
||||
curColumn++;
|
||||
}
|
||||
else if (curRow < vtRows - 1)
|
||||
{
|
||||
curRow++;
|
||||
curColumn = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollUp();
|
||||
curRow = vtRows - 1;
|
||||
curColumn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write one character to VT (regular or special).
|
||||
/// </summary>
|
||||
public void WriteVt(char c)
|
||||
{
|
||||
if (c >= 32 && c <= 127)
|
||||
{
|
||||
WritePrintableChar(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((SpecialChar)c)
|
||||
{
|
||||
/// Carriage return
|
||||
case SpecialChar.CR:
|
||||
curColumn = 0;
|
||||
break;
|
||||
|
||||
/// Line feed
|
||||
case SpecialChar.LF:
|
||||
if (curRow < vtRows - 1)
|
||||
{
|
||||
curRow++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollUp();
|
||||
curRow = vtRows - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
/// Form feed (= clear screen)
|
||||
case SpecialChar.FF:
|
||||
ClearScreen();
|
||||
break;
|
||||
|
||||
/// Backspace
|
||||
case SpecialChar.BS:
|
||||
if (curColumn > 0)
|
||||
{
|
||||
vt[curRow, --curColumn] = ' ';
|
||||
}
|
||||
else if (curRow > 0)
|
||||
{
|
||||
curColumn = vtColumns - 1;
|
||||
vt[--curRow, curColumn] = ' ';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a string to VT.
|
||||
/// </summary>
|
||||
public void WriteVt(string txt)
|
||||
{
|
||||
if (txt != null)
|
||||
{
|
||||
for (int i = 0; i < txt.Length; i++)
|
||||
{
|
||||
WriteVt(txt[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
688
TestBenchFramework/BenchControl/Network/Tftp/TftpServer.cs
Normal file
688
TestBenchFramework/BenchControl/Network/Tftp/TftpServer.cs
Normal file
@ -0,0 +1,688 @@
|
||||
///
|
||||
/// Copyright (c) 2017 Sensus Metering Systems
|
||||
///
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using log4net;
|
||||
|
||||
namespace TBF.BenchControl.Network.Tftp
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple TFTP Server
|
||||
/// </summary>
|
||||
public class TftpServer
|
||||
{
|
||||
static readonly ILog log = LogManager.GetLogger("TftpServer");
|
||||
|
||||
const ushort DefaultTftpPortNr = 69;
|
||||
const int TftpHeaderLength = 4;
|
||||
const int TftpDataBlockLength = 512;
|
||||
readonly char[] Delimiter = new char[] { '\0' }; /// Delimits filename, transfer mode and error message in UDP packets
|
||||
|
||||
/// <summary>
|
||||
/// TFTP server request modes
|
||||
/// </summary>
|
||||
enum RequestMode
|
||||
{
|
||||
BinaryRead,
|
||||
BinaryWrite,
|
||||
AsciiRead,
|
||||
AsciiWrite,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opcodes identifying TFTP packets
|
||||
/// </summary>
|
||||
enum Opcode : short
|
||||
{
|
||||
RRQ = 01, /// Read request packet.
|
||||
WRQ = 02, /// Write request packet.
|
||||
DATA = 03, /// Data packet.
|
||||
ACK = 04, /// Acknowledgement packet.
|
||||
ERROR = 05, /// Wrror packet.
|
||||
OACK = 06 /// Option acknowledgement packet.
|
||||
}
|
||||
|
||||
/// Strings included in RRQ/WRQ packets
|
||||
const string REQUEST_MODE_NETASCII = "netascii";
|
||||
const string REQUEST_MODE_BINARY = "octet";
|
||||
|
||||
/// <summary>
|
||||
/// Error codes included in ERROR packet
|
||||
/// </summary>
|
||||
enum ErrorCode : short
|
||||
{
|
||||
NO_ERROR = 0, /// Not defined, see error message (if any).
|
||||
ERROR_FILE_NOT_FOUND = 1, /// File not found.
|
||||
ERROR_ACCESS_VIOLATION = 2, /// Access violation.
|
||||
ERROR_ALLOC_ERROR = 3, /// Disk full or allocation exceeded.
|
||||
ERROR_ILLEGAL_OP = 4, /// Illegal TFTP operation.
|
||||
ERROR_UNKNOWN_TID = 5, /// Unknown transfer ID.
|
||||
ERROR_FILE_EXISTS = 6, /// File already exists.
|
||||
ERROR_INVALID_USER = 7, /// No such user.
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Single file transfer related class
|
||||
///
|
||||
class FileTransfer
|
||||
{
|
||||
public IPEndPoint Endpoint { get { return endpoint; } }
|
||||
IPEndPoint endpoint;
|
||||
|
||||
public string Filename { get { return filename; } }
|
||||
string filename;
|
||||
|
||||
public RequestMode Mode { get { return mode; } }
|
||||
RequestMode mode;
|
||||
|
||||
public System.IO.Stream Stream;
|
||||
public BinaryReader StreamReader;
|
||||
public BinaryWriter StreamWriter;
|
||||
public int CurrentBlock;
|
||||
public int LastSentDataLength;
|
||||
|
||||
public FileTransfer(IPEndPoint endpoint, string filename, RequestMode mode)
|
||||
{
|
||||
this.endpoint = endpoint;
|
||||
this.filename = filename;
|
||||
this.mode = mode;
|
||||
|
||||
Stream = null;
|
||||
StreamReader = null;
|
||||
StreamWriter = null;
|
||||
CurrentBlock = (mode == RequestMode.BinaryRead ? 1 : 0);
|
||||
LastSentDataLength = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IPEndPoint can be used as a key as there is max. one file transfer for each endpoint.
|
||||
/// </summary>
|
||||
/// <param name="ep">IP endpoint</param>
|
||||
/// <param name="list">List of FileTransfer-s</param>
|
||||
/// <returns></returns>
|
||||
public static FileTransfer Find(IPEndPoint ep, IList<FileTransfer> list)
|
||||
{
|
||||
if (list == null) return null;
|
||||
foreach (FileTransfer ft in list)
|
||||
{
|
||||
if ((ft.endpoint.Address.Equals(ep.Address)) && (ft.endpoint.Port.Equals(ep.Port)))
|
||||
{
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FileTransfer Close() closes open streams.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (StreamReader != null) StreamReader.Close();
|
||||
if (StreamWriter != null) StreamWriter.Close();
|
||||
if (Stream != null) Stream.Close();
|
||||
}
|
||||
|
||||
/// For debugging.
|
||||
public override string ToString()
|
||||
{
|
||||
return "[" + endpoint.ToString() + "," + filename + "," + mode.ToString() +
|
||||
",block=" + CurrentBlock.ToString() + ",last=" + LastSentDataLength.ToString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// TFTP server instance related instance fields
|
||||
///
|
||||
string tftpDirectory; /// TFTP root directory
|
||||
int listenPort; /// UDP port to listen to
|
||||
UdpClient udpClient;
|
||||
Thread listenThread;
|
||||
bool done; /// Flag to finish listenThread
|
||||
IList<FileTransfer> fileTransfers; /// Current file transfers (max. one transfer for each endpoint)
|
||||
|
||||
|
||||
public TftpServer()
|
||||
{
|
||||
tftpDirectory = null;
|
||||
udpClient = null; /// UDP client
|
||||
listenThread = null; /// Listen thread
|
||||
done = false; /// Flag to finish listenThread
|
||||
fileTransfers = null; /// No file transfer
|
||||
}
|
||||
|
||||
|
||||
#region Event handler
|
||||
|
||||
public class NotificationEventArgs : EventArgs
|
||||
{
|
||||
public string Message;
|
||||
public IPAddress IP;
|
||||
public string FileName;
|
||||
|
||||
public NotificationEventArgs(string message, IPAddress ip, string filename)
|
||||
{
|
||||
this.Message = message;
|
||||
this.IP = ip;
|
||||
this.FileName = filename;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void NotificationEventHandler(object sender, NotificationEventArgs args);
|
||||
|
||||
public static event NotificationEventHandler NotificationHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a log and invokes notification handlers (updates TFTP tab-page).
|
||||
/// </summary>
|
||||
/// <param name="message">Notification text start</param>
|
||||
/// <param name="fileTransfer">File transfer object reference or null</param>
|
||||
/// <param name="logType">Logger log type </param>
|
||||
void OnNotify(string message, FileTransfer fileTransfer, log4net.Core.Level level)
|
||||
{
|
||||
/// Write a log
|
||||
IPAddress ip = null;
|
||||
string filename = null;
|
||||
string logStr = message;
|
||||
|
||||
if (fileTransfer != null)
|
||||
{
|
||||
ip = fileTransfer.Endpoint.Address;
|
||||
filename = fileTransfer.Filename;
|
||||
logStr = string.Format("{0} IP={1}, filename={2}", message, ip, filename);
|
||||
}
|
||||
|
||||
if (level == log4net.Core.Level.Debug)
|
||||
log.Debug(logStr);
|
||||
else if (level == log4net.Core.Level.Info)
|
||||
log.Info(logStr);
|
||||
else if (level == log4net.Core.Level.Warn)
|
||||
log.Warn(logStr);
|
||||
else if (level == log4net.Core.Level.Error)
|
||||
log.Error(logStr);
|
||||
else if (level == log4net.Core.Level.Fatal || level == log4net.Core.Level.All)
|
||||
log.Fatal(logStr);
|
||||
|
||||
/// Notification: invoke handlers
|
||||
if (NotificationHandler != null)
|
||||
{
|
||||
NotificationHandler(null, new NotificationEventArgs(message, ip, filename));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start TFTP server
|
||||
/// </summary>
|
||||
/// <param name="tftpDirectory">TFTP root directory</param>
|
||||
/// <param name="netAdapterInfo">Network adadpter to listen to, null=listen to all net.adapters</param>
|
||||
/// <returns>true = TFTP is running, false = TFTP start failed</returns>
|
||||
public bool Start(string tftpDirectory, IPAddress ipAddress)
|
||||
{
|
||||
if (!Directory.Exists(tftpDirectory)) return false; /// TFTP root directory does not exist
|
||||
if (!tftpDirectory.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
tftpDirectory += Path.DirectorySeparatorChar.ToString();
|
||||
}
|
||||
this.tftpDirectory = tftpDirectory;
|
||||
this.listenPort = DefaultTftpPortNr;
|
||||
|
||||
if (udpClient != null) return false; /// TFTP server is already running
|
||||
try
|
||||
{
|
||||
if (ipAddress != null)
|
||||
{
|
||||
IPEndPoint listenEndpoint = new IPEndPoint(ipAddress, listenPort);
|
||||
udpClient = new UdpClient(listenEndpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
udpClient = new UdpClient(listenPort, AddressFamily.InterNetwork);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false; /// Cannot open UDP port (is another TFTP running?)
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileTransfers = new List<FileTransfer>();
|
||||
listenThread = new Thread(new ThreadStart(Listener));
|
||||
listenThread.Name = "TftpServer"; /// Is used as a log file root name
|
||||
listenThread.Start();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop TFTP server
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
done = true;
|
||||
|
||||
if (udpClient != null)
|
||||
{
|
||||
udpClient.Close();
|
||||
udpClient = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/// Close the open file streams
|
||||
if (fileTransfers != null)
|
||||
{
|
||||
foreach (FileTransfer ft in fileTransfers) ft.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.FatalFormat("Fatal error in Stop(): {0}", ex.Message);
|
||||
}
|
||||
fileTransfers = null;
|
||||
}
|
||||
|
||||
|
||||
#region Listner thread section
|
||||
|
||||
/// <summary>
|
||||
/// Get readable string describing the packet.
|
||||
/// </summary>
|
||||
/// <param name="data">TFTP packet</param>
|
||||
/// <param name="actualLength">Number of valid byted in array data</param>
|
||||
/// <returns>description</returns>
|
||||
string GetDebugMessage(Byte[] data, int actualLength)
|
||||
{
|
||||
if (data == null || data.Length < actualLength || actualLength < TftpHeaderLength) return "[invalid packet]";
|
||||
|
||||
Opcode opcode = (Opcode)((((short)data[0]) * 256) + (short)data[1]);
|
||||
|
||||
if (opcode == Opcode.RRQ || opcode == Opcode.WRQ)
|
||||
{
|
||||
Encoding ASCII = Encoding.ASCII;
|
||||
string[] strData = ASCII.GetString(data, 2, data.Length - 2).Split(Delimiter, 3);
|
||||
string filename = strData[0];
|
||||
string mode = strData[1].ToLower();
|
||||
|
||||
return "[" + opcode.ToString() + " filename=" + filename + ", mode=" + mode + "]";
|
||||
}
|
||||
|
||||
int number = data[2] * 256 + data[3];
|
||||
|
||||
if (actualLength > TftpHeaderLength)
|
||||
{
|
||||
return "[" + opcode.ToString() + " + " + number.ToString() + " + " + (actualLength - TftpHeaderLength).ToString() + " bytes]";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "[" + opcode.ToString() + " + " + number.ToString() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main listener thread loop
|
||||
/// </summary>
|
||||
public void Listener()
|
||||
{
|
||||
OnNotify("----- TFTP server started -----", null, log4net.Core.Level.Fatal);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPEndPoint endpoint = null;
|
||||
Byte[] data = udpClient.Receive(ref endpoint);
|
||||
|
||||
log.InfoFormat("Rcvd packet {0}", GetDebugMessage(data, data.Length));
|
||||
|
||||
///
|
||||
/// Process the packet
|
||||
///
|
||||
Opcode opcode = (Opcode)((((short)data[0]) * 256) + (short)data[1]);
|
||||
|
||||
///
|
||||
/// Find any existing file transfer with this IP endpoint
|
||||
///
|
||||
FileTransfer fileTransfer = FileTransfer.Find(endpoint, fileTransfers);
|
||||
|
||||
if (opcode == Opcode.RRQ || opcode == Opcode.WRQ)
|
||||
{
|
||||
if (fileTransfer != null)
|
||||
{
|
||||
///
|
||||
/// If there is an incomplete file transfer with this endpoint, close the open streams.
|
||||
///
|
||||
OnNotify("Forcing an incomplete file transfer to close: ", fileTransfer, log4net.Core.Level.Error);
|
||||
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
fileTransfer = null;
|
||||
}
|
||||
}
|
||||
else if (fileTransfer == null)
|
||||
{
|
||||
/// If there is no existing file transfer with this endpoint, ignore packets other then RRQ or WRQ.
|
||||
log.ErrorFormat("No matching file transfer - packet ignored: IP={0}", endpoint.Address);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case Opcode.RRQ:
|
||||
ProcessReadRequest(data, endpoint);
|
||||
break;
|
||||
|
||||
case Opcode.WRQ:
|
||||
ProcessWriteRequest(data, endpoint);
|
||||
break;
|
||||
|
||||
case Opcode.ERROR:
|
||||
ProcessError(data, fileTransfer);
|
||||
break;
|
||||
|
||||
case Opcode.ACK:
|
||||
ProcessAck(data, fileTransfer);
|
||||
break;
|
||||
|
||||
case Opcode.DATA:
|
||||
ProcessData(data, fileTransfer);
|
||||
break;
|
||||
|
||||
case Opcode.OACK:
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.FatalFormat("Fatal error in Listener(): {0}", exc.Message);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#region TFTP 'GET' section
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'Read Request' (RRQ)
|
||||
/// </summary>
|
||||
/// <param name="data">Data from RRQ packet</param>
|
||||
/// <param name="endpoint">Client IP</param>
|
||||
private void ProcessReadRequest(Byte[] data, IPEndPoint endpoint)
|
||||
{
|
||||
/// Extract a filename and a mode
|
||||
string[] strData = Encoding.ASCII.GetString(data, 2, data.Length - 2).Split(Delimiter, 3);
|
||||
string filename = strData[0];
|
||||
string mode = strData[1].ToLower();
|
||||
|
||||
if (mode == REQUEST_MODE_BINARY)
|
||||
{
|
||||
/// Create FileTransfer object, do not add it to this.fileTransfers yet
|
||||
FileTransfer fileTransfer = new FileTransfer(endpoint, filename, RequestMode.BinaryRead);
|
||||
|
||||
/// Try to open the source file
|
||||
try
|
||||
{
|
||||
fileTransfer.Stream = System.IO.File.OpenRead(tftpDirectory + filename);
|
||||
fileTransfer.StreamReader = new BinaryReader(fileTransfer.Stream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
OnNotify("Cannot open file to be uploaded: ", fileTransfer, log4net.Core.Level.Warn);
|
||||
SendError(fileTransfer, ErrorCode.ERROR_FILE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
/// File open OK, start the transfer, send the 1st data packet
|
||||
OnNotify("Uploading file: ", fileTransfer, log4net.Core.Level.Info);
|
||||
fileTransfers.Add(fileTransfer);
|
||||
SendData(fileTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new Exception("Built-in TFTP server does not support '" + mode + "' file transfer mode."));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send part of file data
|
||||
/// </summary>
|
||||
/// <param name="endpoint">location to send stream to</param>
|
||||
/// <param name="blockNumber">512 byte block to send</param>
|
||||
private void SendData(FileTransfer fileTransfer)
|
||||
{
|
||||
int fileOffset = (fileTransfer.CurrentBlock - 1) * TftpDataBlockLength;
|
||||
fileTransfer.Stream.Seek(fileOffset, SeekOrigin.Begin);
|
||||
|
||||
/// Prepare data buffer
|
||||
Byte[] buffer = new Byte[TftpDataBlockLength + TftpHeaderLength];
|
||||
buffer[0] = 0;
|
||||
buffer[1] = (byte)Opcode.DATA;
|
||||
buffer[2] = (byte)((fileTransfer.CurrentBlock & 0x0000FF00) >> 8);
|
||||
buffer[3] = (byte) (fileTransfer.CurrentBlock & 0x000000FF);
|
||||
fileTransfer.LastSentDataLength = fileTransfer.StreamReader.Read(buffer, TftpHeaderLength, TftpDataBlockLength);
|
||||
|
||||
/// Send the data packet
|
||||
int ecode = udpClient.Send(buffer, fileTransfer.LastSentDataLength + TftpHeaderLength, fileTransfer.Endpoint);
|
||||
log.InfoFormat("Sent packet {0} ecode={1}", GetDebugMessage(buffer, fileTransfer.LastSentDataLength + TftpHeaderLength), ecode);
|
||||
|
||||
/// Check the return value
|
||||
if (ecode != fileTransfer.LastSentDataLength + TftpHeaderLength)
|
||||
{
|
||||
OnNotify("Error when sending data: ecode = " + ecode.ToString() + ", ", fileTransfer, log4net.Core.Level.Error);
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle ACK response and send next block.
|
||||
/// </summary>
|
||||
/// <param name="data">data from packet</param>
|
||||
/// <param name="endpoint">client</param>
|
||||
private void ProcessAck(Byte[] data, FileTransfer fileTransfer)
|
||||
{
|
||||
int protocolBlocknum = 256 * (int)data[2] + (int)data[3];
|
||||
|
||||
/// Check the received block number, support for file size 2GB
|
||||
if (protocolBlocknum == (fileTransfer.CurrentBlock & 0xFFFF))
|
||||
{
|
||||
/// OK => Check the last data block length
|
||||
if (fileTransfer.LastSentDataLength < TftpDataBlockLength)
|
||||
{
|
||||
/// Nothing more to send, finish the transfer
|
||||
OnNotify("Upload completed: ", fileTransfer, log4net.Core.Level.Info);
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Send the next data block
|
||||
fileTransfer.CurrentBlock++;
|
||||
SendData(fileTransfer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Block number NOK => re-send the last block (without incrementing fileTransfer.CurrentBlock).
|
||||
/// This often happens when transferring large files due to iCOM performance limits.
|
||||
log.ErrorFormat("Received ACK does not match the sent block#: IP={0} ---> Re-sending", fileTransfer.Endpoint.Address);
|
||||
SendData(fileTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region TFTP 'PUT' section
|
||||
|
||||
/// <summary>
|
||||
/// Handle 'Write Request' (WRQ)
|
||||
/// </summary>
|
||||
/// <param name="data">Data from WRQ packet</param>
|
||||
/// <param name="endpoint">Client IP</param>
|
||||
private void ProcessWriteRequest(Byte[] data, IPEndPoint endpoint)
|
||||
{
|
||||
/// Extract a filename and a mode
|
||||
string[] strData = Encoding.ASCII.GetString(data, 2, data.Length - 2).Split(Delimiter, 3);
|
||||
string filename = strData[0];
|
||||
string mode = strData[1].ToLower();
|
||||
|
||||
if (mode == REQUEST_MODE_BINARY)
|
||||
{
|
||||
/// Create FileTransfer object, do not add it to this.fileTransfers yet
|
||||
FileTransfer fileTransfer = new FileTransfer(endpoint, filename, RequestMode.BinaryWrite);
|
||||
|
||||
/// Try to open the source file
|
||||
try
|
||||
{
|
||||
fileTransfer.Stream = System.IO.File.Create(tftpDirectory + filename);
|
||||
fileTransfer.StreamWriter = new BinaryWriter(fileTransfer.Stream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
OnNotify("Cannot open file to be downloaded for writing: ", fileTransfer, log4net.Core.Level.Warn);
|
||||
SendError(fileTransfer, ErrorCode.ERROR_FILE_EXISTS);
|
||||
return;
|
||||
}
|
||||
|
||||
/// File open OK, start the transfer, send the 0th acknowledge packet
|
||||
OnNotify("Downloading file: ", fileTransfer, log4net.Core.Level.Info);
|
||||
fileTransfers.Add(fileTransfer);
|
||||
SendAck(fileTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new Exception("Built-in TFTP server does not support '" + mode + "' file transfer mode."));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send acknowledge packet (ACK)
|
||||
/// </summary>
|
||||
/// <param name="fileTransfer">Current FileTransfer object</param>
|
||||
private void SendAck(FileTransfer fileTransfer)
|
||||
{
|
||||
const int AcknowledgePacketLength = 4;
|
||||
|
||||
/// Prepare the acknowledgment packet
|
||||
Byte[] buffer = new Byte[AcknowledgePacketLength];
|
||||
buffer[0] = 0;
|
||||
buffer[1] = (byte)Opcode.ACK;
|
||||
buffer[2] = (byte)((fileTransfer.CurrentBlock & 0x0000FF00) >> 8);
|
||||
buffer[3] = (byte) (fileTransfer.CurrentBlock & 0x000000FF);
|
||||
|
||||
/// Send the packet
|
||||
int ecode = udpClient.Send(buffer, AcknowledgePacketLength, fileTransfer.Endpoint);
|
||||
log.InfoFormat("Sent packet {0} ecode={1}", GetDebugMessage(buffer, AcknowledgePacketLength), ecode);
|
||||
|
||||
/// Check the return value
|
||||
if (ecode != AcknowledgePacketLength)
|
||||
{
|
||||
OnNotify("Error when sending ACK packet: ecode = " + ecode.ToString() + ", ", fileTransfer, log4net.Core.Level.Error);
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessData(Byte[] data, FileTransfer fileTransfer)
|
||||
{
|
||||
int protocolBlocknum = 256 * (int)data[2] + (int)data[3];
|
||||
|
||||
/// Check the received data block number, support max. file size 2GB
|
||||
if (protocolBlocknum != ((fileTransfer.CurrentBlock + 1) & 0xFFFF))
|
||||
{
|
||||
OnNotify("Received data block # is not consecutive --> aborting transfer: ", fileTransfer, log4net.Core.Level.Error);
|
||||
SendError(fileTransfer, ErrorCode.ERROR_UNKNOWN_TID);
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
return;
|
||||
}
|
||||
|
||||
/// Update the current block number, save and acknowledge data
|
||||
fileTransfer.CurrentBlock++;
|
||||
for (int i = TftpHeaderLength; i < data.Length; i++) fileTransfer.StreamWriter.Write(data[i]);
|
||||
SendAck(fileTransfer);
|
||||
|
||||
/// Close the file transfer if the block was the last one (data size < 512)
|
||||
if (data.Length < TftpDataBlockLength + TftpHeaderLength)
|
||||
{
|
||||
OnNotify("Download completed: ", fileTransfer, log4net.Core.Level.Info);
|
||||
fileTransfer.Close();
|
||||
fileTransfers.Remove(fileTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Send part of a stream
|
||||
/// </summary>
|
||||
/// <param name="endpoint">location to send stream to</param>
|
||||
/// <param name="BlockNumber">512 byte block to send</param>
|
||||
private void SendError(FileTransfer fileTransfer, ErrorCode errorCode)
|
||||
{
|
||||
OnNotify("Sending Error Packet: errorCode = " + errorCode.ToString() + ", ", fileTransfer, log4net.Core.Level.Error);
|
||||
|
||||
const int ErrorPacketLength = 10;
|
||||
|
||||
Byte[] buffer = new Byte[ErrorPacketLength];
|
||||
|
||||
buffer[0] = 0;
|
||||
buffer[1] = (byte)Opcode.ACK;
|
||||
buffer[2] = (byte)((fileTransfer.CurrentBlock & 0xFF00) / 256);
|
||||
buffer[3] = (byte)(fileTransfer.CurrentBlock & 0x00FF);
|
||||
buffer[4] = (Byte)'E';
|
||||
buffer[5] = (Byte)'r';
|
||||
buffer[6] = (Byte)'r';
|
||||
buffer[7] = (Byte)'o';
|
||||
buffer[8] = (Byte)'r';
|
||||
buffer[9] = 0;
|
||||
|
||||
int ecode = udpClient.Send(buffer, ErrorPacketLength, fileTransfer.Endpoint);
|
||||
log.InfoFormat("Sent packet {0} ecode={1}", GetDebugMessage(buffer, ErrorPacketLength), ecode);
|
||||
|
||||
if (ecode <= 0)
|
||||
{
|
||||
Debug.WriteLine("Error in send : {0}", ecode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an error response
|
||||
/// </summary>
|
||||
/// <param name="data">data from packet</param>
|
||||
/// <param name="endpoint">client</param>
|
||||
private void ProcessError(Byte[] data, FileTransfer fileTransfer)
|
||||
{
|
||||
int errorCode = 256 * (int)data[2] + (int)data[3];
|
||||
string[] strData = Encoding.ASCII.GetString(data, 2, data.Length - 2).Split(Delimiter, 3);
|
||||
string message = strData[0];
|
||||
OnNotify("Received Error Packet: errorCode=" + errorCode.ToString() + ", message=" + message + ", ",
|
||||
fileTransfer, log4net.Core.Level.Info);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -71,6 +71,9 @@ namespace TBF.BenchControl
|
||||
Factories.Add(new MettlerToledo.Multi.BalanceFactory()); /// MettlerToledo-Multi
|
||||
Factories.Add(new Modbus.Common.Factory()); /// Modbus
|
||||
Factories.Add(new Modbus.PressureMeter.Meret.Factory()); /// Meret pressure meter connected via modbus
|
||||
Factories.Add(new Network.Adapter.Factory());
|
||||
Factories.Add(new Network.Camera.CLP1611.Factory());
|
||||
Factories.Add(new Network.Camera.RoI.Factory());
|
||||
Factories.Add(new Output.FileWriters.Basic.FactorySingle()); /// Output.FileWriters.Basic.Single
|
||||
Factories.Add(new Output.FileWriters.Basic.FactoryCompound()); /// Output.FileWriters.Basic.Compound
|
||||
Factories.Add(new Output.FileWriters.Basic.FactoryHeatMeters()); /// Output.FileWriters.Basic.FactoryHeatMeters
|
||||
|
||||
@ -131,6 +131,7 @@
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
@ -409,6 +410,7 @@
|
||||
<Compile Include="BenchControl\GenericDevices\IHasHeatMtrStatesForm.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IModbus.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\IBenchInfo.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\INetworkAdapter.cs" />
|
||||
<Compile Include="BenchControl\GenericDevices\ISimultTestMethod.cs" />
|
||||
<Compile Include="BenchControl\HeatMetersPath.cs" />
|
||||
<Compile Include="BenchControl\Keithley\Multimeter_2010_RS232\Factory.cs" />
|
||||
@ -492,6 +494,46 @@
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Modbus\QuidoRS\Factory.cs" />
|
||||
<Compile Include="BenchControl\Modbus\QuidoRS\SetOutputsOp.cs" />
|
||||
<Compile Include="BenchControl\Network\Adapter\AdapterInfo.cs" />
|
||||
<Compile Include="BenchControl\Network\Adapter\Netadapter.cs" />
|
||||
<Compile Include="BenchControl\Network\Adapter\Factory.cs" />
|
||||
<Compile Include="BenchControl\Network\Adapter\NetadapterCfg.cs" />
|
||||
<Compile Include="BenchControl\Network\Adapter\NetadapterCfgCtrl.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Adapter\NetadapterCfgCtrl.designer.cs">
|
||||
<DependentUpon>NetadapterCfgCtrl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\Camera.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\CameraCfg.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\CameraCfgCtrl.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\CameraCfgCtrl.designer.cs">
|
||||
<DependentUpon>CameraCfgCtrl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\Factory.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\LiveStreamOp.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\TerminalDlg.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\CLP1611\TerminalDlg.Designer.cs">
|
||||
<DependentUpon>TerminalDlg.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\RoI\RoI.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\RoI\RoICfg.cs" />
|
||||
<Compile Include="BenchControl\Network\Camera\RoI\RoICfgCtrl.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\RoI\RoICfgCtrl.designer.cs">
|
||||
<DependentUpon>RoICfgCtrl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="BenchControl\Network\Camera\RoI\Factory.cs" />
|
||||
<Compile Include="BenchControl\Network\Telnet\Command.cs" />
|
||||
<Compile Include="BenchControl\Network\Telnet\EventArgsClasses.cs" />
|
||||
<Compile Include="BenchControl\Network\Telnet\TelnetClient.cs" />
|
||||
<Compile Include="BenchControl\Network\Telnet\VirtualTerminal.cs" />
|
||||
<Compile Include="BenchControl\Network\Tftp\TftpServer.cs" />
|
||||
<Compile Include="BenchControl\Operations\EnduranceDataLoggingOp.cs" />
|
||||
<Compile Include="BenchControl\Operations\EnthalpyCalculationOp.cs" />
|
||||
<Compile Include="BenchControl\Output\FileWriters\Basic\FactoryCompound.cs" />
|
||||
@ -1790,6 +1832,18 @@
|
||||
<EmbeddedResource Include="BenchControl\Modbus\QuidoRS\QuidoRSCfgCtrl.resx">
|
||||
<DependentUpon>QuidoRSCfgCtrl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="BenchControl\Network\Adapter\NetadapterCfgCtrl.resx">
|
||||
<DependentUpon>NetadapterCfgCtrl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="BenchControl\Network\Camera\CLP1611\CameraCfgCtrl.resx">
|
||||
<DependentUpon>CameraCfgCtrl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="BenchControl\Network\Camera\CLP1611\TerminalDlg.resx">
|
||||
<DependentUpon>TerminalDlg.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="BenchControl\Network\Camera\RoI\RoICfgCtrl.resx">
|
||||
<DependentUpon>RoICfgCtrl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="BenchControl\Operations\AskYesNoForm.resx">
|
||||
<DependentUpon>AskYesNoForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user