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:
Michal Buzik 2025-05-26 08:58:46 +02:00
parent 891795b101
commit b3d6b5a59f
4 changed files with 503 additions and 290 deletions

View File

@ -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>

View File

@ -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_);
}
}
}
}

View File

@ -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(){

View File

@ -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;
}
}