Ejemplo n.º 1
0
        /// <summary>
        /// Prepare MCA-527 for a new sweep or cycle
        /// </summary>
        /// <param name="cycle">Cycle sequence number</param>
        /// <param name="secs">Cycle length in seconds</param>
        /// <exception cref="MCADeviceLostConnectionException">An error occurred communicating with the device.</exception>
        bool InitSettings(ushort cycle, uint secs)
        {
            MCAResponse response = null;

            response = m_device.Client.Send(MCACommand.Clear(ClearMode.ClearMeasurementData0));
            if (response == null)
            {
                throw new MCADeviceLostConnectionException();
            }
            response = m_device.Client.Send(MCACommand.Clear(ClearMode.ClearMeasurementData1));
            if (response == null)
            {
                throw new MCADeviceLostConnectionException();
            }
            if (cycle == 1)              // init some values on first cycle
            {
                response = m_device.Client.Send(MCACommand.SetPresets(Presets.Real, secs));
                if (response == null)
                {
                    throw new MCADeviceLostConnectionException();
                }
                response = m_device.Client.Send(MCACommand.SetRepeat(1));
                if (response == null)
                {
                    throw new MCADeviceLostConnectionException();
                }
            }
            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Performs a single cycle assay operation.
        /// </summary>
        /// <param name="measurement">The measurement parameters needed for the op.</param>
        /// <param name="cancellationToken">The cancellation token to observe.</param>
        /// <exception cref="MCADeviceLostConnectionException">An error occurred communicating with the device.</exception>
        /// <exception cref="MCADeviceBadDataException">An error occurred with the raw data stream state.</exception>
        /// <exception cref="Exception">Empty or corrupt runtime data structure.</exception>
        protected void PerformAssay(Measurement measurement, MeasTrackParams mparams, CancellationToken cancellationToken)
        {
            MCA527ProcessingState ps = (MCA527ProcessingState)(RDT.State);

            Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;

            try
            {
                if (ps == null)
                {
                    throw new Exception("Big L bogus state");                      // caught cleanly below
                }
                if (ps.writingFile && (ps.file == null || ps.file.writer == null))
                {
                    m_logger.TraceEvent(LogLevels.Verbose, 9, "null");
                }
                ushort seq = mparams.seq;
                m_logger.TraceEvent(LogLevels.Info, 0, "MCA527[{0}]: Started assay {1}", DeviceName, seq);
                m_logger.Flush();

                cancellationToken.ThrowIfCancellationRequested();

                if (m_setvoltage)
                {
                    SetVoltage(m_voltage, MaxSetVoltageTime, cancellationToken);
                }

                cancellationToken.ThrowIfCancellationRequested();

                if (seq == 1)                  // init var on first cycle
                {
                    ps.device = m_device;
                }

                bool x = InitSettings(seq, (uint)mparams.interval);                  // truncate for discrete integer result

                Stopwatch stopwatch = new Stopwatch();
                TimeSpan  duration  = TimeSpan.FromSeconds((uint)mparams.interval);
                byte[]    buffer    = new byte[1024 * 1024];

                // a5 5a 42 00 01 00 ae d5 44 56 b9 9b
                // flags: 0x0001 => spectrum is cleared and a new start time is set
                // start time: 0x5644d5ae => seconds since Dec 31, 1969, 16:00:00 GMT
                uint        secondsSinceEpoch = (uint)(Math.Abs(Math.Round((DateTime.UtcNow - MCADevice.MCA527EpochTime).TotalSeconds)));
                MCAResponse response          = m_device.Client.Send(MCACommand.Start(StartFlag.SpectrumClearedNewStartTime,
                                                                                      false, false, false, secondsSinceEpoch));
                if (response == null)
                {
                    throw new MCADeviceLostConnectionException();
                }

                const uint CommonMemoryBlockSize = 1440;
                // what's the most that could be left over from a previous attempt to decode? => 3 bytes
                byte[]  rawBuffer        = new byte[CommonMemoryBlockSize + 3];
                ulong[] timestampsBuffer = new ulong[CommonMemoryBlockSize + 1];

                uint commonMemoryReadIndex = 0;
                uint rawBufferOffset       = 0;

                m_logger.TraceEvent(LogLevels.Verbose, 11901, "{0} start time for {1}", DateTime.Now.ToString(), seq);

                ulong    accumulatedTime = 0, totalEvents = 0;
                int      maxindex = 0;
                TimeSpan elapsed  = new TimeSpan(0);
                stopwatch.Start();
                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    QueryState527ExResponse qs527er = (QueryState527ExResponse)m_device.Client.Send(MCACommand.QueryState527Ex());
                    if (qs527er == null)
                    {
                        throw new MCADeviceLostConnectionException();
                    }

                    MCAState state = qs527er.MCAState;

                    // pull off some data while we are waiting...
                    uint commonMemoryFillLevel = qs527er.CommonMemoryFillLevel;
                    uint bytesAvailable        = commonMemoryFillLevel - commonMemoryReadIndex;

                    elapsed = stopwatch.Elapsed;                      // snapshot

                    if (state != MCAState.Run && bytesAvailable == 0) // requested time is complete
                    {
                        break;
                    }
                    if ((elapsed = stopwatch.Elapsed) > duration)                       // elapsed time is complete
                    {
                        break;
                    }
                    if (bytesAvailable >= CommonMemoryBlockSize)                       // a full data block
                    {
                        QueryCommonMemoryResponse qcmr = (QueryCommonMemoryResponse)m_device.Client.Send(MCACommand.QueryCommonMemory(commonMemoryReadIndex / 2));
                        if (qcmr == null)
                        {
                            throw new MCADeviceLostConnectionException();
                        }
                        // bytesToCopy needs to always be even, so that commonMemoryReadIndex always stays even...
                        uint bytesToCopy = Math.Min(bytesAvailable / 2, CommonMemoryBlockSize / 2) * 2;
                        qcmr.CopyData(0, rawBuffer, (int)rawBufferOffset, (int)bytesToCopy);

                        if (ps.writingFile && ps.file != null && ps.file.writer != null)                         // write the block
                        {
                            ps.file.WriteTimestampsRawDataChunk(rawBuffer, 0, (int)bytesToCopy);
                        }

                        rawBufferOffset       += bytesToCopy;
                        commonMemoryReadIndex += bytesToCopy;
                        uint timestampsCount = m_device.TransformRawData(rawBuffer, ref rawBufferOffset, timestampsBuffer);

                        // make sure rawBufferOffset is never greater than 3 after transforming data
                        // => means something has gone wrong
                        if (rawBufferOffset > 3)
                        {
                            throw new MCADeviceBadDataException();
                        }

                        // copy the data out...
                        if (timestampsCount > 0)
                        {
                            if (maxindex < RDT.State.maxValuesInBuffer)                             // accumulate
                            {
                                if (RDT.State.timeArray.Count < maxindex + timestampsCount)
                                {
                                    RDT.State.timeArray.AddRange(new ulong[timestampsCount]);
                                }
                                for (int i = 0; i < timestampsCount; i++)
                                {
                                    accumulatedTime += timestampsBuffer[i];
                                    RDT.State.timeArray[maxindex] = accumulatedTime;
                                    maxindex++;                                      // always 1 more than the last index
                                }
                                RDT.State.NumValuesParsed     += timestampsCount;
                                RDT.State.hitsPerChn[0]       += timestampsCount;
                                RDT.State.NumTotalsEncountered = RDT.State.NumValuesParsed; // only one channel
                            }
                            else                                                            // process
                            {
                                long _max = RDT.State.NumValuesParsed;
                                if (_max < RDT.State.neutronEventArray.Count)                                  // equalize the length of the empty neutron channel event list
                                {
                                    RDT.State.neutronEventArray.RemoveRange((int)_max, RDT.State.neutronEventArray.Count - (int)_max);
                                }
                                else if (_max > RDT.State.neutronEventArray.Count)
                                {
                                    RDT.State.neutronEventArray.AddRange(new uint[_max - RDT.State.neutronEventArray.Count]);
                                }
                                if (_max < RDT.State.timeArray.Count)
                                {
                                    RDT.State.timeArray.RemoveRange((int)_max, RDT.State.timeArray.Count - (int)_max);
                                }
                                else if (_max > RDT.State.timeArray.Count)
                                {
                                    RDT.State.timeArray.AddRange(new ulong[_max - RDT.State.timeArray.Count]);
                                }
                                m_logger.TraceEvent(LogLevels.Verbose, 88, "{0} {1} handling {2} timestampsCount {3} num", elapsed, duration, timestampsCount, RDT.State.NumValuesParsed);
                                RDT.PassBufferToTheCounters((int)_max);
                                maxindex = 0; totalEvents += RDT.State.NumTotalsEncountered;
                                RDT.StartNewBuffer();
                            }
                        }
                    }
                    else if (bytesAvailable > 0 && state != MCAState.Run)
                    {
                        // special case for when there's not a whole block left to read
                        // we can only read up to the address: CommonMemorySize - 1440
                        uint commonMemorySize = qs527er.CommonMemorySize;

                        uint readAddress = commonMemoryReadIndex;
                        uint readOffset  = 0;
                        if (readAddress > commonMemorySize - 1440)
                        {
                            readOffset   = readAddress - (commonMemorySize - 1440);
                            readAddress -= readOffset;
                        }

                        QueryCommonMemoryResponse qcmr = (QueryCommonMemoryResponse)m_device.Client.Send(MCACommand.QueryCommonMemory(readAddress / 2));
                        if (qcmr == null)
                        {
                            throw new MCADeviceLostConnectionException();
                        }
                        uint bytesToCopy = bytesAvailable;
                        qcmr.CopyData((int)readOffset, rawBuffer, (int)rawBufferOffset, (int)bytesToCopy);

                        if (ps.writingFile && ps.file != null && ps.file.writer != null)                         // write the block
                        {
                            ps.file.WriteTimestampsRawDataChunk(rawBuffer, (int)readOffset, (int)bytesToCopy);
                        }

                        rawBufferOffset       += bytesToCopy;
                        commonMemoryReadIndex += bytesToCopy;
                        uint timestampsCount = m_device.TransformRawData(rawBuffer, ref rawBufferOffset, timestampsBuffer);

                        //if (rawBufferOffset > 0) {
                        // apparently this can happen. Perhaps when the device gets cut off (because of a timer event), right in the middle of writing?
                        //throw new MCADeviceBadDataException();
                        // an Engineer from GBS said we are running on a very old firmware version,
                        // perhaps that has something to do with it...
                        //}
                        if (timestampsCount > 0)
                        {
                            // copy the timestampsBuffer value into the RDT.State.timeArray, Q: wait to fill a much large internal buffer before calling the transform?
                            if (maxindex < RDT.State.maxValuesInBuffer)                             // accumulate
                            {
                                if (RDT.State.timeArray.Count < maxindex + timestampsCount)
                                {
                                    RDT.State.timeArray.AddRange(new ulong[timestampsCount]);
                                }
                                for (int i = 0; i < timestampsCount; i++)
                                {
                                    accumulatedTime += timestampsBuffer[i];
                                    RDT.State.timeArray[maxindex] = accumulatedTime;
                                    maxindex++;                                      // always 1 more than the last index
                                }
                                RDT.State.NumValuesParsed     += timestampsCount;
                                RDT.State.hitsPerChn[0]       += timestampsCount;
                                RDT.State.NumTotalsEncountered = RDT.State.NumValuesParsed; // only one channel
                            }
                            else                                                            // process
                            {
                                long _max = RDT.State.NumValuesParsed;
                                if (_max < RDT.State.neutronEventArray.Count)                                  // equalize the length of the empty neutron channel event list
                                {
                                    RDT.State.neutronEventArray.RemoveRange((int)_max, RDT.State.neutronEventArray.Count - (int)_max);
                                }
                                else if (_max > RDT.State.neutronEventArray.Count)
                                {
                                    RDT.State.neutronEventArray.AddRange(new uint[_max - RDT.State.neutronEventArray.Count]);
                                }
                                if (_max < RDT.State.timeArray.Count)
                                {
                                    RDT.State.timeArray.RemoveRange((int)_max, RDT.State.timeArray.Count - (int)_max);
                                }
                                else if (_max > RDT.State.timeArray.Count)
                                {
                                    RDT.State.timeArray.AddRange(new ulong[_max - RDT.State.timeArray.Count]);
                                }
                                m_logger.TraceEvent(LogLevels.Verbose, 89, "{0} {1} handling {2} timestampsCount {3} num", elapsed, duration, timestampsCount, RDT.State.NumValuesParsed);
                                RDT.PassBufferToTheCounters((int)_max);
                                maxindex = 0; totalEvents += RDT.State.NumTotalsEncountered;
                                RDT.StartNewBuffer();
                            }
                        }
                    }
                    else
                    {
                        // give the device a break, not needed now because PassBufferToTheCounters processing takes time
                        //Thread.Sleep(40); // 100? ms
                        //m_logger.TraceEvent(LogLevels.Verbose, 99899, "{0} {1} handling {2} timestampsCount {3} num", elapsed, duration, 0, RDT.State.NumValuesParsed);
                    }
                    elapsed = stopwatch.Elapsed;          // snapshot the time after the processing and before the next query

                    if (maxindex > 0)                     // accumulated data was not completely processed above, so it happens here
                    {
                        long _max = RDT.State.NumValuesParsed;
                        if (_max < RDT.State.neutronEventArray.Count)                          // equalize the length of the empty neutron channel event list
                        {
                            RDT.State.neutronEventArray.RemoveRange((int)_max, RDT.State.neutronEventArray.Count - (int)_max);
                        }
                        else if (_max > RDT.State.neutronEventArray.Count)
                        {
                            RDT.State.neutronEventArray.AddRange(new uint[_max - RDT.State.neutronEventArray.Count]);
                        }
                        if (_max < RDT.State.timeArray.Count)
                        {
                            RDT.State.timeArray.RemoveRange((int)_max, RDT.State.timeArray.Count - (int)_max);
                        }
                        else if (_max > RDT.State.timeArray.Count)
                        {
                            RDT.State.timeArray.AddRange(new ulong[_max - RDT.State.timeArray.Count]);
                        }
                        m_logger.TraceEvent(LogLevels.Verbose, 90, "{0} {1} handling {2} num", elapsed, duration, RDT.State.NumValuesParsed);
                        RDT.PassBufferToTheCounters((int)_max);
                        maxindex = 0; totalEvents += RDT.State.NumTotalsEncountered;
                        RDT.StartNewBuffer();
                    }
                }                  // while time elapsed is less than requested time

                stopwatch.Stop();
                m_logger.TraceEvent(LogLevels.Verbose, 11901, "{0} stop time for {1}", DateTime.Now.ToString(), seq);
                m_logger.TraceEvent(LogLevels.Info, 0, "MCA527[{0}]: Finished assay; read {1} events in {2}s for {3}", DeviceName, totalEvents, stopwatch.Elapsed.TotalSeconds, seq);
                m_logger.Flush();
                RDT.Cycle.HighVoltage = m_device.GetHighVoltage();

                if (ps.writingFile)
                {
                    m_device.CreateWriteHeaderAndClose(ps.file);
                    m_logger.TraceEvent(LogLevels.Verbose, 11921, "WriteHeader for {0}", seq);
                    m_logger.Flush();
                }

                lock (m_monitor)
                {
                    m_cancellationTokenSource.Dispose();
                    m_cancellationTokenSource = null;
                }

                if (totalEvents == 0)                  // nothing to handle if no events, close up and continue
                {
                    DAQControl.HandleEndOfCycleProcessing(this, new StreamStatusBlock(@"MCA527 Done"));
                    m_logger.TraceEvent(LogLevels.Verbose, 11911, "HandleEndOfCycle for {0}", seq);
                    m_logger.Flush();
                }
            }
            catch (OperationCanceledException)
            {
                m_logger.TraceEvent(LogLevels.Warning, 767, "MCA527[{0}]: Stopping assay", DeviceName);
                m_logger.Flush();
                DAQControl.StopActiveAssayImmediately();
                throw;
            }
            catch (Exception ex)
            {
                m_logger.TraceEvent(LogLevels.Error, 0, "MCA527[{0}]: Error during assay: {1}", DeviceName, ex.Message);
                m_logger.TraceException(ex, true);
                m_logger.Flush();
                DAQControl.HandleFatalGeneralError(this, ex);
                throw;
            }
            finally
            {
            }
        }