gda.device.detector.countertimer.BufferedScaler.java Source code

Java tutorial

Introduction

Here is the source code for gda.device.detector.countertimer.BufferedScaler.java

Source

/*-
 * Copyright  2009 Diamond Light Source Ltd.
 *
 * This file is part of GDA.
 *
 * GDA is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License version 3 as published by the Free
 * Software Foundation.
 *
 * GDA is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along
 * with GDA. If not, see <http://www.gnu.org/licenses/>.
 */

package gda.device.detector.countertimer;

import gda.device.ContinuousParameters;
import gda.device.DeviceException;
import gda.device.detector.BufferedDetector;
import gda.device.detector.DAServer;

import java.util.HashMap;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Adapter for the TfgScalerWithLogValues class so that it may be used in ContinuousScans.
 * <p>
 * Assumes that the TTL signal driving the TFG time-frames is connected to TFG socket TTL INPUT 0.
 */
public class BufferedScaler extends TfgScalerWithLogValues implements BufferedDetector {
    private static final Logger logger = LoggerFactory.getLogger(BufferedScaler.class);
    private ContinuousParameters parameters;
    private boolean continuousMode;
    private double overrunTime = 0.1;
    private DAServer daserver;
    private int ttlSocket = 0; // the TTL Trig In socket [0-3] default is 0
    private Boolean returnCountRates = false;
    private double[][] framesRead;

    public BufferedScaler() {
        try {
            framesRead = new double[getNumberFrames()][5];
        } catch (DeviceException e) {
            logger.error("Cannot construct BufferedScaler, something wrong with TFG", e);
        }
    }

    public double[][] getFramesRead() {
        return framesRead;
    }

    public void clearFramesRead() {
        framesRead = null;
    }

    @Override
    public void collectData() throws DeviceException {
        // do nothing when in continuous mode
        if (continuousMode) {
            return;
        }
        super.collectData();
    }

    @Override
    public Object[] readAllFrames() throws DeviceException {
        Integer lastFrame = getNumberFrames() - 1;
        return readoutCorrectedFrames(0, lastFrame);
    }

    @Override
    public Object[] readFrames(int startFrame, int finalFrame) throws DeviceException {
        double[][] frame = readoutCorrectedFrames(startFrame, finalFrame);
        framesRead = frame;
        return frame;
    }

    @Override
    public double[] readout() throws DeviceException {
        if (continuousMode) {
            Integer numFrames = getNumberFrames();
            // if nothing collected, so 0 frames, then view the contents of the first frame anyway
            if (numFrames == 0) {
                return readoutCorrectedFrames(0, 0)[0];
            }
            return readoutCorrectedFrames(numFrames - 1, numFrames - 1)[0];
        }
        return readoutCorrectedFrames(0, 0)[0];
    }

    private double[][] readoutCorrectedFrames(int startFrame, int finalFrame) throws DeviceException {
        // make sure performCorrections from TfgScalerWithLogValues is called on every frame
        double[][] frames = readoutFrames(startFrame, finalFrame);
        for (int frame = 0; frame < frames.length; frame++) {
            frames[frame] = performCorrections(frames[frame]);
        }
        return frames;
    }

    @Override
    public void setContinuousMode(boolean on) throws DeviceException {
        this.continuousMode = on;
        if (on) {
            setTimeFrames();
        } else {
            switchOffExtTrigger();
        }
    }

    private void setTimeFrames() throws DeviceException {
        if (parameters == null) {
            throw new DeviceException(
                    getName() + " could not set time frames for continuous scans as parameters not supplied!");
        }

        // tfg setup-trig
        switchOnExtTrigger();

        //Send as a single command. Otherwise DAServer reply timeouts are seen and the 3 commands take about 10s!
        StringBuffer buffer = new StringBuffer();
        buffer.append("tfg setup-groups ext-start cycles 1" + "\n");
        buffer.append(parameters.getNumberDataPoints() + " 0.000001 0.00000001 0 0 0 " + (ttlSocket + 8) + "\n");
        buffer.append("-1 0 0 0 0 0 0");
        // FIXME RJW on qexafs that fail, especially where # points < previous scan, why are # frames incorrect?
        logger.debug("Setting da.server to arm itself for " + parameters.getNumberDataPoints() + " time frames");
        daserver.sendCommand(buffer.toString());
        daserver.sendCommand("tfg arm");
    }

