/// /// Copyright (c) 2013-2015 Sensus Metering Systems /// 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 } /// Version string public string Version { get { return cameraVersionStr; } } string cameraVersionStr; /// IDC100 version, valid after 'Connect' /// /// Private fields /// 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 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; /// /// The angle difference since the start of the measurement operation (the start mark) /// public int Pulses { get { if (measurements.Count < 1 || wm_nrBegin >= measurements.Count) { return 0; } return measurements[measurements.Count - 1].angle - measurements[wm_nrBegin].angle; } } /// /// The angle difference between the end and the start of the measurement operation /// 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; } } 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; /// /// Constructor /// /// Camera name = 'Images' subdirectory name) /// Com port number 1..999 /// Baud rate 57600 or 115200 /// Relative brightness 0..1.0f public Idc100(string name, int cameraNr, int comPortNr, int baudRate, float brightness) { this.comPortNr = comPortNr; this.baudRate = baudRate; this.brightness = brightness; this.cameraNr = cameraNr; /// 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(); 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, IdcState.DetectionFailed }; 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, IdcState.DetectionFailed }; 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; } } /// /// Shut down Idc100 operation, stop the worker thread. /// 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 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 ((retv > RetVal.OK) && retv < (RetVal.HOST_START)) { /// This is a detection error, no timeout or fatal error retv = RetVal.DetectionFailed; } } } } } } } 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} {4}\r\n", args.RoiNr, MesurementPeriod_Frames, (args.Triggered ? "1" : "0"), logLen, 30); 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) { if (wm_nrBegin == 0) { wm_nrBegin = measurements.Count; wm_timestampBegin = time; //m_pWnd->PostMessage(WM_USER, EVENT_DATA_READY+m_cameraNr, ID_BEGIN); <------- TODO } else { wm_nrEnd = measurements.Count; wm_timestampEnd = time; //m_pWnd->PostMessage(WM_USER, EVENT_DATA_READY+m_cameraNr, ID_END); <------- 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) { idcState = IdcState.OpCompleted; } else if (errorCode == RetVal.DetectionFailed) { idcState = IdcState.DetectionFailed; } else { 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; } } } } }