/* * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved. */ package ch.psi.mxsc; import ch.psi.mxsc.Puck.Detection; import ch.psi.mxsc.Puck.PuckType; import ch.psi.pshell.sequencer.CommandInfo; import ch.psi.pshell.framework.Context; import ch.psi.pshell.devices.DevicePool; import ch.psi.pshell.devices.DevicePoolListener; import ch.psi.pshell.utils.EncoderJson; import ch.psi.pshell.device.Device; import ch.psi.pshell.device.DeviceListener; import ch.psi.pshell.device.GenericDevice; import ch.psi.pshell.app.App; import ch.psi.pshell.framework.Panel; import ch.psi.pshell.framework.Setup; import ch.psi.pshell.utils.Arr; import ch.psi.pshell.utils.Audio; import ch.psi.pshell.utils.Chrono; import ch.psi.pshell.utils.State; import ch.psi.pshell.swing.SwingUtils; import ch.psi.pshell.utils.State.StateException; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Point; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.util.Random; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiFunction; import java.util.logging.Level; import java.util.logging.Logger; import javax.script.ScriptException; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.DefaultTableModel; /** * */ public class Controller { final boolean DIALOG_PUCK_LOAD_SHOW_BASEPLATE = true; final int REMOVE_PUCK_TIMEOUT = 20000; static Controller instance; final BasePlate basePlate; RoomTemperatureBasePlate roomTemperatureBasePlate; static /*Panel*/ MainPanel mainFrame; Device barcode_reader; Device barcode_reader_puck; PuckDetection puck_detection; String currentMountedSample; public static Controller getInstance() { return instance; } public static boolean isRt() { return Controller.mainFrame.isRt(); } static void createInstance(Panel mainFrame) { Controller.mainFrame = (MainPanel) mainFrame; //### System.setProperty(GenericDevice.PROPERTY_CONFIG_PATH, Setup.getDevicesPath()); if (isRt()){ instance = new ControllerRT(mainFrame); } else { instance = new Controller(mainFrame); } } enum PuckMountMode { Direct, Dialog } final PuckMountMode puckMountMode = App.hasAdditionalArgument("direct") ? PuckMountMode.Direct : PuckMountMode.Dialog; enum PuckSensorAccess { RaspberryPi, Esera; } public enum PuckTypes { unipuck, minispine, mixed } PuckTypes puckTypes = PuckTypes.mixed; public PuckTypes getPuckTypes() { return puckTypes; } void updatePuckTypes() { try { puckTypes = PuckTypes.valueOf(getMainFrame().eval("get_puck_types()", true).toString()); } catch (Exception ex) { puckTypes = PuckTypes.mixed; } switch (puckTypes) { case unipuck: setSinglePuckType(PuckType.Unipuck); break; case minispine: setSinglePuckType(PuckType.Minispine); break; case mixed: //setSinglePuckType(PuckType.Unknown); break; } } void setSinglePuckType(Puck.PuckType puckType) { for (Puck p : basePlate.getPucks()) { p.setPuckType(puckType); } } void resetPuckTypes() { for (Puck p : basePlate.getPucks()) { p.setPuckType(Puck.PuckType.Unknown); } } final PuckSensorAccess puckSensorAccess = PuckSensorAccess.RaspberryPi; static String PUCK_ESERA_DEVICE = "onewire"; public static final int NUMBER_OF_PUCKS = BasePlate.numberOfPucks; protected Controller(){ basePlate = new BasePlate(); instance = this; puckState = new PuckState[NUMBER_OF_PUCKS]; for (int i = 0; i < NUMBER_OF_PUCKS; i++) { puckState[i] = new PuckState(i + 1); } } private Controller(Panel mainFrame) { this(); //basePlate = new BasePlate(); clearPuckStates(); basePlate.addListener(basePlateListener); roomTemperatureBasePlate = new RoomTemperatureBasePlate(); } final DeviceListener basePlateListener = new DeviceListener() { @Override public void onValueChanged(Device device, Object value, Object former) { if (value != null) { String segment = ((Object[]) value)[0].toString(); Integer puck = (Integer) ((Object[]) value)[1]; Integer sample = (Integer) ((Object[]) value)[2]; Controller.this.mainFrame.onSelectionChanged(segment, puck, sample); } else { Controller.this.mainFrame.onSelectionChanged(null, null, null); } } }; String getCurrentSelection() { Object value = basePlate.take(); if (value != null) { String segment = ((Object[]) value)[0].toString(); Integer puck = (Integer) ((Object[]) value)[1]; Integer sample = (Integer) ((Object[]) value)[2]; String ret = segment + String.valueOf(puck); if (sample != null) { ret = ret + String.valueOf(sample); } return ret; } return null; } public void selectPuck(Puck puck) { getMainFrame().basePlatePanel.selectPuck(puck); } public void selectSample(Sample sample) { getMainFrame().basePlatePanel.selectSample(sample); if ((puckPanel != null) && puckPanel.isShowing()) { puckPanel.selectSample(sample); } } //public Panel getMainFrame() { public MainPanel getMainFrame() { return mainFrame; } public void updateView() { getMainFrame().refresh(); } void onInitialize(int runCount) { getMainFrame().addDevice(basePlate); basePlate.addListener(basePlateListener); if (puckSensorAccess == PuckSensorAccess.Esera) { Context.getDevicePool().addListener(new DevicePoolListener() { @Override public void onDeviceAdded(GenericDevice dev) { if (dev.getName().equals(PUCK_ESERA_DEVICE)) { detection = new EseraDetection((Device) dev); } } @Override public void onDeviceRemoved(GenericDevice dev) { if (dev.getName().equals(PUCK_ESERA_DEVICE)) { detection.close(); detection = null; } } }); if (detection != null) { detection.close(); detection = null; } if ((Device) getMainFrame().getDevice(PUCK_ESERA_DEVICE) != null) { detection = new EseraDetection((Device) getMainFrame().getDevice(PUCK_ESERA_DEVICE)); } } getDevicePool().addListener(new DevicePoolListener() { @Override public void onDeviceAdded(GenericDevice dev) { updateDevices(); } @Override public void onDeviceRemoved(GenericDevice dev) { } }); updateDevices(); updatePuckTypes(); clearSamplesTable(); refreshSamplesTable(); } public void onStateChange(State state, State former) { if (state == State.Initializing) { getMainFrame().removeDevice(basePlate); } else if (state == State.Ready) { refreshSamplesTable(); try { Sample sample = getMountedSample(); if ((sample == null) && (roomTemperatureBasePlate != null)) { sample = roomTemperatureBasePlate.getSampleByName(currentMountedSample); roomTemperatureBasePlate.resetLoadedSample(); } basePlate.resetLoadedSample(); if (sample != null) { sample.setLoaded(true); } } catch (Exception ex) { currentMountedSample = null; basePlate.resetLoadedSample(); } getMainFrame().refresh(); } logStateChange(state); } void onTimer() { try { //setPuckLoading(null); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } try { refreshSamplesTable(); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } } final DeviceListener barcodeReaderListener = new DeviceListener() { @Override public void onValueChanged(Device device, Object value, Object former) { if (value != null) { //Keep last value String valStr = value.toString().trim(); if (isBarcodeReaderScanPucks()) { onPuckBarcode(valStr); } else { onSampleBarcode(valStr); } } } }; final DeviceListener barcodeReaderPuckListener = new DeviceListener() { @Override public void onValueChanged(Device device, Object value, Object former) { if (value != null) { //Keep last value String valStr = value.toString().trim(); onPuckBarcode(valStr); } } }; final DeviceListener puckDetectionListener = new DeviceListener() { @Override public void onValueChanged(Device device, Object value, Object former) { if (puck_detection.isEnabled()){ if (value != null) { //Keep last value onPuckDetectionChanged(); } } } }; void updateDevices() { barcode_reader = (Device) getDevice("barcode_reader"); if (barcode_reader != null) { barcode_reader.addListener(barcodeReaderListener); } else { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, "No barcode_reader detected."); } barcode_reader_puck = (Device) getDevice("barcode_reader_puck"); if (barcode_reader_puck != null) { barcode_reader_puck.addListener(barcodeReaderPuckListener); } else { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, "No barcode_reader_puck detected."); } puck_detection = (PuckDetection) getDevice("puck_detection"); if (puck_detection != null) { puck_detection.addListener(puckDetectionListener); } else { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, "No puck_detection detected."); } checkPuckDetectionEnabling(); } GenericDevice getDevice(String name) { return getMainFrame().getDevice(name); } DevicePool getDevicePool() { return Context.getDevicePool(); } State getState() { return getMainFrame().getState(); } void execute(String statement) { getMainFrame().execute(statement); } void execute(String statement, boolean background) { getMainFrame().execute(statement, background); } void execute(String statement, boolean background, boolean showReturn) { getMainFrame().execute(statement, background, showReturn); } void execute(String statement, boolean background, boolean showReturn, boolean showException) { getMainFrame().execute(statement, background, showReturn, showException); } ////////////////////// Puck image detection ///////////////////////////////// public void imageDetectPucks() throws StateException { imageDetectPucks(null, null, null); } public void imageDetectPucks(JComponent plot, JComponent renderer, JComponent text) throws StateException { Map args = new HashMap(); args.put("PLOT", plot); args.put("RENDERER", renderer); args.put("TEXT", text); getMainFrame().runAsync("imgproc/LedDetectionProc", args).handle((ret, ex) -> { if (ex == null) { Map> map = (Map>) ret; setImageDetection(map); } else { getMainFrame().showException((Exception) ex); } return ret; }); updateView(); } public void clearImageDetection() throws StateException, ScriptException, IOException, InterruptedException { Map> map = (Map>) getMainFrame().eval("clear_detection(None)"); setImageDetection(map); } void setImageDetection(Map> map) { for (Puck.PuckType puckType : Puck.PuckType.values()) { for (String name : map.get(puckType.toString())) { Puck p = basePlate.getPuckByName(name); if (p != null) { p.setPuckType(puckType); } } } updateView(); } ////////////////////// BasePlatePanel callbacks ///////////////////////////////// BasePlatePanel puckPanel; void onPuckPressed(Puck puck) { //JPanel panel = new SinglePuckPanel(puck); //panel.setOpaque(false); //getMainFrame().setDetail(panel); if ((puckPanel == null) || (puckPanel != getMainFrame().getDetail())) { puckPanel = new BasePlatePanel(); puckPanel.setMode(BasePlatePanel.Mode.puck); puckPanel.setSelectionMode(BasePlatePanel.SelectionMode.Samples); puckPanel.setDevice((Device) getDevice("BasePlate")); puckPanel.setEnabled(true); //TODO: Puck cannot be shared between two panels (device store single coordinates foe comparing to click) getMainFrame().setDetail(puckPanel); } } void onPuckReleased(Puck puck) { if (!puck.isSelected()) { getMainFrame().setDefaultDetail(); puckPanel = null; } } void onSamplePressed(Sample sample) { onPuckPressed((sample==null)? null : sample.getPuck()); } void onSampleReleased(Sample sample) { onPuckReleased(sample.getPuck()); } void onPlatePressed(BasePlate plate) { if (plate.getSelectedPuck() == null) { getMainFrame().setDefaultDetail(); puckPanel = null; } } void onPlateReleased(BasePlate palte) { } ////////////////////// Puck & Sample Info ///////////////////////////////// PuckState[] puckState; public PuckState[] getPuckStates() { return puckState; } public Puck getPuck(String name) { return basePlate.getPuckByName(name); } public Sample getSample(String name) { return basePlate.getSampleByName(name); } public BasePlate getBasePlate() { return basePlate; } EseraDetection detection; //From 1 to PUCKS_NUMBER public PuckState getPuckState(int id) throws Exception { if ((id <= 0) || (id > NUMBER_OF_PUCKS)) { throw new Exception("invalid puck id: " + id); } return getPuckStates()[id - 1]; } public int getPuckIndex(int address) throws Exception { if ((address <= 0) || (address > NUMBER_OF_PUCKS)) { throw new Exception("invalid puck address: " + address); } for (int i = 0; i < Puck.ADDRESSES.length; i++) { if (Puck.ADDRESSES[i] == address) { return i + 1; } } return -1; } public void clearPuckStates() { for (PuckState puck : getPuckStates()) { puck.clear(); } updateView(); } public List getFreePucks() { List ret = new ArrayList<>(); for (Puck p : basePlate.getPucks()) { if (!p.isDisabled() && (p.getDetection() == Detection.Empty )) { ret.add(p); } } return ret; } public Puck getFreePuck(){ List pucks = getFreePucks(); if (pucks.isEmpty()){ return null; } Random random = new Random(); return pucks.get(random.nextInt(pucks.size())); } String samplesTableJson; //final Object samplesTableLock = new Object(); void refreshSamplesTable() { //synchronized(samplesTableLock){ SwingUtilities.invokeLater(() -> { try { if (Context.getSequencer().getState().isInitialized()) { String json = (String) Context.getSequencer().evalLineBackground("get_samples_info()"); if (!json.equals(samplesTableJson)) { samplesTableJson = json; //SamplesInfo sampleInfo = (SamplesInfo) EncoderJson.decode(json, SampleInfo.class); SampleInfo[] samples = (SampleInfo[]) EncoderJson.decode(json, SampleInfo[].class); Object[][] sampleData = new Object[samples.length][]; for (int i = 0; i < samples.length; i++) { sampleData[i] = samples[i].getData(); } getMainFrame().setSamplesTable(sampleData); } } } catch (Exception ex) { clearSamplesTable(); Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } }); //} } void clearSamplesTable() { samplesTableJson = null; getMainFrame().setSamplesTable(new Object[][]{}); } Map getPuckDatamatrix() { try { return (Map) Context.getSequencer().evalLineBackground("get_puck_datamatrix()"); } catch (Exception ex) { return null; } } Map getPuckDatamatrixInfo() { try { return (Map) Context.getSequencer().evalLineBackground("get_puck_datamatrix_info()"); } catch (Exception ex) { return null; } } String getPuckFromDatamatrix(String dm){ try { return (String) Context.getSequencer().evalLineBackground("get_puck_from_datamatrix('" + dm + "')"); } catch (Exception ex) { return null; } } public Sample getMountedSample() throws Exception{ String mountedSample = (String) Context.getSequencer().evalLineBackground("get_setting('mounted_sample_position')"); checkMountedSampleChange(currentMountedSample, mountedSample); currentMountedSample = mountedSample; Sample sample = basePlate.getSampleByName(currentMountedSample); return sample; } public void resetMountedSample() throws Exception{ String mountedSample = (String) Context.getSequencer().evalLineBackground("get_setting('mounted_sample_position')"); checkMountedSampleChange(currentMountedSample, null); Context.getSequencer().evalLineBackground("set_setting('mounted_sample_position', None)"); } void checkMountedSampleChange(String former, String current){ if (((current == null) && (former!=null)) || ((current != null) && (!current.equals(former)))){ logSampleMounted(former, current); } } ////////////////////// Device callbacks ///////////////////////////////// Point fmm; public void onCoverDetection(Point fmm ){ this.fmm = fmm; checkPuckLoading(); } public boolean isCoverDetected() { return fmm!=null; } boolean doorsOpened; public void onDoorsOpenChange(boolean value){ doorsOpened = value; doorsHaveOpened =value; checkPuckLoading(); } public void onSampleBarcode(String datamatrix) { getMainFrame().setSampleDatamatrix(datamatrix); System.out.println("Detected Sample: " + datamatrix); } public void onPuckBarcode(String datamatrix) { if (isPuckLoading()) { playSound("scanned"); System.out.println("Detected Puck: " + datamatrix); onPuckScanned(datamatrix); } removedPuck = null; } Puck.Detection[] currentDetection; void onPuckDetectionChanged() { if (isPuckLoading()) { Puck.Detection[] detection = basePlate.getDetection(); for (int i = 0; i < Controller.NUMBER_OF_PUCKS; i++) { Puck puck = basePlate.getPucks()[i]; boolean detectedPuckInserted = (currentDetection[i] != Puck.Detection.Present) && (detection[i] == Puck.Detection.Present); boolean detectedPuckRemoved = (currentDetection[i] != Puck.Detection.Empty) && (detection[i] == Puck.Detection.Empty); if (detectedPuckInserted) { onPuckMounted(puck); } else if (detectedPuckRemoved) { onPuckUnmounted(puck); } } currentDetection = detection; } } ////////////////////// Puck Loading ///////////////////////////////// PuckLoadingDialog dialogPuckLoading; JDialog dialogAskPuckDatamatrix; boolean puckLoading; boolean puckReaderOk = true; String insertedPuckDatamatrix; Puck removedPuck; boolean doorsHaveOpened; //Enables/disables puck loading mode. Opens dialod if PuckMountMode is Dialog. void setPuckLoading(boolean load) { if (load != puckLoading) { if (load){ if (!canSetPuckLoading()){ Logger.getLogger(Controller.class.getName()).warning("Cannot set puck loading"); return; } insertedPuckDatamatrix = null; removedPuck = null; } else { setLaserPos((Puck)null); } if ((dialogAskPuckDatamatrix != null) && (dialogAskPuckDatamatrix.isShowing())) { dialogAskPuckDatamatrix.setVisible(false); } hideDialogPuckLoading(); puckLoading = load; onPuckScanned(null); Device reader = getPuckBarcodeReader(); if (reader != null) { final String name = reader.getName(); BiFunction errorHandler = (BiFunction) (ret, ex) -> { if (ex != null) { if (puckReaderOk) { Logger.getLogger(Controller.class.getName()).warning("Communication failure: " + name); } puckLoading = false; puckReaderOk = false; } else { if (!puckReaderOk) { Logger.getLogger(Controller.class.getName()).warning("Communication resumed: " + name); } puckReaderOk = true; } return ret; }; try { if (puckLoading) { getMainFrame().evalAsync(name + ".enable(); " + name + ".polling = 100", true).handle(errorHandler); currentDetection = basePlate.getDetection(); } else if (getState().isInitialized()) { getMainFrame().evalAsync(name + ".polling = 0; " + name + ".disable()", true).handle(errorHandler); onPuckScanned(null); } getMainFrame().evalAsync("onPuckLoadingChange(" + (puckLoading ? "True" : "False") + ")"); } catch (Exception ex) { errorHandler.apply(null, ex); } if ( hasLoadDialog()) { if (puckLoading) { showDialogPuckLoading(); if (!DIALOG_PUCK_LOAD_SHOW_BASEPLATE){ mainFrame.setViewDesign(); } } else { hideDialogPuckLoading(); if (!DIALOG_PUCK_LOAD_SHOW_BASEPLATE){ mainFrame.setViewCamera(); } } } } } else { if (puckLoading) { if ((dialogPuckLoading != null) && (dialogPuckLoading.isVisible())) { dialogPuckLoading.restore(); } } } } //Returns if can switch to puck loading mode: no cover, doors open and robot parked. Or else, service mode. public boolean canSetPuckLoading(){ if (!getState().isInitialized()){ return false; } if (isServiceMode()){ return true; } return !isCoverDetected() && isDoorOpen() && isRobotParked(); } //Reset puck loading mode id any condition is false - closing the dialog private void checkPuckLoading(){ try{ if (isServiceMode()){ //Open/close manually in service mode } else { if (!canSetPuckLoading()){ setPuckLoading(false); } else { //Opens automatically once after door is oppen if (doorsHaveOpened){ doorsHaveOpened=false; //setPuckLoading(true); } } } } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } } //Returns if puck loading mode is enabled. public boolean isPuckLoading() { try { if (isPuckDetectionLoading()){ if (!puck_detection.isEnabled()){ //Does not process load events if checking missing pucks before re-enabling detection return false; } } } catch (IOException ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } return puckLoading; } //Returns if puck detection is enabled during puck loading only (puck_detection == "loading") Boolean puckDetectionLoading; public boolean isPuckDetectionLoading() throws IOException{ if (puckDetectionLoading==null){ puckDetectionLoading = "loading".equals(Context.getSetting("puck_detection")); } return puckDetectionLoading; } //Manages puck detection enabling/disabling if isPuckDetectionLoading()==true public void checkPuckDetectionEnabling(){ boolean showingPuckLoadingDialog; try{ showingPuckLoadingDialog = (dialogPuckLoading != null) && (dialogPuckLoading.isShowing()); if ( isPuckDetectionLoading()){ if (showingPuckLoadingDialog){ var werePresent = new ArrayList(); Puck[] pucks = basePlate.getPucks(); for (Puck p : pucks){ if (p.getDetection() == Puck.Detection.Present){ werePresent.add(p.getName()); } } puck_detection.applyCache(); var present = new ArrayList(); for (Puck p : pucks){ if (p.getDetection() == Puck.Detection.Present){ present.add(p.getName()); } } var removed = new ArrayList<>(werePresent); removed.removeAll(present); if (removed.size()>0){ PuckDetectionErrorDialog dlg = new PuckDetectionErrorDialog(dialogPuckLoading, false); dlg.initialize(removed); dlg.setLocationRelativeTo(dialogPuckLoading); dlg.setVisible(true); for (String address: removed){ Puck puck = basePlate.getPuckByName(address); clearPuckMountedSample(puck); Controller.getInstance().linkPuckDatamatrix(puck, null, false); } } } puck_detection.setEnabled(showingPuckLoadingDialog); } } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } } //Shows puck loading dialog void showDialogPuckLoading() { if ((dialogPuckLoading != null) && (dialogPuckLoading.isVisible())) { return; } dialogPuckLoading = new PuckLoadingDialog(mainFrame.getTopLevel(), false, false, DIALOG_PUCK_LOAD_SHOW_BASEPLATE); dialogPuckLoading.setVisible(true); checkPuckDetectionEnabling(); dialogPuckLoading.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { try{ setPuckLoading(false); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } } @Override public void windowClosed(WindowEvent e) { checkPuckDetectionEnabling(); } }); } //Hides puck loading dialog void hideDialogPuckLoading() { if (dialogPuckLoading != null) { dialogPuckLoading.setVisible(false); dialogPuckLoading.dispose(); dialogPuckLoading = null; try { List puckInfo = (List) getMainFrame().eval("get_puck_info()", true); Context.getSequencer().sendEvent("DewarContentUpdate", puckInfo); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } } } //Called when a puck is scanned public void onPuckScanned(String datamatrix) { Logger.getLogger(Controller.class.getName()).info("Scanned puck: " + datamatrix); if (isPuckLoading()) { getMainFrame().setPuckDatamatrix(datamatrix); if ( hasLoadDialog()) { showDialogPuckLoading(); dialogPuckLoading.onPuckScanned(datamatrix); } } else { getMainFrame().setPuckDatamatrix(null); } } //Called when a puck is detected inserted in the dewar public void onPuckMounted(Puck puck) { String datamatrix = getMainFrame().getPuckDatamatrix(); Logger.getLogger(Controller.class.getName()).info("Mounted puck: " + puck.getName() + " - datamatrix:" + datamatrix); playSound("mounted"); logPuckDetectionChange(puck, true); onPuckScanned(null); //If no new puck is scanned and detected mounted in the same place of the last unmount, //considers the detection is flickering (up to a timeout) if ((datamatrix==null) || (datamatrix.isBlank())){ if (puck == removedPuck){ if ((System.currentTimeMillis() - removeTimestamp) < REMOVE_PUCK_TIMEOUT){ datamatrix = insertedPuckDatamatrix; } } else { removedPuck = null; } } if ((datamatrix != null) && (!datamatrix.isEmpty())) { Controller.getInstance().linkPuckDatamatrix(puck, datamatrix, !hasLoadDialog()); } if (hasLoadDialog()) { showDialogPuckLoading(); dialogPuckLoading.onPuckMounted(puck, datamatrix); } else { if ((datamatrix == null) || (datamatrix.isEmpty())){ askPuckDatamatrix(puck); } } insertedPuckDatamatrix = datamatrix; removedPuck = null; } long removeTimestamp; //Called when a puck is detected removed from the the dewar public void onPuckUnmounted(Puck puck) { Logger.getLogger(Controller.class.getName()).info("Unmounted puck: " + puck.getName()); playSound("unmounted"); clearPuckMountedSample(puck); Controller.getInstance().linkPuckDatamatrix(puck, null, !hasLoadDialog()); if ( hasLoadDialog()) { showDialogPuckLoading(); dialogPuckLoading.onPuckUnmounted(puck); } removedPuck = puck; removeTimestamp = System.currentTimeMillis(); } public boolean hasLoadDialog(){ return(puckMountMode == PuckMountMode.Dialog); } //Links a puck to a datamatrix, or removes the link is datamatrix=null. //This is called by puck detectiokn events and also when puck is manually linked to a datamatrix. public void linkPuckDatamatrix(Puck puck, String datamatrix, boolean showMessage) { // if ( ((puck.getId()==null) && (datamatrix!=null)) || // (puck.getId()!=null) && (!puck.getId().equals(datamatrix))){ String puckName = (puck == null) ? "" : puck.getName(); if (datamatrix == null) { datamatrix = ""; } datamatrix = datamatrix.trim(); System.out.println("Setting datamatrix '" + datamatrix + "' to puck: " + puckName); try { Context.getSequencer().evalLineBackground("set_puck_datamatrix('" + puckName + "','" + datamatrix + "')"); if (puck != null) { puck.setId(datamatrix); } else { basePlate.clearId(datamatrix); } if (showMessage && (puck != null) && !datamatrix.isEmpty()) { SwingUtils.showMessage(getMainFrame(), "Puck loading", "Puck '" + datamatrix + "' set to position " + puckName, 5000); } } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } refreshSamplesTable(); getMainFrame().refresh(); // } } //Manual selection of a datamatrix for a detected puck if does not have a loading dialog void askPuckDatamatrix(Puck puck) { if ((dialogAskPuckDatamatrix != null) && (dialogAskPuckDatamatrix.isShowing())) { dialogAskPuckDatamatrix.setVisible(false); } if (puck == null) { return; } Map dms = getPuckDatamatrix(); if ((dms != null) && (dms.size() > 0)) { JTable table = new JTable(); List list = new ArrayList<>(); for (Object dm : dms.keySet()) { Object address = dms.get(dm); list.add(new Object[]{dm, address}); } table.setModel(new DefaultTableModel( list.toArray(new Object[0][]), new String[]{ "Datamatrix", "Address" } ) { public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } }); JLabel label = new JLabel("Select datamatrix for puck at " + puck.getName() + ":"); label.setFont(label.getFont().deriveFont(20.0f)); table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); table.setFont(table.getFont().deriveFont(28.0f)); table.setRowHeight(40); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(table); JPanel panel = new JPanel(); JButton ok = new JButton("OK"); JButton cancel = new JButton("Cancel"); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BorderLayout()); buttonPanel.add(cancel, BorderLayout.WEST); buttonPanel.add(ok, BorderLayout.EAST); panel.setLayout(new BorderLayout()); panel.add(label, BorderLayout.NORTH); panel.add(scrollPane, BorderLayout.CENTER); panel.add(buttonPanel, BorderLayout.SOUTH); ok.setPreferredSize(new Dimension(200, ok.getPreferredSize().height)); cancel.setPreferredSize(new Dimension(200, ok.getPreferredSize().height)); dialogAskPuckDatamatrix = SwingUtils.showDialog(getMainFrame().getTopLevel(), "Puck Loading", new Dimension(400, 600), panel); cancel.addActionListener((ev) -> { dialogAskPuckDatamatrix.setVisible(false); }); ok.addActionListener((ev) -> { int row = table.getSelectedRow(); String dm = (row >= 0) ? String.valueOf(table.getValueAt(row, 0)) : null; dialogAskPuckDatamatrix.setVisible(false); if (dm != null) { linkPuckDatamatrix(puck, dm, true); } }); } } //Clear mounted flag of samples of removed puck. void clearPuckMountedSample(Puck puck){ try{ Sample sample = getMountedSample(); if ((sample!=null) && (sample.getPuck() == puck)){ resetMountedSample(); sample.setLoaded(false); SwingUtilities.invokeLater(()->{; getMainFrame().refresh(); }); } } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } } ////////////////////// Laser Pointer ///////////////////////////////// String laserPos; public void setLaserPos(String pos){ try { laserPos = pos; getMainFrame().evalAsync("set_laser_pos(" + ((pos==null) ? "" : ("'" + pos + "'") ) + ")" ,true); getMainFrame().basePlatePanel.pointPuck((pos==null) ? null : basePlate.getPuckByName(pos)); if ((dialogPuckLoading != null) && (dialogPuckLoading.isVisible()) && dialogPuckLoading.getBasePlatePanel()!=null) { dialogPuckLoading.getBasePlatePanel().pointPuck((pos==null) ? null : basePlate.getPuckByName(pos)); } } catch (StateException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } } public void setLaserPos(Puck puck){ if (puck==null){ setLaserPos((String)null); } else { setLaserPos(puck.getName()); } } public String getLaserPos(){ return laserPos; } ////////////////////// Utilities ///////////////////////////////// void playSound(String name) { try { Audio.playFile(new File(Setup.expandPath("{home}/sounds/" + name + ".wav")), false); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.FINE, null, ex); } } public Boolean isLedRoomTemp() { try { if (getMainFrame().getState().isInitialized()){ return getMainFrame().eval("is_led_room_temp()", true).equals(true); } } catch (Exception ex) { } return null; } public Boolean isRoomTemp() { try { if (getMainFrame().getState().isInitialized()){ return getMainFrame().eval("is_room_temp()", true).equals(true); } } catch (Exception ex) { } return null; } public Boolean isServiceMode() { try { if (getMainFrame().getState().isInitialized()){ return getMainFrame().eval("is_service_mode()", true).equals(true); } } catch (Exception ex) { } return null; } //Non-blocking public boolean isDoorOpen() { try { return doorsOpened; //if (getMainFrame().getState().isInitialized()){ // return getMainFrame().eval("is_door_closed()", true).equals(false); // } } catch (Exception ex) { } return false; } //Non-blocking public boolean isRobotParked() { try { if (getMainFrame().getState().isInitialized()){ return getMainFrame().eval("'pPark' in robot.get_current_points_cached()", true).equals(true); } } catch (Exception ex) { } return false; } public void setServiceMode(boolean value){ try{ String state = value ? "True" : "False"; getMainFrame().eval("set_service_mode(" + state + ")", true); } catch (Exception ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } checkPuckLoading(); } public Boolean isBarcodeReaderScanPucks() { try { return getMainFrame().eval("is_barcode_reader_scan_pucks()", true).equals(true); } catch (Exception ex) { return false; } } public Device getPuckBarcodeReader() { try { return (Device) getMainFrame().eval("get_puck_barcode_reader()", true); } catch (Exception ex) { return null; } } public String getWorkingMode() { try { return String.valueOf(getMainFrame().eval("robot.working_mode", true)); } catch (Exception ex) { return "Unknown"; } } public boolean isManualMode() { try { return getMainFrame().eval("is_manual_mode()", true).equals(true); } catch (Exception ex) { return false; } } public Boolean isRoomTempEnabled() { try { return getMainFrame().eval("is_room_temperature_enabled()", true).equals(true); } catch (Exception ex) { return null; } } public Boolean isBeamlineStatusEnabled() { try { return getMainFrame().eval("is_beamline_status_enabled()", true).equals(true); } catch (Exception ex) { return null; } } public Boolean isImagingEnabled() { try { return getMainFrame().eval("is_imaging_enabled()", true).equals(true); } catch (Exception ex) { return null; } } ////////////////////// Logs ///////////////////////////////// void logSampleMounted(String former, String current){ logEvent((current!=null) ? "Sample Mounted" : "Sample Unmounted", former, current); } void logPuckDetectionChange(Puck puck, boolean mounted){ logEvent(mounted ? "Puck Mounted" : "Puck Unmounted", puck.getName(), isPuckLoading() ? "Puck Loading" : ""); } void logStateChange(State state){ String command = ""; if (state==State.Busy){ CommandInfo info = Context.getCommandBus().getCurrentCommand(true); if (info != null){ command = (info.script != null) ? info.script : info.command; } } logEvent("State Change", state.toString(), command); } public void logEvent(String... event){ try{ long now = System.currentTimeMillis(); Path path = Paths.get(Setup.getOutputPath(), "events", Chrono.getTimeStr(now,"YYYYMMdd") + ".txt"); path.toFile().getParentFile().mkdirs(); String[] data = new String[]{ Chrono.getTimeStr(now, "dd/MM/YY HH:mm:ss.SSS"), }; data = Arr.append(data, event); Files.write(path, String.join("\t", data).getBytes(), path.toFile().exists() ? StandardOpenOption.APPEND : StandardOpenOption.CREATE); Files.write(path, System.lineSeparator().getBytes(), StandardOpenOption.APPEND); } catch(Exception ex){ Logger.getLogger(Controller.class.getName()).log(Level.WARNING, null, ex); } } }