    @Override
    public boolean isContinuousMode() {
        return continuousMode;
    }

    @Override
    public ContinuousParameters getContinuousParameters() {
        return parameters;
    }

    @Override
    public void setContinuousParameters(ContinuousParameters parameters) {
        this.parameters = parameters;
    }

    @Override
    public void clearMemory() throws DeviceException {
        scaler.clear();
        scaler.start();
    }

    /**
     * switch off external triggering by the TTL0 input
     * @throws DeviceException 
     */
    private void switchOffExtTrigger() throws DeviceException {
        daserver.sendCommand("tfg setup-trig start");
    }

    /**
     * switch on external triggering by the TTL0 input
     * @throws DeviceException 
     */
    private void switchOnExtTrigger() throws DeviceException {
        daserver.sendCommand("tfg setup-trig start ttl" + ttlSocket);
    }

    @Override
    public int getNumberFrames() throws DeviceException {
        if (!continuousMode)
            return 0;
        String[] cmds = new String[] { "status show-armed", "progress", "status", "full", "lap", "frame" };
        HashMap<String, String> currentVals = new HashMap<String, String>();
        for (String cmd : cmds) {
            currentVals.put(cmd, daserver.sendCommand("tfg read " + cmd).toString());
            //         logger.info("tfg read "+ cmd + ": " + currentVals.get(cmd));
        }
        if (currentVals.isEmpty())
            return 0;

        // else either scan not started (return -1) or has finished (return continuousParameters.getNumberDataPoints())

        // if started but nothing collected yet
        if (currentVals.get("status show-armed")
                .equals("EXT-ARMED") /*&& currentVals.get("status").equals("IDLE")*/ ) {
            return 0;
        }

        // if frame is non-0 then work out the current frame
        if (!currentVals.get("frame").equals("0")) {
            String numFrames = currentVals.get("frame");
            try {
                return extractCurrentFrame(Integer.parseInt(numFrames));
            } catch (NumberFormatException e) {
                throw new DeviceException(numFrames);
            }
        }

        return parameters.getNumberDataPoints();
    }

    private int extractCurrentFrame(int frameValue) {
        if (isEven(frameValue)) {
            Integer numFrames = frameValue / 2;
            return numFrames;
        }
        Integer numFrames = (frameValue - 1) / 2;
        return numFrames;
    }

    private boolean isEven(int x) {
        return (x % 2) == 0;
    }

    public void setOverrunTime(double overrunTime) {
        this.overrunTime = overrunTime;
    }

    /**
     * The excess time to collect data for above the movement time. This ensures all motor encoder data has been read.
     * <p>
     * Default is 0.1;
     * 
     * @return double time in seconds
     */
    public double getOverrunTime() {
        return overrunTime;
    }

    public DAServer getDaserver() {
        return daserver;
    }

    public void setDaserver(DAServer daserver) {
        this.daserver = daserver;
    }

    public void setReturnCountRates(Boolean returnCountRates) {
        if (!timeChannelRequired && returnCountRates) {
            timeChannelRequired = true;
            extraNames = (String[]) ArrayUtils.addAll(new String[] { "time" }, this.extraNames);
            outputFormat = (String[]) ArrayUtils.addAll(new String[] { this.outputFormat[0] }, this.outputFormat);
        } else if (timeChannelRequired && this.returnCountRates && !returnCountRates) {
            timeChannelRequired = false;
            extraNames = (String[]) ArrayUtils.remove(this.extraNames, 0);
            outputFormat = (String[]) ArrayUtils.remove(this.outputFormat, 0);
        }
        this.returnCountRates = returnCountRates;
    }

    public Boolean getReturnCountRates() {
        return returnCountRates;
    }

    @Override
    public int maximumReadFrames() throws DeviceException {
        // as this is only a few integers per frame, its unlikely to ever cause memory issues.
        return 99999;
    }

    public int getTtlSocket() {
        return ttlSocket;
    }

    public void setTtlSocket(int ttlSocket) {
        this.ttlSocket = ttlSocket;
    }

}