public void ConnectLMMMInstruments() { if (!Instruments.Active.HasSocketBasedLM()) { return; } LMInstrument lmi = (LMInstrument)Instruments.Active.FirstLM(); // for the LMs // Start listening for instruments. StartLMDAQServer((LMConnectionInfo)lmi.id.FullConnInfo); // NEXT: socket reset should occur here for robust restart and recovery collog.TraceInformation("Broadcasting to LM instruments. . ."); // broadcast message to all subnet (configurable, defaulting to 169.254.x.x) addresses. This is the instrument group. // look for the number of requested instruments DAQControl.LMMMComm.PostLMMMCommand(LMMMLingo.Tokens.broadcast); collog.TraceInformation("Sent broadcast. Waiting for LM instruments to connect"); // wait until enough time has elapsed to be sure live instruments can report back Thread.Sleep(lmi.id.FullConnInfo.Wait); // todo: configure this with a unique wait parameter value if (!LMMMComm.LMServer.IsRunning) { collog.TraceEvent(LogLevels.Error, 0x2A29, "No socket server for LM support running"); } }
/// <summary> /// Checks control state for DAQ continuation, then /// If at the end of a cycle /// 1) finishes cycle processing (wait for analyzer completion, get results, summarize counts, cycle conditioning steps) /// a) starts the next assay cycle, or /// b) notifies controller of DAQ measurement completion /// </summary> /// <param name="activeInstr">instrument object associated with the current DAQ state</param> /// <param name="sb">status block object indicating end of a cycle</param> internal static void HandleEndOfCycleProcessing(LMInstrument activeInstr, Analysis.StreamStatusBlock sb) { activeInstr.RDT.PlaceStatusTextOnCurrentCycle(sb); bool done = true; // assume done for all instruments activeInstr.DAQState = DAQInstrState.Online; // tbd RR: need to lock this // for each networked instrument // check ALL instrument for done so we can set the assay.state to done or repeat // only look at active instrs in the listbox list. for (int j = 0; j < Instruments.Active.Count; j++) // NEXT: revisit this for mixing of the LM and SR behaviors { if (Instruments.Active[j].DAQState != DAQInstrState.Online) { done = false; break; } } if (done) // all are done { CurState.State = DAQInstrState.Online; gControl.netlog.TraceInformation("Assay cycle " + CurState.Measurement.CurrentRepetition + " complete"); if ((CurState.Measurement.CurrentRepetition < CurState.Measurement.RequestedRepetitions) || (CurState.Measurement.RequestedRepetitions == 0) && !CurState.IsQuitRequested) { // dev note: this could be spawned in a task because the end processing can be time consuming, delaying the start of next DAQ iteration bool ok = activeInstr.RDT.EndOfCycleProcessing(CurState.Measurement); if (ok) // start the next cycle { gControl.FireEvent(EventType.ActionInProgress, gControl); gControl.StartLM_SRAssay(); } else { gControl.MajorOperationCompleted(); // the overall pend handle used by cmd line } } else { gControl.netlog.TraceInformation("All assay cycles completed"); activeInstr.RDT.EndOfCycleProcessing(CurState.Measurement); // do final processing on the last cycle, then do the last cycle closure processing activeInstr.RDT.EndOfCycleProcessing(CurState.Measurement, last: true); gControl.MajorOperationCompleted(); // the overall pend handle used by cmd line } } }
public LMInstrument MatchByPort(int Port) { return((LMInstrument)this.Find(i => { if (i is LMInstrument) { LMInstrument lm = (LMInstrument)i; return lm.port == Port; } else { return false; } } )); }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> static void SL_ClientConnected(object sender, SocketAsyncEventArgs e) { connections = Interlocked.Increment(ref connections); Socket s = e.UserToken as Socket; System.Net.IPEndPoint ep = (System.Net.IPEndPoint)s.RemoteEndPoint; gControl.netlog.TraceInformation("New Connection : " + s.RemoteEndPoint.ToString()); LMInstrument lmi = new LMInstrument(e, ep.Port); Instruments.All.Add(lmi); // dev note: need a parallel entry in the counting parameters map on the enclosing Measurement for each instrument and it;s SR params class instance // get the status of the instrument DAQControl.ReadInstrStatus(lmi); }
public void ApplyInstrumentSettings() { foreach (Instrument instrument in Instruments.Active) { try { instrument.ApplySettings(); } catch (Exception ex) { collog.TraceException(ex); } } // for now, this is for the LMs only if (!Instruments.Active.HasConnectedLM()) { return; } LMInstrument lm = (LMInstrument)Instruments.Active.AConnectedLM(); LMConnectionInfo lmc = (LMConnectionInfo)lm.id.FullConnInfo; if (lm.SocketBased()) // it's an LMMM { // look for any flags requiring conditioning of the instrument prior to assay or HV // e.g. input=0, the arg to each is already parsed in the command line processing state //if (NC.App.Config.LMMM.isSet(LMFlags.input)) { DAQControl.LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.input, lmc.DeviceConfig.Input); } //if (NC.App.Config.LMMM.isSet(LMFlags.debug)) { DAQControl.LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.debug, lmc.DeviceConfig.Debug); } //if (NC.App.Config.LMMM.isSet(LMFlags.leds)) { DAQControl.LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.leds, lmc.DeviceConfig.LEDs); } //if (NC.App.Config.LMMM.isSet(LMFlags.hv)) { DAQControl.LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.hvset, lmc.DeviceConfig.HV); } } else // its a PTR-32 { } }
static void PacketLogSLOW(LMInstrument activeInstr, SocketAsyncEventArgs e) { // my little hack by Joe Longo, where I learn by doing byte[] bstr1 = new byte[e.BytesTransferred]; Array.Copy(e.Buffer, e.Offset, bstr1, 0, e.BytesTransferred); string tesmp = bytestoASCIIchars(bstr1, e.BytesTransferred, 132); string eos = ((e.BytesTransferred % 2) == 0 ? "EVEN " : "ODD "); ulong buffo = 0; if (activeInstr != null) { if (activeInstr.RDT != null) { buffo = activeInstr.NumProcessedRawDataBuffers; } eos += activeInstr.DAQState.ToString(); } gControl.netlog.TraceEvent(LogLevels.Verbose, 696, "{0}:{1} {2} bytes, state {3}", buffo, packets, e.BytesTransferred, eos); gControl.netlog.TraceEvent(LogLevels.Verbose, 697, ">>>" + tesmp); }
// get the LM ranking position (0, 1, 2, etc) public int RankPositionInList(LMInstrument inst) { int idx = 0; for (int i = 0; i < this.Count; i++) { if (this[i] is LMInstrument) { if (this[i].Equals(inst)) { return(idx); } else { idx++; } } } return(-1); }
void DisconnectFromLMInstruments() { if (Instruments.Active.HasSocketBasedLM()) { if (_SL == null) { return; } // Stop incoming accepts _SL.Stop(); IEnumerator iter = Instruments.Active.GetLMEnumerator(); // Close all connected instruments while (iter.MoveNext()) { LMInstrument lmi = (LMInstrument)iter.Current; if (lmi.id.SRType.IsSocketBasedLM()) { _SL.StopClient(lmi.instrSocketEvent); } } } }
/// <summary> /// Prepare a detector for live assay/HV by adding it to the active list. /// </summary> /// <param name="det"></param> public static void ActivateDetector(Detector det) { if (det.Id.SRType.IsSocketBasedLM()) { LMInstrument lm = new LMInstrument(det); lm.DAQState = DAQInstrState.Offline; // these are manually initiated as opposed to auto-pickup lm.selected = false; //must broadcast first to get it selected if (!Instruments.All.Contains(lm)) { Instruments.All.Add(lm); // add to global runtime list } } else if (det.Id.SRType.IsUSBBasedLM()) { Ptr32Instrument ptr = new Ptr32Instrument(det); ptr.DAQState = DAQInstrState.Offline; // these are manually initiated as opposed to auto-pickup if (!Instruments.All.Contains(ptr)) { Instruments.All.Add(ptr); // add to global runtime list } } }
// still need to test if this works // typing 'stop' at prompt stops the current cycle, but not the overall processing state, this method should now stop the entire process // devnote: Could just use a timer-based check of the token, same as for progress polling into the analyzer /// <summary> /// send the cancel command to each LMMM, set the instrument state Online to prevent data processing of any additional packets /// </summary> /// <param name="removeCurNCDFile">delete the current NCD files created for the current interval</param> private void StopLMCAssay(bool removeCurNCDFile) { collog.TraceEvent(LogLevels.Info, 0, "Stopping assay..."); CurState.State = DAQInstrState.Online; // stop each instrument in the active list foreach (Instrument active in Instruments.Active) { //This new from USB version incc6, commenting out has no effect on doubles/triples errors hn 9/22/2014 active.StopAssay(); // send cancel command to the LMMM instruments if (active is LMInstrument && ((LMInstrument)active).SocketBased()) { LMInstrument lmi = active as LMInstrument; LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.cancel, 0, Instruments.Active.RankPositionInList(lmi)); // send to all active, 1 by 1 if (collectingFileData && lmi.file != null) { lmi.file.CloseWriter(); if (removeCurNCDFile) { lmi.file.Delete(); } } active.DAQState = DAQInstrState.Online; } else if (active is SRInstrument) { // tell the SR thread handler to cancel it ctrllog.TraceInformation("Stop SR {0}", active.id.IdentName()); SRWrangler.StopThread(active as SRInstrument, true); active.DAQState = DAQInstrState.Offline; } } ctrllog.TraceInformation("Assay cancelled"); NC.App.Loggers.Flush(); }
static public void ReadInstrStatus(LMInstrument lmi) { DAQControl.LMMMComm.FormatAndSendLMMMCommand(LMMMLingo.Tokens.cstatus, 0, Instruments.Active.RankPositionInList(lmi)); }
/// <summary> /// Handle data from the client sockets /// </summary> /// <param name="sender"></param> /// <param name="e"></param> static void SL_DataReceived(object sender, SocketAsyncEventArgs e) { Socket s = e.UserToken as Socket; System.Net.IPEndPoint ep = (System.Net.IPEndPoint)s.RemoteEndPoint; packets = Interlocked.Increment(ref packets); // call the specific instrument handler here using the ID. // This routine is needed if there are more than one type of instrument. // match with port it came from, each connection will have a different port. LMInstrument activeInstr = Instruments.Active.MatchByPort(ep.Port); // dev note: this might be slow, could speed up this by switching to a map rather than a list bool verbose = gControl.netlog.ShouldTrace(LogLevels.Verbose); if (verbose) { PacketLogSLOW(activeInstr, e); } if (activeInstr.DAQState == DAQInstrState.ReceivingData) { activeInstr.NumProcessedRawDataBuffers++; if (verbose) /* diag buffer tracing */ { string temp = string.Format("{0}: bytes {1}, total bytes {2}, LM {3}", activeInstr.NumProcessedRawDataBuffers, e.BytesTransferred, numTotalBytes, Instruments.Active.IndexOf(activeInstr)); gControl.netlog.TraceEvent(LogLevels.Verbose, 686, temp); } try { if (CurState.IsQuitRequested) { throw new AnalysisDefs.CancellationRequestedException(); } else if ((e.BytesTransferred % 2) == 0) // EVEN messages are data. { // dev note: file writing is controlled via LiveFileWrite (activeInstr.file as NCCFile.NCDFile).Write(e.Buffer, e.Offset, e.BytesTransferred); try { // this method copies the buffer and sends it on to neutron counting var res = activeInstr.RDT.PassBufferToTheCounters(e.Buffer, e.Offset, e.BytesTransferred); if (res != null) //Handle this error condition as if it is a regular ODD-count packet with the end marker { HandleEndOfCycleProcessing(activeInstr, res); } } catch (Exception ex) { HandleFatalGeneralError(activeInstr, ex); } } else // ODD - last data is the status message. { try { LMComm.LMMMLingo.Tokens response = LMMMComm.DataPacketResponseMatch(e.Buffer, e.Offset, e.BytesTransferred); // command parsing here should be as fast as possible because data collection is active and may be hampered by even short delays in this section // it is a status message, the last message of an assay if (response == LMComm.LMMMLingo.Tokens.statusdata) // dev note: must be odd length and end with '......' or '......' (old style) or else start with 'Status\r\n' (new style Nov. 2010) { try // // write the last message to the file.This might be a partial data + last message { (activeInstr.file as NCCFile.NCDFile).Write(e.Buffer, e.Offset, e.BytesTransferred); (activeInstr.file as NCCFile.NCDFile).CloseWriter(); } catch (Exception fex) { if ((activeInstr.file as NCCFile.NCDFile).stream != null) { gControl.netlog.TraceEvent(LogLevels.Error, 642, "{0}: error on close {1}", (activeInstr.file as NCCFile.NCDFile).stream.Name, fex.Message); } } var res = activeInstr.RDT.PassBufferToTheCounters(e.Buffer, e.Offset, e.BytesTransferred); HandleEndOfCycleProcessing(activeInstr, res); } else if (response == LMComm.LMMMLingo.Tokens.tosenddatasize) // this says how many bytes are going to be sent { numTotalBytes = LMMMComm.ResponseToSendDataSize(e.Buffer, e.Offset, e.BytesTransferred); // t gControl.netlog.TraceEvent(LogLevels.Verbose, 654, "Expecting " + Convert.ToString(numTotalBytes) + " (to sen)"); } else if (response == LMComm.LMMMLingo.Tokens.unrecognizeddata) // unrecognized command { string temp = LMMMComm.ResponseUnrecoSample(e.Buffer, e.Offset, e.BytesTransferred); gControl.netlog.TraceInformation(temp); } else // it might be an odd message with some data tacked on the beginning { if (gControl.collectingFileData) { (activeInstr.file as NCCFile.NCDFile).Write(e.Buffer, e.Offset, e.BytesTransferred); (activeInstr.file as NCCFile.NCDFile).CloseWriter(); } if (response == LMComm.LMMMLingo.Tokens.rates) // somehow got a rates block { RatesStatus p = new RatesStatus(); String received = LMMMComm.NonDataResponse(e.Buffer, e.Offset, e.BytesTransferred); LMMMComm.SplitRatesReadResponse(received, ref p); gControl.netlog.TraceInformation("ReceivingData rates {0} on LM {1}:{2}", p.ToString(), Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId); } CurState.State = DAQInstrState.Online; gControl.netlog.TraceInformation("Cycle " + CurState.Measurement.CurrentRepetition + " complete"); if ((CurState.Measurement.CurrentRepetition < CurState.Measurement.RequestedRepetitions) || (CurState.Measurement.RequestedRepetitions == 0)) { bool ok = activeInstr.RDT.EndOfCycleProcessing(CurState.Measurement); if (ok) { gControl.FireEvent(EventType.ActionInProgress, gControl); gControl.StartLM_SRAssay(); } else { gControl.MajorOperationCompleted(); // the overall pend handle used by cmd line } } else { gControl.netlog.TraceInformation("All assay cycles completed, but with data in an odd-sized packet"); bool ok = activeInstr.RDT.EndOfCycleProcessing(CurState.Measurement, last: true); gControl.MajorOperationCompleted(); // the overall pend handle used by cmd line } } } catch (AnalysisDefs.FatalNeutronCountingException fae) // propagated up from the AnalysisHandler { HandleFatalGeneralError(activeInstr, fae); } catch (AnalysisDefs.CancellationRequestedException) // thrown from this method { StopActiveAssayImmediately(); } catch (Exception oddex) { gControl.netlog.TraceEvent(LogLevels.Error, 643, "Internal error, stopping active processing, {0}: Odd data length handler: {1}", activeInstr.NumProcessedRawDataBuffers, oddex.Message); HandleFatalGeneralError(activeInstr, oddex); } } } catch (AnalysisDefs.CancellationRequestedException) // thrown from this method { StopActiveAssayImmediately(); } if (verbose) { gControl.netlog.Flush(); } } else if (activeInstr.DAQState == DAQInstrState.Online || activeInstr.DAQState == DAQInstrState.HVCalib) // we are not taking data. { String received = LMMMComm.NonDataResponse(e.Buffer, e.Offset, e.BytesTransferred); if (activeInstr.IsNew()) { string iname = String.Empty; string type = InstrType.LMMM.ToString(); LMMMComm.SplitBroadcastResponse(received, ref type, ref iname, ref activeInstr.id.version); activeInstr.id.DetectorId = iname; activeInstr.id.SetSRType(type); gControl.netlog.TraceInformation("The new instrument is " + LMLoggers.LognLM.FlattenChars(received)); gControl.netlog.TraceInformation(Instruments.All.Count + " instrument(s) online"); activeInstr.selected = true; // this should only be set if there is no UI CurState.State = DAQInstrState.Online; gControl.FireEvent(EventType.ActionPrep, gControl); } else { // slow parsing in this section is fine because data collection is not occurring LMComm.LMMMLingo.Tokens response = LMMMComm.ResponseMatchPrefix(received); if (response == LMComm.LMMMLingo.Tokens.cstatus) // it is a status readback { LMMMComm.SplitCStatusResponse(received, ref activeInstr.lmstatus); gControl.netlog.TraceInformation( "cStatus for LM {0}:{1} is dbg:{2}, leds:{3}, input:{4}, HVset:{5}, HV:{6}, LLD Max:{7}, LLD:{8}, (u1:{9})", Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId, activeInstr.lmstatus.debug, activeInstr.lmstatus.leds, activeInstr.lmstatus.inputPath, activeInstr.lmstatus.setpoint, activeInstr.lmstatus.hv, activeInstr.lmstatus.MaxLLD, activeInstr.lmstatus.LLD, activeInstr.lmstatus.u1); } else if (response == LMComm.LMMMLingo.Tokens.hvread) // it is a hv readback { int hv = 0; LMMMComm.SplitHVReadResponse(received, ref hv); gControl.netlog.TraceInformation("HVread {0} volts for LM {1}:{2}", hv, Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId); } else if (response == LMComm.LMMMLingo.Tokens.hvcalib) // it is a hv calibration point { HVControl.HVStatus hvst = new HVControl.HVStatus(); LMMMComm.SplitHVCalibResponse(received, ref hvst); gControl.AppendHVCalibration(hvst); gControl.netlog.TraceInformation("HVcalib for LM {0}:{1} is [setpt:{2}, read:{3}, . . .]", Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId, hvst.HVsetpt, hvst.HVread); gControl.StepHVCalibration(); } else if (response == LMComm.LMMMLingo.Tokens.rates) // it is a rates response { RatesStatus p = new RatesStatus(); LMMMComm.SplitRatesReadResponse(received, ref p); gControl.netlog.TraceInformation("Rates {0} on LM {1}:{2}", p.ToString(), Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId); } else if (response == LMComm.LMMMLingo.Tokens.power) // it is a power status { PowerStatus p = new PowerStatus(); LMMMComm.SplitPowerReadResponse(received, ref p); gControl.netlog.TraceInformation("Power AC {0}, Batt {1}, Batt Level {2} on LM {3}:{4}", p.ACPresent, p.batteryPresent, p.batterylevelPct, Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId); } else if (response == LMComm.LMMMLingo.Tokens.lld) // LLD status { int lld = 0; LMMMComm.SplitLLDReadResponse(received, ref lld); gControl.netlog.TraceInformation("LLD {0} on LM {1}:{2}", lld, Instruments.Active.IndexOf(activeInstr), activeInstr.id.DetectorId); } else // RR: this could be binary data if you cancel an assay and linux is sending a buffer. // RR: this is a large amount of data and we don't want it displayed. // tbd RR: figure out how to turn this back on when data is finished dumping. { if (verbose) { PacketLogSLOW(activeInstr, e); } } } if (verbose) { gControl.netlog.Flush(); } } }
public static bool SocketBased(this LMInstrument lm) { return(lm.id.SRType.IsSocketBasedLM()); }