/** * Add given sample to buffer, performing a back-in-time check, updating the sample buffer error * state. * * @param value Value to archive * @return <code>false</code> if value failed back-in-time or future check, <code>true</code> if * value was added. */ protected final boolean addValueToBuffer(final VType value) { // Suppress samples that are too far in the future final Timestamp time = VTypeHelper.getTimestamp(value); if (isFuturistic(time)) { trouble_sample_log.log("'" + getName() + "': Futuristic " + value); return false; } synchronized (this) { if (last_archived_value != null && VTypeHelper.getTimestamp(last_archived_value).compareTo(time) >= 0) { // Cannot use this sample because of back-in-time problem. // Usually this is NOT an error: // We logged an initial sample, disconnected, disabled, ..., // and now we got an update from the IOC which still // carries the old, original time stamp of the PV, // and that's back in time... trouble_sample_log.log( getName() + " skips back-in-time:\n" + "last: " + VTypeHelper.toString(last_archived_value) + "\n" + "new : " + VTypeHelper.toString(value)); return false; } // else ... last_archived_value = value; } buffer.add(value); if (SampleBuffer.isInErrorState()) need_write_error_sample = true; return true; }
/** * Add given info value to buffer, tweaking its time stamp if necessary * * @param value Value to archive * @return Value that was actually added, which may have adjusted time stamp */ protected final VType addInfoToBuffer(VType value) { synchronized (this) { if (last_archived_value != null) { final Timestamp last = VTypeHelper.getTimestamp(last_archived_value); if (last.compareTo(VTypeHelper.getTimestamp(value)) >= 0) { // Patch the time stamp final Timestamp next = last.plus(TimeDuration.ofMillis(100)); value = VTypeHelper.transformTimestamp(value, next); } // else: value is OK as is } } addValueToBuffer(value); return value; }
/** {@inheritDoc} */ @Override public VType next() throws Exception { if (index < 0) throw new Exception("End of samples"); // $NON-NLS-1$ // Remember value, prepare the next value final VType result = value; samples.getLock().lock(); try { ++index; if (index >= samples.size()) index = -1; // No more samples else { value = samples.get(index).getVType(); if (VTypeHelper.getTimestamp(value).compareTo(end) > 0) index = -1; // Beyond end time } } finally { samples.getLock().unlock(); } return result; }
/** {@inheritDoc} */ @Override protected void performExport(final IProgressMonitor monitor, final PrintStream out) throws Exception { final DateFormat date_format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); int count = 0; for (ModelItem item : model.getItems()) { // Item header if (count > 0) out.println(); printItemInfo(out, item); // Get data monitor.subTask(NLS.bind("Fetching data for {0}", item.getName())); final ValueIterator values = createValueIterator(item); // Dump all values MatlabQualityHelper qualities = new MatlabQualityHelper(); long line_count = 0; out.println("clear t;"); out.println("clear v;"); out.println("clear q;"); while (values.hasNext() && !monitor.isCanceled()) { final VType value = values.next(); ++line_count; // t(1)='2010/03/15 13:30:10.123'; out.println( "t{" + line_count + "}='" + date_format.format(VTypeHelper.getTimestamp(value).toDate()) + "';"); // v(1)=4.125; final double num = VTypeHelper.toDouble(value); if (Double.isNaN(num) || Double.isInfinite(num)) out.println("v(" + line_count + ")=NaN;"); else out.println("v(" + line_count + ")=" + num + ";"); // q(1)=0; out.println( "q(" + line_count + ")=" + qualities.getQualityCode( VTypeHelper.getSeverity(value), VTypeHelper.getMessage(value)) + ";"); if (line_count % PROGRESS_UPDATE_LINES == 0) monitor.subTask(NLS.bind("{0}: Wrote {1} samples", item.getName(), line_count)); } out.println(comment + "Convert time stamps into 'date numbers'"); out.println("tn=datenum(t, 'yyyy/mm/dd HH:MM:SS.FFF');"); out.println(comment + "Prepare patched data because"); out.println(comment + "timeseries() cannot handle duplicate time stamps"); out.println("[xx, idx]=unique(tn, 'last');"); out.println("pt=tn(idx);"); out.println("pv=v(idx);"); out.println("pq=q(idx);"); out.println("clear xx idx"); out.println(comment + "Convert into time series and plot"); // Patch "_" in name because Matlab plot will interprete it as LaTeX sub-script final String channel_name = item.getDisplayName().replace("_", "\\_"); out.println( "channel" + count + "=timeseries(pv', pt', pq', 'IsDatenum', true, 'Name', '" + channel_name + "');"); out.print("channel" + count + ".QualityInfo.Code=["); for (int q = 0; q < qualities.getNumCodes(); ++q) out.print(" " + q); out.println(" ];"); out.print("channel" + count + ".QualityInfo.Description={"); for (int q = 0; q < qualities.getNumCodes(); ++q) out.print(" '" + qualities.getQuality(q) + "'"); out.println(" };"); out.println(); ++count; } out.println(comment + "Example for plotting the data"); for (int i = 0; i < count; ++i) { out.println("subplot(1, " + count + ", " + (i + 1) + ");"); out.println("plot(channel" + i + ");"); } }
/** {@inheritDoc} */ @Override public VType next() throws Exception { final VType result = samples[index]; ++index; if (index < samples.length) return result; // Prepare next batch of samples fetch(VTypeHelper.getTimestamp(result)); if (samples == null) return result; // Inspect next batch of samples // In most cases, this fetch should return the 'result' again: // some_timestamp value A // last_timestamp value B <-- last_sample of previous batch // new_timestamp value C // Since we ask from at-or-before last_timestamp on, // we get the last_sample once more and need to skip it. // // But also consider the following situation, where the last batch ended // in a range of data that had the same time stamp, and even some same // values: // some_timestamp value A // last_timestamp value B // last_timestamp value C // last_timestamp value C // last_timestamp value C <-- last_sample of previous batch // last_timestamp value C // last_timestamp value C // last_timestamp value D // last_timestamp value E // new_timestamp value F // Reasons for same timestamps: Stuck IOC clock, // or sequences like .. Repeat N, next value, Disconnected, Arch. Off. // Reason for the same value: General mess-up. // // When we request new data from 'last_sample.getTime()' on, // i.e. from last_timestamp on, we could get any of the values B to E, // since they're all stamped at-or-before last_timestamp. // Which one exactly depends on optimization inside the data server. // From the end of the new samples, go backward: for (index = samples.length - 1; index >= 0; --index) { // If we find the previous batch's last sample... if (samples[index].equals(result)) // Skip all the samples up to and including it break; } // Nothing to skip? Return as is. if (index < 0) index = 0; // Nothing left? Clear samples. if (index >= samples.length - 1) samples = null; return result; }