Refactor camera handling; add UI and image management support.
Replaced legacy UDP and RTP mechanisms with new live stream, grab, and save image functionality using TCP. Introduced event-based UI command handling and image overlay. Updated resource management for improved reliability and added support for saving captured images to disk.
This commit is contained in:
parent
891795b101
commit
b3d6b5a59f
@ -3,12 +3,15 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AContainerControl_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F32c22f7c1b7049ccad5f07031bb43bf35b8590_003Fb3_003F54768651_003FContainerControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AControl_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F32c22f7c1b7049ccad5f07031bb43bf35b8590_003F01_003F35d9c974_003FControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4290c01eea7748b3aa477ca831e6a387531830_003F6e_003Fc16f1098_003FIList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AILog_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9c853b67fc2341bf8af0d999ea188b6a42000_003Ff4_003F27b3d1bb_003FILog_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AImage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1af41839925b4409b823837d7b5f29d691940_003Fcc_003Fba3dfabe_003FImage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4290c01eea7748b3aa477ca831e6a387531830_003F92_003Fe3eb9ff2_003FList_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkStream_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc0c221501f3a41f8ac0af9d6a9dc9ff335fd90_003F78_003Fdc4af641_003FNetworkStream_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATcpClient_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc0c221501f3a41f8ac0af9d6a9dc9ff335fd90_003Fdb_003Fe9bb8972_003FTcpClient_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATestMethodInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4472e9d6a19b4c92bcc9a80bd60ca17d26da8_003F98_003F3ffb6d31_003FTestMethodInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUdpClient_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc0c221501f3a41f8ac0af9d6a9dc9ff335fd90_003Fdb_003Fe89b26d3_003FUdpClient_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUserControl_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F32c22f7c1b7049ccad5f07031bb43bf35b8590_003Fc3_003F7d8608ff_003FUserControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003A_005F_005FError_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4290c01eea7748b3aa477ca831e6a387531830_003Ffa_003Fa44fa010_003F_005F_005FError_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/UnitTesting/CreateUnitTestDialog/ShowAdvancedOptions/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/CreateUnitTestDialog/TestProjectMapping/=743DF7DB_002DC7B6_002D42EB_002D986D_002D0F485E5588E4/@EntryIndexedValue">77EB589F-C670-4489-AAD6-2A3C02061FD1</s:String>
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/CreateUnitTestDialog/TestProjectMapping/=8648FD92_002DCDA1_002D4C3A_002DB5F9_002DFE547CE1FA48/@EntryIndexedValue">77EB589F-C670-4489-AAD6-2A3C02061FD1</s:String>
|
||||
|
||||
@ -10,12 +10,14 @@ using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using Renci.SshNet;
|
||||
using Common;
|
||||
using TBF.Rig.Network.Telnet;
|
||||
using TBF.Resources;
|
||||
using TBF.Rig.Network.Camera.CJMS11.POJO;
|
||||
using TBF.UiBridge;
|
||||
|
||||
namespace TBF.Rig.Network.Camera.CJMS11
|
||||
{
|
||||
@ -95,6 +97,7 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
public Telnet.TelnetClient Telnet;
|
||||
private TerminalDlg terminalDlg;
|
||||
string sha1sumResponse;
|
||||
JmsMessage jmsMessage;
|
||||
bool sha1sumResponseProcessed;
|
||||
|
||||
///
|
||||
@ -113,33 +116,28 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
Put,
|
||||
}
|
||||
ScpCommand scpCommand;
|
||||
|
||||
|
||||
const int UdpPortBase = 20000; /// Port base for all UDP protocols
|
||||
|
||||
|
||||
///
|
||||
/// MJpeg RTP protocol support
|
||||
///
|
||||
int rtpTcpLocalPort;
|
||||
TcpClient rtpTcpClient;
|
||||
Thread rtpListenerThread;
|
||||
NetworkStream rtpStream = null;
|
||||
StreamReader rtpReader = null;
|
||||
static bool stopRtpListenerFlag;
|
||||
int cameraTcpLocalPort;
|
||||
TcpClient cameraTcpClient;
|
||||
NetworkStream cameraStream = null;
|
||||
StreamReader cameraReader = null;
|
||||
private Image lastImage;
|
||||
|
||||
///
|
||||
/// RTCP protocol (reserved)
|
||||
///
|
||||
int rtcpUdpLocalPort;
|
||||
|
||||
///
|
||||
/// Measurement results protocol
|
||||
///
|
||||
int msrmntUdpLocalPort;
|
||||
UdpClient msrmntUdpClient; /// If != null msrmntListenerThread
|
||||
Thread msrmntListenerThread;
|
||||
static bool stopMsrmntListenerFlag;
|
||||
Thread liveStreamListenerThread;
|
||||
static bool stopLiveStreamListenerFlag;
|
||||
|
||||
Thread grabImageListenerThread;
|
||||
static bool stopGrabImageListenerFlag;
|
||||
|
||||
Thread stopUIListenerThread;
|
||||
static bool stopUIListenerFlag;
|
||||
|
||||
Thread saveImageListenerThread;
|
||||
static bool stopSaveImageListenerFlag;
|
||||
|
||||
///
|
||||
/// ROI related parameters
|
||||
@ -195,32 +193,14 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
{
|
||||
UiBridge.Bridge.OnCameraInfo(cameraIdx, string.Format("{0} ver.{1} {2} s/n {3}", Name, sdCardVer, ipAddress, CameraCfg.HardwareAddress));
|
||||
|
||||
ClpUserName = (sdCardVer.Length > 0 && sdCardVer[0] == '1') ? "tbf" : "pi";
|
||||
// start live stream, grab image, ... listener thread
|
||||
UiBridge.Bridge.CameraUICmdHandler += HandleCameraUICmd;
|
||||
|
||||
StartRtpListener(IPAddress, iPort);
|
||||
StartMsrmntListener(IPAddress, msrmntUdpLocalPort);
|
||||
|
||||
connectionInfo = new PasswordConnectionInfo(IPAddress.ToString(), ClpUserName, ClpPassword);
|
||||
|
||||
/// Open telnet clint and start the log-in process
|
||||
Telnet = new Telnet.TelnetClient(this, CameraCfg.Name, ClpUserName, ClpPassword, TelnetPrompt, TelnetSkipFirstLine, CameraCfg.DisplayTerminal);
|
||||
|
||||
Telnet.promptReceivedHandler += delegate(object sndr, PromptReceivedEventArgs a)
|
||||
{
|
||||
OnPromptReceived(sndr, a);
|
||||
};
|
||||
|
||||
if (CameraCfg.DisplayTerminal)
|
||||
{
|
||||
terminalDlg = new TerminalDlg(CameraCfg.Name, Telnet);
|
||||
terminalDlg.Show();
|
||||
}
|
||||
|
||||
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.CONNECT, ipAddress.ToString(), 10, 30));
|
||||
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.CLEAR_RESPONSE));
|
||||
Telnet.Enqueue(new Telnet.Command(Network.Telnet.CmdAction.SEND_COMMAND, "sha1sum clp/*"));
|
||||
|
||||
log.FatalFormat("'{0}' detected: Id={1} addr={2} IP={3} SD={4}", Name, CameraIdx, CameraCfg.HardwareAddress, ipAddress, sdCardVer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -236,8 +216,8 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
running = false;
|
||||
|
||||
stopScpThreadFlag = true;
|
||||
stopRtpListenerFlag = true;
|
||||
stopMsrmntListenerFlag = true;
|
||||
stopLiveStreamListenerFlag = true;
|
||||
stopGrabImageListenerFlag = true;
|
||||
|
||||
if (Telnet != null)
|
||||
{
|
||||
@ -252,19 +232,13 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
if ((CameraCfg.DebugLevel != DebugMode.Simulate) && (CameraCfg.DebugLevel != DebugMode.DetectedOff))
|
||||
{
|
||||
if (scpThread != null && scpThread.IsAlive) scpThread.Join(50);
|
||||
if (rtpListenerThread != null) rtpListenerThread.Join(50);
|
||||
if (msrmntListenerThread != null) msrmntListenerThread.Join(50);
|
||||
if (liveStreamListenerThread != null) liveStreamListenerThread.Join(50);
|
||||
if (grabImageListenerThread != null) grabImageListenerThread.Join(50);
|
||||
|
||||
if (rtpTcpClient != null)
|
||||
if (cameraTcpClient != null)
|
||||
{
|
||||
rtpTcpClient.Close();
|
||||
rtpTcpClient = null;
|
||||
}
|
||||
|
||||
if (msrmntUdpClient != null)
|
||||
{
|
||||
msrmntUdpClient.Close();
|
||||
msrmntUdpClient = null;
|
||||
cameraTcpClient.Close();
|
||||
cameraTcpClient = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,11 +259,12 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
public void RunDeviceAfter() { }
|
||||
|
||||
|
||||
void OnPromptReceived(object sndr, PromptReceivedEventArgs a)
|
||||
void OnPromptReceived(object sndr, PromptReceivedJMSEventArgs a)
|
||||
{
|
||||
if (sha1sumResponse == null)
|
||||
{
|
||||
sha1sumResponse = a.Response;
|
||||
jmsMessage = a.Message;
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,102 +300,7 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
#endregion Configuration Change Handling
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Detect the camera with specified hardware address (DIP switches).
|
||||
/// Optionally set camera date and time.
|
||||
/// </summary>
|
||||
/// <param name="hwAddress">Hardware address (DIP switches)</param>
|
||||
/// <param name="setDateTime">true = Broadcast 'SetDateTime' to all cameras</param>
|
||||
/// <param name="ipAddress">Detected IP address</param>
|
||||
/// <param name="hardware">Detected hardware</param>
|
||||
/// <param name="revision">Detected HW revision</param>
|
||||
/// <param name="serial">Detected serial number</param>
|
||||
/// <param name="sdCardVer">Detected OS image</param>
|
||||
/// <returns>true when camera detected successfully</returns>
|
||||
bool DetectCamera(int hwAddress, ref IPAddress ipAddress, bool setDateTime, out string hardware, out string revision, out string serial, out string sdCardVer)
|
||||
{
|
||||
for (int trials = 1; trials <= 3; trials++)
|
||||
{
|
||||
UdpClient udpClient = new UdpClient();
|
||||
|
||||
try
|
||||
{
|
||||
if (setDateTime)
|
||||
{
|
||||
SetDateTime(udpClient, DateTime.Now);
|
||||
}
|
||||
|
||||
///
|
||||
/// Send a request for camera information
|
||||
///
|
||||
DateTime detectionStart = DateTime.Now;
|
||||
CameraInfoRequest(udpClient, hwAddress);
|
||||
|
||||
///
|
||||
/// Receive a response or timeout
|
||||
///
|
||||
IAsyncResult asyncRslt = udpClient.BeginReceive(null, null);
|
||||
if (asyncRslt.AsyncWaitHandle.WaitOne(500))
|
||||
{
|
||||
/// Response received within time limit
|
||||
IPEndPoint cameraIPEndpoint = new IPEndPoint(IPAddress.Any, 1852);
|
||||
byte[] inputBuffer = udpClient.EndReceive(asyncRslt, ref cameraIPEndpoint);
|
||||
|
||||
double duration_ms = (DateTime.Now - detectionStart).TotalMilliseconds;
|
||||
ipAddress = cameraIPEndpoint.Address;
|
||||
|
||||
udpClient.Close();
|
||||
|
||||
string response = Encoding.ASCII.GetString(inputBuffer, 0, inputBuffer.Length);
|
||||
string[] strArr = response.Split(new char[] { ' ', '=' });
|
||||
if (strArr.Length == 10 && strArr[0] == "Address" && strArr[2] == "Hardware" &&
|
||||
strArr[4] == "Revision" && strArr[6] == "Serial" && strArr[8] == "Image")
|
||||
{
|
||||
hardware = strArr[3];
|
||||
revision = strArr[5];
|
||||
serial = strArr[7];
|
||||
sdCardVer = strArr[9];
|
||||
}
|
||||
else if (strArr.Length == 8 && strArr[0] == "Address" && strArr[2] == "Hardware" &&
|
||||
strArr[4] == "Revision" && strArr[6] == "Serial")
|
||||
{
|
||||
hardware = strArr[3];
|
||||
revision = strArr[5];
|
||||
serial = strArr[7];
|
||||
sdCardVer = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string msg = string.Format("Camera {0} detected in {1} ms: HWAddress={2} IPAddress={3} {4}",
|
||||
CameraCfg.Name,
|
||||
duration_ms,
|
||||
CameraCfg.HardwareAddress,
|
||||
ipAddress == null ? "not detected" : ipAddress.ToString(),
|
||||
response);
|
||||
log.Debug(msg);
|
||||
Console.WriteLine(msg);
|
||||
|
||||
return true; /// Camera detected
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.ErrorFormat("Camera {0} with HWAddress={1} not detected : {2}", CameraCfg.Name, CameraCfg.HardwareAddress, exc.Message);
|
||||
}
|
||||
|
||||
udpClient.Close();
|
||||
}
|
||||
|
||||
ipAddress = null;
|
||||
hardware = null;
|
||||
revision = null;
|
||||
serial = null;
|
||||
sdCardVer = null;
|
||||
return false; /// No camera detected
|
||||
}
|
||||
|
||||
|
||||
bool DetectJMSCamera(int hwAddress, ref IPAddress ipAddress, bool setDateTime, out string hardware, out string revision, out string serial, out string sdCardVer)
|
||||
{
|
||||
@ -515,8 +395,8 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
reader.Close();
|
||||
if (stream != null)
|
||||
stream.Close();
|
||||
if (tcpClient.Connected)
|
||||
tcpClient.Close();
|
||||
|
||||
tcpClient.Close();
|
||||
}
|
||||
|
||||
|
||||
@ -705,7 +585,343 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Define the handler method
|
||||
private void HandleCameraUICmd(object sender, CameraUICmdEventArgs e)
|
||||
{
|
||||
// Example reaction to event
|
||||
if (e.CameraUICmd == CameraUICmd.Live)
|
||||
{
|
||||
if (stopLiveStreamListenerFlag == false && liveStreamListenerThread != null && liveStreamListenerThread.IsAlive)
|
||||
return;
|
||||
log.Debug("Handle CameraUICmd received - Live");
|
||||
stopLiveStreamListenerFlag = false;
|
||||
StartLiveStreamListener(IPAddress, iPort);
|
||||
}
|
||||
else if (e.CameraUICmd == CameraUICmd.Stop)
|
||||
{
|
||||
if (stopLiveStreamListenerFlag == true)
|
||||
return;
|
||||
log.Debug("Handle CameraUICmd received - Stop Live");
|
||||
stopLiveStreamListenerFlag = true;
|
||||
}
|
||||
else if (e.CameraUICmd == CameraUICmd.Grab)
|
||||
{
|
||||
if (liveStreamListenerThread != null && liveStreamListenerThread.IsAlive)
|
||||
{
|
||||
log.Debug("Handle CameraUICmd received - GrabImage - will Stop Live");
|
||||
stopUIThreads();
|
||||
return;
|
||||
}
|
||||
|
||||
StartGrabImageListener(IPAddress, iPort);
|
||||
|
||||
}
|
||||
else if (e.CameraUICmd == CameraUICmd.SaveImage)
|
||||
{
|
||||
if (liveStreamListenerThread != null && liveStreamListenerThread.IsAlive)
|
||||
{
|
||||
log.Debug("Handle CameraUICmd received - SaveImage - will end Live Stream");
|
||||
stopUIThreads();
|
||||
}
|
||||
lastImage = null;
|
||||
StartSaveImageListener(IPAddress, iPort);
|
||||
SaveImageToFile(lastImage);
|
||||
lastImage = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveImageToFile(Image imageToSave)
|
||||
{
|
||||
|
||||
if (imageToSave == null)
|
||||
{
|
||||
log.Error("Nothing to save in SaveImageToFile");
|
||||
return; // nothing to save
|
||||
}
|
||||
|
||||
using (SaveFileDialog dialog = new SaveFileDialog())
|
||||
{
|
||||
dialog.Title = "Save Image As";
|
||||
dialog.Filter = "PNG Image|*.png|JPEG Image|*.jpg|Bitmap Image|*.bmp";
|
||||
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
|
||||
dialog.FileName = "my_image.png";
|
||||
|
||||
if (dialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// Choose format based on extension
|
||||
var ext = System.IO.Path.GetExtension(dialog.FileName).ToLower();
|
||||
System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Png;
|
||||
if (ext == ".jpg") format = System.Drawing.Imaging.ImageFormat.Jpeg;
|
||||
else if (ext == ".bmp") format = System.Drawing.Imaging.ImageFormat.Bmp;
|
||||
|
||||
try
|
||||
{
|
||||
imageToSave.Save(dialog.FileName, format);
|
||||
MessageBox.Show("Image saved to: " + dialog.FileName);
|
||||
}catch(Exception exc)
|
||||
{
|
||||
MessageBox.Show("Error saving image: " + exc.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartSaveImageListener(IPAddress localIP, int localPort)
|
||||
{
|
||||
EstablishCameraConnection(localIP, localPort);
|
||||
|
||||
saveImageListenerThread = new Thread(new ThreadStart(SaveImageListener));
|
||||
saveImageListenerThread.Start();
|
||||
}
|
||||
|
||||
private void EstablishCameraConnection(IPAddress localIP, int localPort)
|
||||
{
|
||||
if (this.cameraTcpClient == null)
|
||||
{
|
||||
cameraTcpClient = new TcpClient(localIP.ToString(), localPort);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveImageListener()
|
||||
{
|
||||
int penWidth = 1;
|
||||
Pen pen = new Pen(Color.Green, penWidth);
|
||||
|
||||
try
|
||||
{
|
||||
cameraStream = cameraTcpClient.GetStream();
|
||||
cameraStream.ReadTimeout = 1000;
|
||||
cameraReader = new StreamReader(cameraStream, Encoding.ASCII);
|
||||
|
||||
SendCommand(CommandM.prepare_camera_);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.Error($"Initialisation of connection readers failed: {exc.Message}");
|
||||
return;
|
||||
}
|
||||
stopSaveImageListenerFlag = false;
|
||||
|
||||
while (!stopSaveImageListenerFlag)
|
||||
{
|
||||
try
|
||||
{
|
||||
SendCommand(CommandM.grab_image_);
|
||||
string responseAnswer = cameraReader.ReadLine();
|
||||
|
||||
if (responseAnswer.Length > 0)
|
||||
{
|
||||
/// Process the packet
|
||||
JmsPacket newPacket = new JmsPacket(responseAnswer);
|
||||
|
||||
switch (newPacket.JmsMessage.Command)
|
||||
{
|
||||
case CommandM.grab_image_:
|
||||
ParsedImage parsedImage = newPacket.JmsMessage.getImage();
|
||||
if (parsedImage.Encoding == ImageType.BASE_64)
|
||||
{
|
||||
Image image = parsedImage.Image;
|
||||
|
||||
|
||||
if (showOverlayRect && overlayRect != null && overlayThickness > 0)
|
||||
{
|
||||
using (var grph = Graphics.FromImage(image))
|
||||
{
|
||||
if (penWidth != overlayThickness)
|
||||
{
|
||||
penWidth = overlayThickness;
|
||||
pen = new Pen(Color.Green, penWidth);
|
||||
}
|
||||
|
||||
grph.DrawRectangle(pen, overlayRect);
|
||||
}
|
||||
}
|
||||
|
||||
UiBridge.Bridge.OnImage(this.cameraIdx, image);
|
||||
lastImage = image;
|
||||
stopSaveImageListenerFlag = true; // mam obrazok ukoncim a zavriem thread
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
string msg = string.Format("Exception in MJpeg RTP listener thread: {0}", exc.Message);
|
||||
log.Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
stopGrabImageListenerFlag = false;
|
||||
SendCommand(CommandM.close_);
|
||||
SendCommand(CommandM.disconnect_);
|
||||
|
||||
CloseCameraResources();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void stopUIThreads()
|
||||
{
|
||||
log.Debug("Handle CameraUICmd StopUIListener");
|
||||
stopUIListenerThread = new Thread(StopUIListener);
|
||||
stopUIListenerThread.Start();
|
||||
}
|
||||
|
||||
void StopUIListener()
|
||||
{
|
||||
stopUIListenerFlag = false;
|
||||
while (!stopUIListenerFlag)
|
||||
{
|
||||
stopLiveStreamListenerFlag = true;
|
||||
stopGrabImageListenerFlag = true;
|
||||
|
||||
if ((liveStreamListenerThread != null && liveStreamListenerThread.IsAlive) ||
|
||||
(grabImageListenerThread != null && grabImageListenerThread.IsAlive))
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
stopUIListenerFlag = true;
|
||||
}
|
||||
}
|
||||
stopLiveStreamListenerFlag = false;
|
||||
stopGrabImageListenerFlag = false;
|
||||
}
|
||||
|
||||
|
||||
private void StartGrabImageListener(IPAddress localIP, int localPort)
|
||||
{
|
||||
if (this.cameraTcpClient != null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (this.cameraTcpClient == null)
|
||||
{
|
||||
cameraTcpClient = new TcpClient(localIP.ToString(), localPort);
|
||||
}
|
||||
|
||||
grabImageListenerThread = new Thread(new ThreadStart(GrabImageListener));
|
||||
grabImageListenerThread.Start();
|
||||
}
|
||||
|
||||
void GrabImageListener()
|
||||
{
|
||||
int penWidth = 1;
|
||||
Pen pen = new Pen(Color.Green, penWidth);
|
||||
|
||||
try
|
||||
{
|
||||
cameraStream = cameraTcpClient.GetStream();
|
||||
cameraStream.ReadTimeout = 1000;
|
||||
cameraReader = new StreamReader(cameraStream, Encoding.ASCII);
|
||||
|
||||
SendCommand(CommandM.prepare_camera_);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.Error($"Initialisation of connection readers failed: {exc.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
stopGrabImageListenerFlag = false;
|
||||
int iCountOf_NACK = 0;
|
||||
|
||||
while (!stopGrabImageListenerFlag)
|
||||
{
|
||||
try
|
||||
{
|
||||
SendCommand(CommandM.grab_image_);
|
||||
string responseAnswer = cameraReader.ReadLine();
|
||||
|
||||
if (responseAnswer.Length > 0)
|
||||
{
|
||||
/// Process the packet
|
||||
JmsPacket newPacket = new JmsPacket(responseAnswer);
|
||||
|
||||
if (newPacket.JmsMessage.Status != MessageStatus.ACK)
|
||||
{
|
||||
if (iCountOf_NACK < 5)
|
||||
{
|
||||
iCountOf_NACK++;
|
||||
continue;
|
||||
}
|
||||
log.ErrorFormat("Error occured more as 5 time in GrabImageListener: {0}", newPacket.JmsMessage.Status);
|
||||
stopGrabImageListenerFlag = true; // mam obrazok ukoncim a zavriem thread
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
switch (newPacket.JmsMessage.Command)
|
||||
{
|
||||
case CommandM.grab_image_:
|
||||
ParsedImage parsedImage = newPacket.JmsMessage.getImage();
|
||||
if (parsedImage.Encoding == ImageType.BASE_64)
|
||||
{
|
||||
Image image = parsedImage.Image;
|
||||
|
||||
|
||||
if (showOverlayRect && overlayRect != null && overlayThickness > 0)
|
||||
{
|
||||
using (var grph = Graphics.FromImage(image))
|
||||
{
|
||||
if (penWidth != overlayThickness)
|
||||
{
|
||||
penWidth = overlayThickness;
|
||||
pen = new Pen(Color.Green, penWidth);
|
||||
}
|
||||
|
||||
grph.DrawRectangle(pen, overlayRect);
|
||||
}
|
||||
}
|
||||
|
||||
UiBridge.Bridge.OnImage(this.cameraIdx, image);
|
||||
stopGrabImageListenerFlag = true; // mam obrazok ukoncim a zavriem thread
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
string msg = string.Format("Exception in MJpeg RTP listener thread: {0}", exc.Message);
|
||||
log.Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
stopGrabImageListenerFlag = false;
|
||||
SendCommand(CommandM.close_);
|
||||
SendCommand(CommandM.disconnect_);
|
||||
|
||||
CloseCameraResources();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private void CloseCameraResources()
|
||||
{
|
||||
cameraReader?.Close();
|
||||
cameraStream?.Close();
|
||||
cameraTcpClient?.Close();
|
||||
cameraTcpClient?.Dispose();
|
||||
cameraTcpClient = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// listener for multiple - repetetive image receiving
|
||||
/// </summary>
|
||||
@ -715,29 +931,46 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
/// <param name="localIP"></param>
|
||||
/// <param name="localPort"></param>
|
||||
|
||||
private void StartRtpListener(IPAddress localIP, int localPort)
|
||||
private void StartLiveStreamListener(IPAddress localIP, int localPort)
|
||||
{
|
||||
rtpTcpClient = new TcpClient(new IPEndPoint(localIP, localPort));
|
||||
rtpListenerThread = new Thread(new ThreadStart(RtpListener));
|
||||
rtpListenerThread.Start();
|
||||
if (this.cameraTcpClient == null)
|
||||
{
|
||||
cameraTcpClient = new TcpClient(localIP.ToString(), localPort);
|
||||
}
|
||||
|
||||
liveStreamListenerThread = new Thread(new ThreadStart(LiveStreamListener));
|
||||
liveStreamListenerThread.Start();
|
||||
}
|
||||
|
||||
void RtpListener()
|
||||
void LiveStreamListener()
|
||||
{
|
||||
JpegFrame jpegFrame = new JpegFrame();
|
||||
bool synced = false;
|
||||
int penWidth = 1;
|
||||
Pen pen = new Pen(Color.Green, penWidth);
|
||||
|
||||
rtpStream = rtpTcpClient.GetStream();
|
||||
rtpStream.ReadTimeout = 1000;
|
||||
rtpReader = new StreamReader(rtpStream, Encoding.ASCII);
|
||||
try
|
||||
{
|
||||
cameraStream = cameraTcpClient.GetStream();
|
||||
cameraStream.ReadTimeout = 1000;
|
||||
cameraReader = new StreamReader(cameraStream, Encoding.ASCII);
|
||||
|
||||
SendCommand(CommandM.prepare_camera_);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
log.Error($"Initialisation of connection readers failed: {exc.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!stopRtpListenerFlag)
|
||||
stopLiveStreamListenerFlag = false;
|
||||
while (!stopLiveStreamListenerFlag)
|
||||
{
|
||||
try
|
||||
{
|
||||
string responseAnswer = rtpReader.ReadLine();
|
||||
|
||||
SendCommand(CommandM.grab_image_);
|
||||
string responseAnswer = cameraReader.ReadLine();
|
||||
|
||||
if (responseAnswer.Length > 0)
|
||||
{
|
||||
@ -772,23 +1005,9 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
UiBridge.Bridge.OnImage(this.cameraIdx, image);
|
||||
}
|
||||
break;
|
||||
case CommandM.close_:
|
||||
synced = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//}
|
||||
// else if (newPacket.Mark)
|
||||
// {
|
||||
// /// Synchronize when a packet with Mark occurs, process the next packet
|
||||
// jpegFrame.Clear();
|
||||
// synced = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /// Stay unsynchronized
|
||||
// }
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
@ -798,77 +1017,17 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
}
|
||||
}
|
||||
|
||||
stopLiveStreamListenerFlag = false;
|
||||
SendCommand(CommandM.close_);
|
||||
SendCommand(CommandM.disconnect_);
|
||||
|
||||
CloseCameraResources();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void StartMsrmntListener(IPAddress localIP, int localPort)
|
||||
{
|
||||
msrmntUdpClient = new UdpClient(new IPEndPoint(localIP, localPort));
|
||||
msrmntListenerThread = new Thread(new ThreadStart(MsrmntListener));
|
||||
msrmntListenerThread.Start();
|
||||
}
|
||||
|
||||
void MsrmntListener()
|
||||
{
|
||||
StringBuilder toBeProcessed = new StringBuilder();
|
||||
int[] angles = new int[RoisAndResults.MaxRegisteredRois];
|
||||
|
||||
while (!stopMsrmntListenerFlag)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPEndPoint endpoint = null;
|
||||
Byte[] data = msrmntUdpClient.Receive(ref endpoint);
|
||||
|
||||
toBeProcessed.Append(Encoding.ASCII.GetString(data, 0, data.Length));
|
||||
log.DebugFormat("MeasurementUdpListener() ... toBeProcessed = {0}", toBeProcessed);
|
||||
|
||||
while (true)
|
||||
{
|
||||
int from = toBeProcessed.ToString().IndexOf('[');
|
||||
if (from < 0) break;
|
||||
|
||||
int len = toBeProcessed.ToString(from + 1, toBeProcessed.Length - from - 1).IndexOf(']');
|
||||
if (len < 0) break;
|
||||
|
||||
string[] pulsesArr = toBeProcessed.ToString(from + 1, len).Split(new char[] { ';' });
|
||||
|
||||
bool fmtError = false;
|
||||
long timeMs;
|
||||
if ((pulsesArr.Length >= 2) &&
|
||||
(pulsesArr.Length <= RoisAndResults.MaxRegisteredRois + 1) &&
|
||||
long.TryParse(pulsesArr[0], out timeMs))
|
||||
{
|
||||
for (int i = 1; i < pulsesArr.Length; i++)
|
||||
{
|
||||
int val;
|
||||
if (int.TryParse(pulsesArr[i], out val))
|
||||
{
|
||||
angles[i - 1] = Math.Abs(val); /// TODO: pozerat CW/CCW a podla toho dat +/-
|
||||
}
|
||||
else
|
||||
{
|
||||
fmtError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fmtError) roisAndResults.SetResults(timeMs, angles);
|
||||
}
|
||||
|
||||
toBeProcessed.Remove(0, from + len + 2);
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
string msg = string.Format("Exception in the measurement listener thread: {0}", exc.Message);
|
||||
log.Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//public void OnMeasurementDataReceived(object sender, MeasuredDataEventArgs msrmtData)
|
||||
@ -897,7 +1056,7 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
int wid = hiRes ? 1280 : 640;
|
||||
int hgh = hiRes ? 960 : 480;
|
||||
string command = string.Format("/opt/vc/bin/raspivid -t 0 -cd MJPEG -w {0} -h {1} -fps 30 -b 8000000 -o - | gst-launch-1.0 fdsrc ! \"image/jpeg,framerate=30/1\" ! jpegparse ! rtpjpegpay ! udpsink host={2} port={3}",
|
||||
wid, hgh, NetAdapter.IPAddress, rtpTcpLocalPort);
|
||||
wid, hgh, NetAdapter.IPAddress, cameraTcpLocalPort);
|
||||
//string command = string.Format("~/userland/build/bin/raspivid -t 0 -cd MJPEG -w {0} -h {1} -fps 30 -b 8000000 -o - | gst-launch-1.0 fdsrc ! \"image/jpeg,framerate=30/1\" ! jpegparse ! rtpjpegpay ! udpsink host={2} port={3}",
|
||||
// wid, hgh, NetAdapter.IPAddress, rtpUdpLocalPort);
|
||||
|
||||
@ -929,59 +1088,82 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
|
||||
public void Start()
|
||||
{
|
||||
/// Prepare the telent command
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 1; i <= roisAndResults.RegisteredRoisCount; i++)
|
||||
///Prepare communication with the camera
|
||||
if (cameraStream != null && cameraReader != null && cameraStream.CanWrite)
|
||||
{
|
||||
sb.Append(" ");
|
||||
sb.Append(roisAndResults.GetRoiParams(i));
|
||||
|
||||
JmsPacket answer = SendCommandAndWaitToAnswer(CommandM.prepare_camera_);
|
||||
|
||||
int incorrectAnswerCount = 0;
|
||||
bool answerCorrect = false;
|
||||
while (!answerCorrect || incorrectAnswerCount < 3)
|
||||
{
|
||||
if (answer.JmsMessage.Command == CommandM.prepare_camera_)
|
||||
{
|
||||
answerCorrect = true;
|
||||
if (answer.JmsMessage.Status == MessageStatus.ACK)
|
||||
{
|
||||
log.Debug("Camera is ready to receive data");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Error("NOCK answer - prepare_camera");
|
||||
}
|
||||
}
|
||||
|
||||
incorrectAnswerCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendCommand(CommandM command)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cameraStream != null && cameraReader != null && cameraStream.CanWrite)
|
||||
{
|
||||
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(" " + CommandMEnum.GetVal(command)+"\r\n");
|
||||
cameraStream.Write(buffer, 0, buffer.Length);
|
||||
//cameraStream.Flush();
|
||||
}
|
||||
}catch(Exception exc)
|
||||
{
|
||||
log.ErrorFormat("{0} SendCommand: {1}", Name, exc.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
private JmsPacket SendCommandAndWaitToAnswer(CommandM command)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cameraStream != null && cameraReader != null && cameraStream.CanWrite)
|
||||
{
|
||||
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(" " + CommandMEnum.GetVal(command)+"\r\n");
|
||||
cameraStream.Write(buffer, 0, buffer.Length);
|
||||
//cameraStream.Flush();
|
||||
|
||||
string readLine = cameraReader.ReadLine();
|
||||
JmsPacket newPacket = new JmsPacket(readLine);
|
||||
return newPacket;
|
||||
}
|
||||
}catch(Exception exc)
|
||||
{
|
||||
log.ErrorFormat("{0} SendCommand: {1}", Name, exc.Message);
|
||||
}
|
||||
|
||||
int logImagesArg;
|
||||
switch (CameraCfg.TestImagesMode)
|
||||
{
|
||||
default:
|
||||
case TestImagesMode.None:
|
||||
case TestImagesMode.LoadImages:
|
||||
logImagesArg = 0;
|
||||
break;
|
||||
case TestImagesMode.SaveFirstImages:
|
||||
logImagesArg = CameraCfg.TestImagesCount;
|
||||
break;
|
||||
case TestImagesMode.SaveLastImages:
|
||||
logImagesArg = -CameraCfg.TestImagesCount;
|
||||
break;
|
||||
}
|
||||
|
||||
command = string.Format("clp/Measurement -udp {0} {1}{2}{3} 1 7 0 0 {4}",
|
||||
NetAdapter.IPAddress,
|
||||
msrmntUdpLocalPort,
|
||||
(CameraCfg.TestImagesMode == TestImagesMode.LoadImages) ? (" -l " + CameraCfg.TestImagesCount.ToString()) : string.Empty,
|
||||
sb,
|
||||
logImagesArg);
|
||||
|
||||
measurementCommandSent = false;
|
||||
|
||||
/// If ready send (=enqueue) the command
|
||||
if (Telnet.State == TelnetClient.TelnetState.Inactive)
|
||||
{
|
||||
log.WarnFormat("{0} SEND_MSRMNT_CMD: {1}", Name, command);
|
||||
Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_MSRMNT_CMD, command));
|
||||
measurementCommandSent = true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Event Run()
|
||||
{
|
||||
if (!measurementCommandSent)
|
||||
while (true)
|
||||
{
|
||||
/// When ready send (=enqueue) the command
|
||||
if (Telnet.State == TelnetClient.TelnetState.Inactive)
|
||||
{
|
||||
log.WarnFormat("{0} SEND_MSRMNT_CMD: {1}", Name, command);
|
||||
Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_MSRMNT_CMD, command));
|
||||
measurementCommandSent = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Event.None;
|
||||
@ -991,8 +1173,12 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
{
|
||||
if (measurementCommandSent)
|
||||
{
|
||||
log.WarnFormat("{0} SEND_COMMAND: CTRL-Q", Name);
|
||||
Telnet.Enqueue(new Telnet.Command(CmdAction.SEND_COMMAND, TelnetClient.Q_Command));
|
||||
log.WarnFormat("{0} SEND_COMMAND: cancel", Name);
|
||||
if (cameraStream.CanWrite)
|
||||
{
|
||||
SendCommand(CommandM.close_);
|
||||
SendCommand(CommandM.disconnect_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,12 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
set => payload = value;
|
||||
}
|
||||
|
||||
public string OrigStatus => orig_status;
|
||||
|
||||
public string OrigCommand => orig_command;
|
||||
|
||||
public string OrigPayload => orig_payload;
|
||||
|
||||
public JmsMessage(string status, string command, string payload)
|
||||
{
|
||||
this.status = MessageStatusEnum.GetCommandM(status);
|
||||
@ -38,6 +44,7 @@ namespace TBF.Rig.Network.Camera.CJMS11
|
||||
orig_status = status;
|
||||
orig_command = command;
|
||||
orig_payload = payload;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public bool isMessageImageType(){
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TBF.Rig.Network.Camera.CJMS11;
|
||||
|
||||
namespace TBF.Rig.Network.Telnet
|
||||
{
|
||||
@ -61,6 +62,22 @@ namespace TBF.Rig.Network.Telnet
|
||||
Response = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of argument of PromptReceviedEventHandler
|
||||
/// </summary>
|
||||
public class PromptReceivedJMSEventArgs : EventArgs
|
||||
{
|
||||
public string Response; /// Response to a command from the telnet server ...
|
||||
/// ... without the terminal prompt string.
|
||||
public JmsMessage Message; /// Message received from the server.
|
||||
|
||||
public PromptReceivedJMSEventArgs(string text, JmsMessage message)
|
||||
{
|
||||
Response = text;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user