tbf/TestBenchFramework/BenchControl/Cameras/IdcCamera/Idc100.cs

1442 lines
51 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using log4net;
namespace TBF.BenchControl.Cameras.IdcCamera
{
public class Idc100
{
private static readonly ILog log = LogManager.GetLogger(typeof(Idc100));
///
/// Constants
///
const string IdcHomeDir = Program.HomeDir; /// Contains subdirectory Images/...
const int MesurementPeriod_Frames = 6;
const int ParamsSize = 14;
const int MaxMeasurementsCount = 160000; /// Enough for +/- 3,5h measurement
///
/// Data marks identifying events
///
enum MARK
{
FALLING = 2000000000, /// Marks measurement start
RISING = 2000000001, /// marks measurement end
BEGIN = 2000000002, /// not used
END = 2000000003, /// not used
DUMMY = 2000000004
}
/// <summary>Version string</summary>
public string Version { get { return cameraVersionStr; } }
string cameraVersionStr; /// IDC100 version, valid after 'Connect'
/// <summary>
/// Private fields
/// </summary>
int cameraNr; /// 0-based camera number
int comPortNr; /// COM port number
int baudRate;
float brightness; /// Relative brightness 0 .. 1.0f
string imagesPath;
Tools.IniUtil commonIni;
SerialLayer serial; /// Communications
Thread workerThread;
struct Measurement
{
public uint timeStamp;
public int angle;
public Measurement(uint timeStamp, int angle)
{
this.timeStamp = timeStamp;
this.angle = angle;
}
}
IList<Measurement> measurements; /// Raw angle measurements obtained by the camera
int wm_nrBegin; /// Measuremnt start mark
uint wm_timestampBegin;
int wm_nrEnd; /// Measurement end mark
uint wm_timestampEnd;
/// <summary>
/// The angle difference since the start of the measurement operation (the start mark)
/// </summary>
public int Pulses
{
get
{
if (measurements.Count < 1 || wm_nrBegin >= measurements.Count) return 0;
return measurements[measurements.Count - 1].angle - measurements[wm_nrBegin].angle;
}
}
/// <summary>
/// The angle difference between the end and the start of the measurement operation
/// </summary>
public int TotalPulses
{
get
{
if (wm_nrBegin >= measurements.Count || wm_nrEnd > measurements.Count || wm_nrBegin > wm_nrEnd) return 0;
return measurements[wm_nrEnd - 1].angle - measurements[wm_nrBegin].angle;
}
}
int m_initSpeed;
IdcState _idcState;
///
IdcState idcState
{
get { return _idcState; }
set
{
if (value != _idcState)
{
_idcState = value;
TBF.UiBridge.Bridge.OnCameraStateChanged(this,
new TBF.UiBridge.CameraStateChangedEventArgs(cameraNr, value));
}
}
}
///
public IdcState IdcState { get { return _idcState; } }
string m_errorStr; /// last camera error string
RetVal m_lastError; /// last error (either host or camera)
/// On program exit the control sets these events to avoid deadlocks
AutoResetEvent workerCommandEvent;
AutoResetEvent workerEvent;
IWorkerCmd workerCmd;
RetVal workerResponse;
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Camera name = 'Images' subdirectory name)</param>
/// <param name="comPortNr">Com port number 1..999</param>
/// <param name="baudRate">Baud rate 57600 or 115200</param>
/// <param name="brightness">Relative brightness 0..1.0f</param>
public Idc100(string name, int cameraNr, int comPortNr, int baudRate, float brightness)
{
this.comPortNr = comPortNr;
this.baudRate = baudRate;
this.brightness = brightness;
this.cameraNr = cameraNr;
m_initSpeed = 0;
/// Read the rest of parameters from INI-files
this.commonIni = new Tools.IniUtil(IdcHomeDir + "config\\common.ini");
/// Create SerialLayer instance
imagesPath = string.Format("{0}Images\\{1}\\", IdcHomeDir, name);
Directory.CreateDirectory(imagesPath);
serial = new SerialLayer(cameraNr, comPortNr, baudRate, 2000, imagesPath);
/// Initialize the rest
measurements = new List<Measurement>();
wm_nrBegin = 0;
wm_nrEnd = 0;
wm_timestampBegin = 0;
wm_timestampEnd = 0;
m_lastError = RetVal.OK;
idcState = IdcState.NotConnected;
workerCmd = null;
workerResponse = 0;
workerCommandEvent = new AutoResetEvent(false);
workerEvent = new AutoResetEvent(false);
//ExecuteIdcIniFile();
}
public RetVal StartOp(IWorkerCmd workerCmd)
{
IdcState[] iniStates;
IdcTransition[] sTransTbl;
///------------------------------------ Connection state ------------------------------------
if (workerCmd is Command.Connect)
{
m_lastError = Connect((workerCmd as Command.Connect).TimeoutMs);
return m_lastError;
}
else if (workerCmd is Command.Disconnect)
{
iniStates = new IdcState[] { IdcState.Idle, IdcState.Busy, IdcState.OpCompleted, IdcState.OpFailed };
sTransTbl = new IdcTransition[] { new IdcTransition(RetVal.SequenceError, IdcState.Unchanged),
new IdcTransition(RetVal.FatalError, IdcState.Unchanged),
new IdcTransition(RetVal.OK, IdcState.NotConnected), };
serial.m_disconnecting = true;
serial.UnlockLastRead(); /// Quit infinite fifo.Get() waiting for a character in read FIFO
RetVal retv = IssueThreadCmd(workerCmd, iniStates, sTransTbl);
if (retv == RetVal.SequenceError)
return m_lastError = RetVal.OK; /// Camera was not connected - OK
else
return m_lastError = retv;
}
else if (idcState == IdcState.NotConnected)
{
/// connection must be established for all remaining operations
return (m_lastError = RetVal.CameraNotConnected);
}
///------------------------------------ Other operations ------------------------------------
if (workerCmd is Command.Detect || workerCmd is Command.Measure || workerCmd is Command.Stream)
{
///
/// Long lasting (start/stop) operations state transition table
///
iniStates = new IdcState[] { IdcState.Idle };
sTransTbl = new IdcTransition[] { new IdcTransition(RetVal.Busy, IdcState.Busy),
new IdcTransition(RetVal.OpFailed, IdcState.OpFailed),
new IdcTransition(RetVal.OK, IdcState.Busy), };
}
else
{
///
/// Immediate operations state transition table
///
iniStates = new IdcState[] { IdcState.Idle };
sTransTbl = new IdcTransition[] { new IdcTransition(RetVal.Busy, IdcState.Busy),
new IdcTransition(RetVal.OK, IdcState.Idle), };
}
m_lastError = IssueThreadCmd(workerCmd, iniStates, sTransTbl);
return m_lastError;
}
public RetVal StopOp()
{
IdcState[] iniStates = new IdcState[] { IdcState.Busy,
IdcState.OpCompleted,
IdcState.OpFailed };
IdcTransition[] sTransTbl = new IdcTransition[] { new IdcTransition(RetVal.SequenceError, IdcState.Unchanged),
new IdcTransition(RetVal.OK, IdcState.Idle)
};
return m_lastError = IssueThreadCmd(new Command.StopOp(), iniStates, sTransTbl);
}
//---------------------------------------------------------------------
// Connect
// Starts the worker thread, opens the COM-port and establishes
// communication with the camera.
// Returns:
// 0 = OK
// RetVal.SEQUENCE_ERROR ....... camera was already connected, etc
// RetVal.INVALID_COMPORT_NR ... invalid COM-port number
// RetVal.CANNOT_INIT_CAMERA ... when worker thread cannot be started
// RetVal.CANNOT_OPEN_COMPORT ... cannot open COM-port
// RetVal.CANNOT_SET_COMPORT_PARAMETERS ... cannot set comm. parameters
// RetVal.COMM_TIMEOUT ... comm. timeout when establishing a connection
// RetVal.UNKNNOWN_COMM_ERROR ... other less common comm. error
//---------------------------------------------------------------------
RetVal Connect(int timeoutMs)
{
lock (serial)
{
if (idcState != IdcState.NotConnected) return RetVal.SequenceError; /// Command sequence error
if (comPortNr == 0) return RetVal.InvalidComPortNr;
/// Start the worker thread
workerThread = new Thread(new ThreadStart(Worker));
workerThread.Start();
if (workerEvent.WaitOne(timeoutMs))
{
if (workerResponse == RetVal.OK)
{
idcState = IdcState.Idle;
return RetVal.OK; /// Intro part completed OK in time, thread is running OK
}
else
{
return workerResponse; /// Return the code from the thread
}
}
return RetVal.CommTimeout; /// Timeout
}
}
///------------------------------------------------------------------------------
/// Used to issue command to the worker thread
/// Arguments:
/// threadCmd ... thread command (definend in enum in Common.h)
/// expectedStates ... = NULL ... do not check current state
/// = {state1, state2, ..., 0} ... check if current
/// state is one of states in the zero terminated arary
/// stateTransitionTable= {{resp1,state1},{resp2,state2}, ... ,{RetVal.OK,defaultState}}
/// (!!! last item must be {RetVal.OK,defaultState})
/// Returns:
/// workerResponse (error code in case of an error)
///------------------------------------------------------------------------------
RetVal IssueThreadCmd(IWorkerCmd workerCmd, IdcState[] expectedStates, IdcTransition[] stateTransitionTable)
{
lock (serial)
{
/// Check the initial state
if (idcState == IdcState.NotConnected || expectedStates == null)
{
return RetVal.SequenceError; /// Camera is not connected or expexted states missing
}
///
bool isInExpectedState = false;
foreach (var expextedState in expectedStates)
{
if (idcState == expextedState) isInExpectedState = true;
}
if (!isInExpectedState)
{
return RetVal.SequenceError; /// Camera is not in any of the expected states
}
/// Issue thread comand and wait for a response
workerResponse = 0;
this.workerCmd = workerCmd;
workerCommandEvent.Set();
workerEvent.WaitOne();
/// Change the state depending on the response
if (stateTransitionTable != null)
{
foreach (var item in stateTransitionTable)
{
if (item.RetVal == workerResponse)
{
if (item.NewState != IdcState.Unchanged) idcState = item.NewState;
break;
}
}
}
return workerResponse;
}
}
/// <summary>
/// Shut down Idc100 operation, stop the worker thread.
/// </summary>
public void ShutDown()
{
if (workerThread != null) workerThread.Join();
}
void Worker()
{
//-------------------------------------------------------------------
// Introductory part: 'Connect' operation waits until it is completed
//-------------------------------------------------------------------
/// Open the COM-port and set communication parameters
workerResponse = serial.OpenPort();
/// Verify connection and get version
if (RetVal.OK == workerResponse && RetVal.OK != serial.GetVer(out cameraVersionStr))
{
serial.ClosePort();
workerResponse = RetVal.CannotCommWithCamera;
}
/// Signal intro is finished, return on error
workerEvent.Set();
if (workerResponse != RetVal.OK) return; /// Thread halted on error
//--------------------------------------------------
// Worker thread loop
//--------------------------------------------------
string cmd;
RetVal retv;
int iretv;
while (true)
{
workerCommandEvent.WaitOne();
//-------------------------------------------------------------------------------------------
if (workerCmd is Command.Disconnect)
{
// Disconnect camera: close the com-port and exit worker thread
serial.ClosePort();
workerResponse = RetVal.OK;
workerEvent.Set();
return;
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.StopOp)
{
// StopOp() when camera is idle -> do nothing
workerResponse = RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.StartNew)
{
// Format:
// startnew
// Issues command(s):
// startnew
// settime <year> <month> <date> <hour> <min> <sec>
byte znak;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
serial.WriteString("startnew\r\n");
workerResponse = RetVal.Busy; // state -> State.CAMERA_BUSY
workerEvent.Set();
// Returns:
// WAIT_OBJECT_0 ... WorkerCommand.STOP_OP received
// WAIT_TIMEOUT .... time expired, no WorkerCommand.STOP_OP received
while (true)
{
if (workerCommandEvent.WaitOne(6000))
{
/// Signal received
if (workerCmd is Command.StopOp)
{
workerResponse = RetVal.OpInterrupted;
break;
}
}
else
{
/// Timeout
workerResponse = RetVal.OK;
break;
}
}
if (workerResponse == RetVal.OK)
{
do {
retv = serial.ReadByte(out znak);
}
while (znak != '$'); // read all characters in the buffer
serial.WriteString("connect\r\n");
if (RetVal.OK != serial.ReadByte(out znak) || znak != 'V') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '\r') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '\n') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '$') workerResponse = RetVal.OpFailed;
else workerResponse = RetVal.OK;
}
if (workerResponse == RetVal.OK)
{
/// settime
DateTime now = DateTime.Now;
string settimeStr = String.Format("settime {0} {1} {2} {3} {4} {5} {6}\r\n",
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond);
serial.WriteString(settimeStr);
if (RetVal.OK != serial.ReadByte(out znak) || znak != '>') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != ' ') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '0') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != ' ') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != 'O') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != 'K') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '\r') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '\n') workerResponse = RetVal.OpFailed;
else if (RetVal.OK != serial.ReadByte(out znak) || znak != '$') workerResponse = RetVal.OpFailed;
else workerResponse = RetVal.OK;
}
/// Verify connection and get version
if (RetVal.OK == workerResponse && RetVal.OK != serial.GetVer(out cameraVersionStr))
{
serial.ClosePort();
workerResponse = RetVal.CannotCommWithCamera;
workerEvent.Set();
continue;
}
WT_SSOp_Complete(workerResponse);
workerResponse = RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.SetBrightness)
{
Command.SetBrightness args = workerCmd as Command.SetBrightness;
/// Set image brightness
/// Format: setbright 0..100
/// Example: setbright 50
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(string.Format("setbright {0}\r\n", Math.Max(0, Math.Min((int)(100.0f * args.Brightness), 100))),
out received, 1, out m_errorStr);
workerResponse = (iretv <= 0 || received[0] < 0) ? RetVal.OpFailed : RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Grab)
{
Command.Grab args = workerCmd as Command.Grab;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(string.Format("setbright {0}\r\n", Math.Max(0, Math.Min((int)(100.0f * args.Brightness), 100))),
out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
iretv = serial.CommandInt(String.Format("new matbyte snap({0},{1}) vecint iroi(5)\r\n", args.W, args.H),
out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
iretv = serial.CommandInt(String.Format("set iroi {0} {1} {2} {3} {4}\r\n",
args.X, args.Y, args.W, args.H, args.Scale),
out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
// grab
iretv = serial.CommandInt(String.Format("grab snap iroi\r\n"),
out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
// save
string fmtStr = (args.Format == FileFormat.Bmp) ? "bmp" : ( (args.Format == FileFormat.Jpeg) ? "jpg" : "idc");
cmd = string.Format("save {0} snap {1}\r\n", fmtStr, args.FileName);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
workerResponse = (iretv <= 0 || received[0] < 0) ? RetVal.OpFailed : RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Save)
{
Command.Save args = workerCmd as Command.Save;
string fmtStr = (args.Format == FileFormat.Bmp) ? "bmp" : ( (args.Format == FileFormat.Jpeg) ? "jpg" : "idc");
cmd = string.Format("save {0} {1} {2}\r\n", fmtStr, args.VariableName, args.FileName);
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
// NOK
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
else if (!args.WaitCompleted)
{
// OK and does not wait for completition
workerResponse = RetVal.OK;
workerEvent.Set();
continue;
}
else
{
// OK, but waits for completition
workerResponse = RetVal.Busy; // state -> State.CAMERA_BUSY
workerEvent.Set();
while (true)
{
Thread.Sleep(200);
iretv = serial.CommandInt("fiostate\r\n", out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] <= 0)
{
//m_pWnd->PostMessage(WM_USER, EVENT_OP_COMPLETED+m_cameraNr, 0); <------- TODO
idcState = IdcState.OpCompleted;
break;
}
}
WT_SSOp_Wait4StopOp(Timeout.Infinite);
// OK & completed
workerResponse = RetVal.OK;
workerEvent.Set();
}
}
//-------------------------------------------------------------------------------------------
/*
///---------------------------------------
/// Releases IDC100 memory allocated by created images and variables
/// and deletes oroi1 ... oroi9 (complete detection result)
/// Format: clear
///---------------------------------------
case WorkerCommand.NEW_WM:
{
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt("delete -all\r\n", out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
workerEvent.Set();
break;
}
iretv = serial.CommandInt("new int nrarrows\r\n", out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
workerEvent.Set();
break;
}
iretv = serial.CommandInt(String.Format("set nrarrows {0}\r\n", arrows.GetLength(0) - 1), out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
workerEvent.Set();
break;
}
workerResponse = RetVal.OK; /// Eventually overwritten in the for loop
//------
for (int arwIx = 1; arwIx <= arrows.GetLength(0) - 1; arwIx++)
{
cmd = String.Format("new vecfloat params{0}({1}) vecint oroi{0}(5) matshort bkgnd{0}({2},{3}) matbyte detected{0}({4},{5})\r\n",
arwIx, ParamsSize, (int)(Math.Round(arrows[arwIx].oroi_w)), (int)(Math.Round(arrows[arwIx].oroi_h)),
arrows[arwIx].iroi_w, arrows[arwIx].iroi_h);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
break;
}
cmd = String.Format("set params{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14}\r\n",
arwIx, ParamsSize,
arrows[arwIx].wmType,
arrows[arwIx].cx.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].cy.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].oroi_w.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].oroi_h.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].r1.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].r2.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].r3.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].a1.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].a2.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].step_a.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].nom_speed.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
arrows[arwIx].background_corr);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
break;
}
cmd = String.Format("set oroi{0} 0 0 {1} {2} 1\r\n",
arwIx, (int)(Math.Round(arrows[arwIx].oroi_w)), (int)(Math.Round(arrows[arwIx].oroi_h)));
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv==0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
break;
}
} //for
workerEvent.Set();
break;
}
*/
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Detect)
{
Command.Detect args = workerCmd as Command.Detect;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(string.Format("setbright {0}\r\n", Math.Max(0, Math.Min((int)(100.0f * args.Brightness), 100))),
out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
workerResponse = RetVal.Busy; // state -> State.CAMERA_BUSY
workerEvent.Set();
/// Common commands:
cmd = "delete -ex oroi1 oroi2 bkgnd1 bkgnd2 detected1 detected2\r\n";
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
if (RetVal.OK == (retv = WT_SSOp_FastCmd("loadflash\r\n")))
{
cmd = String.Format("new vecfloat params{0}({1}) vecint oroi{0}(5) matshort bkgnd{0}({2},{3}) matbyte detected{0}({4},{5})\r\n",
args.RoiNr,
ParamsSize,
(int)Math.Round(args.ORoiW),
(int)Math.Round(args.ORoiH),
args.IRoiW,
args.IRoiH);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
cmd = String.Format("set params{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14}\r\n",
args.RoiNr,
ParamsSize,
args.WMeterType,
args.CX.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.CY.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.ORoiW.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.ORoiH.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.R1.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.R2.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.R3.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.Ang1.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.Ang2.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.AngStep.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.NomSpeed.ToString("F2", System.Globalization.CultureInfo.InvariantCulture),
args.BackgroundCorr);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
cmd = String.Format("set oroi{0} 0 0 {1} {2} 1\r\n",
args.RoiNr, (int)Math.Round(args.ORoiW), (int)Math.Round(args.ORoiH));
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
if (args.WMeterType == 0)
{
///
/// wmType==0 commands:
///
cmd = String.Format("new vecint iroi{0}(5) periods timestamps cubbyte seq\r\n", args.RoiNr);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
cmd = String.Format("set iroi{0} {1} {2} {3} {4} 1\r\n",
args.RoiNr, args.IRoiX, args.IRoiY, args.IRoiW, args.IRoiH);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
StringBuilder sb = new StringBuilder(40);
for (int i = 0; i < args.SequenceLen; i++)
{
sb.Append(" ");
sb.Append((i % 2 == 0) ? "1" : args.SequenceTiming.ToString());
}
if (RetVal.OK == (retv = WT_SSOp_FastCmd(String.Format("set periods{0}\r\n", sb.ToString()))))
{
cmd = String.Format("grab seq iroi{0} {1} periods timestamps\r\n",
args.RoiNr, args.SequenceLen);
if (RetVal.OK == (retv = WT_SSOp_LongCmd(cmd)))
{
switch (args.RoiNr)
{
default: retv = 0; break;
case 2: retv = WT_SSOp_LongCmd_NoTmOut("mask seq iroi2 oroi1\r\n"); break;
case 3: retv = WT_SSOp_LongCmd_NoTmOut("mask seq iroi3 oroi1 oroi2\r\n"); break;
case 4: retv = WT_SSOp_LongCmd_NoTmOut("mask seq iroi4 oroi1 oroi2 oroi3\r\n"); break;
}
if (RetVal.OK == retv)
{
retv = WT_SSOp_LongCmd(String.Format("detect {0} seq periods detected{0}\r\n",
args.RoiNr));
if (retv == RetVal.OK)
{
// save
cmd = string.Format("save jpg detected{0} detected{0}\r\n", args.RoiNr);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
RetVal retv2 = (iretv <= 0 || received[0] < 0) ? RetVal.OpFailed : RetVal.OK;
if (retv2 == RetVal.OpInterrupted) retv = RetVal.OpInterrupted;
}
}
}
}
}
}
}
else if (args.WMeterType >= 1)
{ //
// wmType==1,2 commands:
//
cmd = String.Format("new matfloat homo vecint iroi{0}(5) cubbyte seq cubshort c1 matshort strip lsdbkg digits0\r\n", args.RoiNr);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
cmd = String.Format("set iroi{0} {1} {2} {3} {4} 1\r\n", args.RoiNr, args.IRoiX, args.IRoiY, args.IRoiW, args.IRoiH);
if (RetVal.OK == (retv = WT_SSOp_FastCmd(cmd)))
{
if (RetVal.OK == (retv = WT_SSOp_LongCmd(String.Format("grab seq iroi{0} 20 11\r\n", args.RoiNr))))
{
if (RetVal.OK == (retv = WT_SSOp_LongCmd(String.Format("detect {0} seq 1 detected{0} homo\r\n", args.RoiNr))))
{
// time 95s +/- 1.5 turns
if (RetVal.OK == (retv = WT_SSOp_LongCmd(String.Format("grab c1 oroi{0} 300 7\r\n", args.RoiNr))))
{
if (RetVal.OK == (retv = WT_SSOp_LongCmd_NoTmOut(String.Format("mount c1 oroi{0} homo strip lsdbkg 0\r\n", args.RoiNr))))
{
retv = WT_SSOp_LongCmd("getdigits strip digits0\r\n");
}
}
}
}
}
}
}
}
}
}
}
}
WT_SSOp_Complete(retv);
workerResponse = RetVal.OK;
workerEvent.Set();
}
/*
case WorkerCommand.VERIFY:
{
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt("verify\r\n", out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OP_FAILED;
workerEvent.Set();
break;
}
workerResponse = RetVal.BUSY; // state -> State.CAMERA_BUSY
workerEvent.Set();
workerResponse = RetVal.OK;
workerEvent.Set();
break;
}
*/
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Measure)
{
Command.Measure args = workerCmd as Command.Measure;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(string.Format("setbright {0}\r\n", Math.Max(0, Math.Min((int)(100.0f * args.Brightness), 100))),
out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
int logLen = 400000 / (int)Math.Round(args.ORoiW) / (int)Math.Round(args.ORoiH);
if (logLen < 2) logLen = 2;
if (args.WMeterType == 0)
{
cmd = String.Format("new vecint iroi{0}(5) snaptimes(10) cubshort snaps({1},{2},10) log({1},{2},{3}) int shift\r\n",
args.RoiNr, (int)Math.Round(args.ORoiW), (int)Math.Round(args.ORoiH), logLen);
}
else
{
cmd = String.Format("new vecint iroi{0}(5) snaptimes(10) cubshort snaps({1},{2},10) lsdlog int shift\r\n",
args.RoiNr, (int)Math.Round(args.CX), (int)Math.Round(args.CY)); // snaps(cx,cy,10) ... dimensions
}
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv<=0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
cmd = String.Format("set iroi{0} {1} {2} {3} {4} 1\r\n",
args.RoiNr, args.IRoiX, args.IRoiY, args.IRoiW, args.IRoiH);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
/*
cmd = String.Format("getshift seq iroi{0} shift {1}\r\n", args.RoiNr, 30);
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
*/
if (args.WMeterType == 0 && args.MaxMvmt == 0 && args.MinMvmt == 0)
{
///
/// Std: Uses 'initSpeed'
///
cmd = String.Format("task 1 oroi{0} 1 {1} {2} shift snaps snaptimes log {3} params{0} bkgnd{0}\r\n",
args.RoiNr,
MesurementPeriod_Frames,
(args.Triggered ? "1" : "0"),
logLen);
serial.FifoFlush();
serial.WriteString(cmd); // send command
}
else if (args.WMeterType == 0)
{
//
// Introduced in ver.7.6.7:
// Uses 'maxMvmt' and 'minMvmt', allows faster movement measurement
//
cmd = String.Format("task 1 oroi{0} 1 {1} {2} shift snaps snaptimes log {3} params{0} bkgnd{0} {4} {5}\r\n",
args.RoiNr,
MesurementPeriod_Frames,
(args.Triggered ? "1" : "0"),
logLen,
args.MaxMvmt,
args.MinMvmt);
serial.FifoFlush();
serial.WriteString(cmd); // send command
}
else if (args.WMeterType >= 1)
{
//
// Digital counters (Dubai)
//
cmd = String.Format("task {0} oroi{1} 1 {2} {3} shift snaps snaptimes 0 0 homo digits0 params{1} lsdbkg 36 lsdlog\r\n",
args.WMeterType + 1,
args.RoiNr,
MesurementPeriod_Frames,
(args.Triggered ? "1" : "0"));
serial.FifoFlush();
serial.WriteString(cmd); // send command
}
else
{
// ...
}
// clear measurement data
measurements.Clear();
wm_nrBegin = 0;
wm_nrEnd = 0;
wm_timestampBegin = 0;
wm_timestampEnd = 0;
workerResponse = RetVal.Busy; // state -> State.CAMERA_BUSY
workerEvent.Set();
// start reading data
byte znak;
bool stopOpReceived = false;
int angle;
uint time;
while (true)
{
// wait for '>' character, check for WorkerCommand.STOP_OP
do {
if (!stopOpReceived && WorkerCommand.StopOp == WT_SSOp_Wait4StopOp(5))
{
stopOpReceived = true;
serial.WriteByte((byte)'Q');
}
if (RetVal.OK != (retv = serial.ReadByte(out znak))) /// if ReadByte_C fails => quit the loop ...
{ /// ... and return negative error code
break;
}
}
while (znak != '>');
if (retv != RetVal.OK) break; /// communication failed
/// Read the rest of line
StringBuilder restOfLine = new StringBuilder();
while (RetVal.OK == (retv = serial.ReadByte(out znak)) &&
(znak != (byte)'\r') && (znak != (byte)'\n'))
{
restOfLine.Append((char)znak);
}
if (retv != RetVal.OK) break;
log.InfoFormat("Received: >{0}", restOfLine);
/// Parse the line, save and send the result
string[] results = restOfLine.ToString().Split(new char[] { ' ' });
if ((results.Length >= 3) && results[1].Equals("0") && results[2].Equals("OK"))
{
retv = RetVal.OK; /// Op. successfully completed
break;
}
else if (results.Length < 3 || !UInt32.TryParse(results[1], out time) || !Int32.TryParse(results[2], out angle))
{
retv = RetVal.OpFailed; /// Op. failed
log.ErrorFormat("RetVal.OpFailed", restOfLine);
break;
}
if (!stopOpReceived)
{
if ((time > 0) && (measurements.Count < MaxMeasurementsCount))
{
if (angle == (int)MARK.DUMMY)
{
// do nothing
}
else if (angle == (int)MARK.FALLING)
{
wm_nrBegin = measurements.Count;
wm_timestampBegin = time;
//m_pWnd->PostMessage(WM_USER, EVENT_DATA_READY+m_cameraNr, ID_BEGIN); <------- TODO
}
else if (angle == (int)MARK.RISING)
{
wm_nrEnd = measurements.Count;
wm_timestampEnd = time;
//m_pWnd->PostMessage(WM_USER, EVENT_DATA_READY+m_cameraNr, ID_END); <------- TODO
}
else
{
measurements.Add(new Measurement(time, angle));
//m_pWnd->PostMessage(WM_USER, EVENT_DATA_READY+m_cameraNr, wm_nrmeasurements); <------- TODO
}
}
}
else if (retv == RetVal.OK && time == 0)
{
/// Wait until '$'
do {
if (RetVal.OK != (retv = serial.ReadByte(out znak))) /// if ReadByte_C fails => quit ...
break; //return -retv; /// ... the loop and return negative ...
} /// ... error code
while (znak != '$');
break;
}
}
if (retv != RetVal.OK && !stopOpReceived)
{
//m_pWnd->PostMessage(WM_USER, EVENT_OP_FAILED+m_cameraNr, 0); <------- TODO
idcState = IdcState.OpFailed;
WT_SSOp_Wait4StopOp(Timeout.Infinite);
}
workerResponse = RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Other)
{
Command.Other args = workerCmd as Command.Other;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
iretv = serial.CommandInt(args.Command + "\r\n", out received, 1, out m_errorStr);
if (iretv < 0) workerResponse = (RetVal)(-iretv);
else if (iretv==0) workerResponse = RetVal.OpFailed;
else if (received[0] < 0) workerResponse = (RetVal)(-received[0]);
else workerResponse = RetVal.OK;
workerEvent.Set();
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.Stream)
{
Command.Stream args = workerCmd as Command.Stream;
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
/// Check the camera file I/O state
while (true)
{
iretv = serial.CommandInt("fiostate\r\n", out received, 1, out m_errorStr);
if (iretv <= 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
else if (received[0] == 0)
{
break; /// Continue - start a stream operation
}
}
iretv = serial.CommandInt(string.Format("setbright {0}\r\n", Math.Max(0, Math.Min((int)(100.0f * args.Brightness), 100))),
out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
/// Grab one image
if (args.Type != StreamType.Full)
{
iretv = serial.CommandInt("acqimage\r\n", out received, 1, out m_errorStr);
if (iretv <= 0 || received[0] < 0)
{
workerResponse = RetVal.OpFailed;
workerEvent.Set();
continue;
}
}
/// Prepare the camera command string
if (args.Format == FileFormat.Bmp)
{
if (args.Type == StreamType.SubSampled) cmd = "streamssdbmp\r\n";
else if (args.Type == StreamType.Focus) cmd = "streamroibmp\r\n";
else cmd = "streambmp\r\n";
}
else if (args.Format == FileFormat.Jpeg)
{
if (args.Type == StreamType.SubSampled) cmd = "streamssdjpg\r\n";
else if (args.Type == StreamType.Focus) cmd = "streamroijpg\r\n";
else cmd = "streamjpg\r\n";
}
else
{
workerResponse = RetVal.OK;
workerEvent.Set();
continue;
}
/// Start streaming
iretv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (iretv >= 1 && received[0] == 0)
{
workerResponse = RetVal.Busy; // state -> State.CAMERA_BUSY
workerEvent.Set();
WorkerCommand wrkCmd = WT_SSOp_Wait4StopOp(Timeout.Infinite);
/// Stop streaming
iretv = serial.CommandInt("stopstream\r\n", out received, 1, out m_errorStr);
if (iretv >= 1 && received[0] == 0)
{
workerResponse = RetVal.OK; // state -> State.CAMERA_IDLE
workerEvent.Set();
}
if (wrkCmd != WorkerCommand.StopOp)
{
WT_SSOp_Wait4StopOp(Timeout.Infinite);
workerResponse = RetVal.OK; // state: State.CAMERA_OP_COMPLETED -> State.CAMERA_IDLE or
workerEvent.Set();
}
}
else
{
/// Streaming was not started, return error and wait for StopOp
workerResponse = RetVal.OpFailed; // state -> State.CAMERA_OP_FAILED
workerEvent.Set();
WT_SSOp_Wait4StopOp(Timeout.Infinite);
workerResponse = RetVal.OK; // state -> State.CAMERA_IDLE
workerEvent.Set();
}
}
//-------------------------------------------------------------------------------------------
else if (workerCmd is Command.StopStream)
{
Command.StopStream args = workerCmd as Command.StopStream;
}
} // end while (true)
}
//---------------------------------------------------------------------
// Sends command and waits for a response.
//
// Arguments:
// cmd ........ command
// Returns:
// long ... 0 = command completed OK, error code=0
// 1...999 = command completed with an error code
// RetVal.OP_INTERRUPTED = StopOp was received by the OCX component
// 1000... = camera error (communication timeout ?)
//---------------------------------------------------------------------
RetVal WT_SSOp_FastCmd(string cmd)
{
if (WorkerCommand.StopOp == WT_SSOp_Wait4StopOp(1))
{
return RetVal.OpInterrupted; /// This error code has the priority to avoid deadlocks
}
int[] received = new int[1];
received[0] = 0; /// OK in debug mode
/// Send a command that cannot be interrupted via 'Q'
int readByteRetv = serial.CommandInt(cmd, out received, 1, out m_errorStr);
if (readByteRetv<0) return (RetVal)(-readByteRetv); /// possibly a camera timeout
return (RetVal)(-received[0]); /// <--- normal return from the operation
}
//---------------------------------------------------------------------
// Sends command and waits for "> 'received' 'string'" or sends 'Q'
// after CMD_STOP_OP. Then waits for a prompt '$'.
// Waits until '>' is received.
//
// Arguments:
// cmd ........ command
// Returns:
// long ... 0 = command completed OK, error code=0
// 1...999 = command completed with an error code
// RetVal.OP_INTERRUPTED = StopOp was received by the OCX component
// 1000... = camera error (communication timeout ?)
//---------------------------------------------------------------------
RetVal WT_SSOp_LongCmd(string cmd)
{
/// Send the command
serial.FifoFlush();
serial.WriteString(cmd);
RetVal readByteRetv;
byte znak;
/// When WorkerCommand.STOP_OP arrives, 'Q' character is sent to abort the operation.
/// Then the loop still waits until '>' is received.
bool stopOpReceived = false;
do {
if (!stopOpReceived && WorkerCommand.StopOp == WT_SSOp_Wait4StopOp(5))
{
/// send 'Q' if CMD_STOP_OP worker thread command is received
stopOpReceived = true;
serial.WriteByte((byte)'Q');
}
if (RetVal.OK != (readByteRetv = serial.ReadByte(out znak))) break;
/// if ReadByte_C fails quit the loop and return negative error code
}
while (znak != (byte)'>');
if (stopOpReceived) return RetVal.OpInterrupted; /// StopOp: This error code has the priority to avoid deadlocks
if (readByteRetv != RetVal.OK) return readByteRetv; /// Possibly a camera communication timeout
/// Read a line of text from IDC terminated by '\r' (and '\n')
StringBuilder tmp = new StringBuilder();
do
{
if (RetVal.OK != (readByteRetv = serial.ReadByte(out znak))) break;
if (znak == (byte)'\r') break;
tmp.Append((char)znak);
}
while (true);
log.InfoFormat("{0}: Received: >{1}", cameraNr, tmp);
if (readByteRetv != RetVal.OK) return readByteRetv; /// Return on error
/// Parse the line after '>'.
/// Read two fields: Return code and the rest of the line.
const int maxArrayLen = 3;
string[] strArray = tmp.ToString().Split(new char[] {' '}, maxArrayLen);
///
if (strArray.Length < 3) return RetVal.CommError; /// Unexpected format, there should be at least 2 strings
///
int negativeIdcReturnCode;
if (!Int32.TryParse(strArray[1], out negativeIdcReturnCode))
{
return RetVal.CommError;
}
else if (negativeIdcReturnCode < 0)
{
m_errorStr = strArray[2];
}
/// Read characters until '$' received
do {
if (0 != (readByteRetv = serial.ReadByte(out znak))) break;
}
while (znak != '$');
if (readByteRetv != RetVal.OK) return readByteRetv; /// Possibly a camera communication timeout
return (RetVal)(-negativeIdcReturnCode); /// Normal return from the operation
}
//----------------------------------------------------------------------------
// Sends command and waits for "> 'received' 'string'" or sends 'Q'
// after CMD_STOP_OP. Then waits for a prompt '$'.
//
// Arguments:
// cmd ........ command
// Returns:
// long ... 0 = command completed OK, error code=0
// 1...999 = command completed with an error code
// RetVal.OP_INTERRUPTED = StopOp was received by the OCX component
// 1000... = camera error (communication timeout ?)
//----------------------------------------------------------------------------
RetVal WT_SSOp_LongCmd_NoTmOut(string cmd)
{
/// Send the command
serial.FifoFlush();
serial.WriteString(cmd);
RetVal readByteRetv;
byte znak;
/// When WorkerCommand.STOP_OP arrives, 'Q' character is sent to abort the operation.
/// Then the loop still waits until '>' is received.
bool stopOpReceived = false;
do {
if (!stopOpReceived && WorkerCommand.StopOp == WT_SSOp_Wait4StopOp(5))
{
// send 'Q' if CMD_STOP_OP worker thread command is received
stopOpReceived = true;
serial.WriteByte((byte)'Q');
}
readByteRetv = serial.ReadByte(out znak); /// Do not quit the loop on timeout (???)
}
while (znak != '>');
if (stopOpReceived) return RetVal.OpInterrupted; /// StopOp: This error code has the priority to avoid deadlocks
if (readByteRetv != RetVal.OK) return readByteRetv; /// Possibly a camera communication timeout
/// Read a line of text from IDC terminated by '\r' (and '\n')
StringBuilder tmp = new StringBuilder();
do
{
if (RetVal.OK != (readByteRetv = serial.ReadByte(out znak))) break;
if (znak == (byte)'\r') break;
tmp.Append((char)znak);
}
while (true);
if (readByteRetv != RetVal.OK) return readByteRetv; /// Return on error
/// Parse the line after '>'.
/// Read two fields: Return code and the rest of the line.
const int maxArrayLen = 2;
string[] strArray = tmp.ToString().Split(new char[] { ' ' }, maxArrayLen);
///
if (strArray.Length < 2) return RetVal.OpFailed; /// Unexpected format, there should be at least 2 strings
///
int negativeIdcReturnCode;
Int32.TryParse(strArray[0], out negativeIdcReturnCode);
if (negativeIdcReturnCode < 0) m_errorStr = strArray[1];
/// Read characters until '$' received
do
{
if (0 != (readByteRetv = serial.ReadByte(out znak))) break;
}
while (znak != '$');
if (readByteRetv != RetVal.OK) return readByteRetv; /// Possibly a camera communication timeout
return (RetVal)(-negativeIdcReturnCode); /// Normal return from the operation
}
//---------------------------------------------------------------------
// Sends OP_COPMPETED / OP_FAILED message and waits for StopOp.
//
// Arguments:
// errorCode ... RetVal.OP_INTERRUPTED, !!!do not issue any message anymore
// < 1000 command line response (number after >), or
// >=1000 error code (camera timeout, etc.)
// Returns:
// long ........ 0 = OK ... 'received' is valid
// RetVal.COMM_TIEMOUT
//---------------------------------------------------------------------
void WT_SSOp_Complete(RetVal errorCode)
{
if (errorCode == RetVal.OpInterrupted) return;
// Send an appropriate message to the control
if (errorCode == RetVal.OK)
{
//m_pWnd->PostMessage(WM_USER, EVENT_OP_COMPLETED+m_cameraNr, 0); <------- TODO
idcState = IdcState.OpCompleted;
}
else
{
//m_pWnd->PostMessage(WM_USER, EVENT_OP_FAILED+m_cameraNr, -errorCode); <------- TODO
idcState = IdcState.OpFailed;
}
// Wait for StopOp
WT_SSOp_Wait4StopOp(Timeout.Infinite);
}
/** ------------------------------------------------------------------------------
* Waits for CMD_STOP_OP command. Other commands are ignoerd.
*
* Arguments:
* ms .............. timeout in ms or INFINITE (default)
* Returns:
* WorkerCommand.STOP_OP ... STOP_OP received
* WorkerCommand.Timeout ... time expired, no STOP_OP received
* ------------------------------------------------------------------------------- */
WorkerCommand WT_SSOp_Wait4StopOp(int timeoutMs)
{
while (true)
{
if (workerCommandEvent.WaitOne(timeoutMs))
{
if (workerCmd is Command.StopOp) return WorkerCommand.StopOp;
}
else
{
return WorkerCommand.Timeout;
}
}
}
}
}