609 lines
20 KiB
Java
609 lines
20 KiB
Java
/*
|
|
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
|
*/
|
|
package ch.psi.mxsc;
|
|
|
|
import ch.psi.mxsc.Puck.PuckType;
|
|
import ch.psi.pshell.core.Context;
|
|
import ch.psi.pshell.core.DevicePool;
|
|
import ch.psi.pshell.core.DevicePoolListener;
|
|
import ch.psi.pshell.core.JsonSerializer;
|
|
import ch.psi.pshell.device.Device;
|
|
import ch.psi.pshell.device.DeviceAdapter;
|
|
import ch.psi.pshell.device.DeviceListener;
|
|
import ch.psi.pshell.device.GenericDevice;
|
|
import ch.psi.pshell.device.ReadbackDevice;
|
|
import ch.psi.pshell.ui.Panel;
|
|
import ch.psi.utils.State;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.script.ScriptException;
|
|
import javax.swing.JComponent;
|
|
import javax.swing.table.DefaultTableModel;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public class Controller {
|
|
|
|
static Controller instance;
|
|
final BasePlate basePlate;
|
|
final /*Panel*/ MainPanel mainFrame;
|
|
Device hexiposi;
|
|
Device barcode_reader;
|
|
Device puck_detection;
|
|
|
|
|
|
public static Controller getInstance() {
|
|
return instance;
|
|
}
|
|
|
|
static void createInstance(Panel mainFrame) {
|
|
instance = new Controller(mainFrame);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
final PuckSensorAccess puckSensorAccess = PuckSensorAccess.RaspberryPi;
|
|
|
|
static String PUCK_ESERA_DEVICE = "onewire";
|
|
|
|
public static final int NUMBER_OF_PUCKS = 30;
|
|
|
|
private Controller(Panel mainFrame) {
|
|
basePlate = new BasePlate();
|
|
puckState = new PuckState[NUMBER_OF_PUCKS];
|
|
for (int i = 0; i < NUMBER_OF_PUCKS; i++) {
|
|
puckState[i] = new PuckState(i + 1);
|
|
}
|
|
this.mainFrame = (MainPanel) mainFrame;
|
|
instance = this;
|
|
clearPuckStates();
|
|
|
|
basePlate.addListener(basePlateListener);
|
|
}
|
|
|
|
final DeviceListener basePlateListener = new DeviceAdapter() {
|
|
@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);
|
|
}
|
|
|
|
//public Panel getMainFrame() {
|
|
public MainPanel getMainFrame() {
|
|
return mainFrame;
|
|
}
|
|
|
|
public void updateView() {
|
|
getMainFrame().refresh();
|
|
}
|
|
|
|
void onInitialize(int runCount) {
|
|
getMainFrame().addDevice(basePlate);
|
|
basePlate.addListener(basePlateListener);
|
|
System.out.println(basePlate.getState());
|
|
|
|
|
|
if (puckSensorAccess == PuckSensorAccess.Esera) {
|
|
getMainFrame().getContext().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();
|
|
}
|
|
}
|
|
|
|
void onTimer(){
|
|
try {
|
|
setPuckLoading(Controller.getInstance().isPuckLoading());
|
|
} catch (Exception ex) {
|
|
setPuckLoading(false);
|
|
}
|
|
refreshSamplesTable();
|
|
}
|
|
|
|
final DeviceListener hexiposiListener = new DeviceAdapter() {
|
|
@Override
|
|
public void onValueChanged(Device device, Object value, Object former) {
|
|
updateView();
|
|
}
|
|
};
|
|
|
|
final DeviceListener barcodeReaderListener = new DeviceAdapter() {
|
|
@Override
|
|
public void onValueChanged(Device device, Object value, Object former) {
|
|
if (value!=null){ //Keep last value
|
|
String valStr = value.toString().trim();
|
|
if (puckLoading && isBarcodeReaderScanPucks()){
|
|
onPuckBarcode(valStr);
|
|
} else {
|
|
getMainFrame().setSampleDatamatrix(valStr);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
final DeviceListener puckDetectionListener = new DeviceAdapter() {
|
|
@Override
|
|
public void onValueChanged(Device device, Object value, Object former) {
|
|
if (value!=null){ //Keep last value
|
|
onPuckDetectionChanged();
|
|
}
|
|
}
|
|
};
|
|
|
|
void updateDevices(){
|
|
if (hexiposi!=null){
|
|
hexiposi.removeListener(hexiposiListener);
|
|
}
|
|
if (barcode_reader!=null){
|
|
hexiposi.removeListener(barcodeReaderListener);
|
|
}
|
|
if (puck_detection!=null){
|
|
hexiposi.removeListener(puckDetectionListener);
|
|
}
|
|
hexiposi = (Device) getMainFrame().getDevice("hexiposi");
|
|
if (hexiposi != null) {
|
|
hexiposi.addListener(hexiposiListener);
|
|
} else {
|
|
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, "No hexiposi detected.");
|
|
}
|
|
mainFrame.hexiposiPanel.setDevice(hexiposi);
|
|
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.");
|
|
}
|
|
puck_detection = (Device) getDevice("puck_detection");
|
|
if (puck_detection!=null){
|
|
puck_detection.addListener(puckDetectionListener);
|
|
} else {
|
|
Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, "No puck_detection detected.");
|
|
}
|
|
}
|
|
|
|
final PuckState[] puckState;
|
|
|
|
public PuckState[] getPuckStates() {
|
|
return puckState;
|
|
}
|
|
|
|
public Puck getPuck(String name) {
|
|
return basePlate.getPuckByName(name);
|
|
}
|
|
|
|
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 String getHexiposiPosition() {
|
|
try {
|
|
return (String) ((ReadbackDevice) hexiposi).getReadback().take();
|
|
} catch (Exception ex) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public boolean isSelectedPuck(Puck puck){
|
|
return ("" + puck.getSegment()).equalsIgnoreCase(getHexiposiPosition());
|
|
}
|
|
|
|
public List<Puck> getSelectedPucks(){
|
|
List<Puck> ret = new ArrayList<>();
|
|
for (int i=0; i< NUMBER_OF_PUCKS; i++){
|
|
if (isSelectedPuck(basePlate.getPucks()[i])){
|
|
ret.add(basePlate.getPucks()[i]);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
public Boolean isLedRoomTemp() {
|
|
try {
|
|
return getMainFrame().eval("is_led_room_temp()", true).equals(true);
|
|
} catch (Exception ex) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public Boolean isRoomTemp() {
|
|
try {
|
|
return getMainFrame().eval("is_room_temp()", true).equals(true);
|
|
} catch (Exception ex) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
public Boolean isBarcodeReaderScanPucks() {
|
|
try {
|
|
return getMainFrame().eval("is_barcode_reader_scan_pucks()", true).equals(true);
|
|
} catch (Exception ex) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public Boolean isPuckLoading() {
|
|
try {
|
|
return getMainFrame().eval("is_puck_loading()", true).equals(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 void imageDetectPucks() throws Context.ContextStateException {
|
|
imageDetectPucks(null, null, null);
|
|
}
|
|
|
|
public void imageDetectPucks(JComponent plot, JComponent renderer, JComponent text) throws Context.ContextStateException {
|
|
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<String, List<String>> map = (Map<String, List<String>>) ret;
|
|
setImageDetection(map);
|
|
} else {
|
|
getMainFrame().showException((Exception) ex);
|
|
}
|
|
return ret;
|
|
});
|
|
updateView();
|
|
}
|
|
|
|
public void clearImageDetection() throws Context.ContextStateException, ScriptException, IOException, InterruptedException {
|
|
Map<String, List<String>> map = (Map<String, List<String>>) getMainFrame().eval("clear_detection(None)");
|
|
setImageDetection(map);
|
|
}
|
|
|
|
void setImageDetection(Map<String, List<String>> 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();
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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.getPuck());
|
|
}
|
|
|
|
void onSampleReleased(Sample sample){
|
|
onPuckReleased(sample.getPuck());
|
|
}
|
|
|
|
void onPlatePressed(BasePlate plate){
|
|
if (plate.getSelectedPuck() == null){
|
|
getMainFrame().setDefaultDetail();
|
|
puckPanel = null;
|
|
}
|
|
}
|
|
|
|
void onPlateReleased(BasePlate palte){
|
|
}
|
|
|
|
GenericDevice getDevice(String name){
|
|
return getMainFrame().getDevice(name);
|
|
}
|
|
|
|
DevicePool getDevicePool(){
|
|
return getMainFrame().getContext().getDevicePool();
|
|
}
|
|
|
|
Context getContext(){
|
|
return getMainFrame().getContext();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
////////////////////// Sample Info /////////////////////////////////
|
|
|
|
String samplesTableJson;
|
|
final Object samplesTableLock = new Object();
|
|
void refreshSamplesTable() {
|
|
synchronized(samplesTableLock){
|
|
try {
|
|
String json = (String) Context.getInstance().evalLineBackground("get_samples_info()");
|
|
if (!json.equals(samplesTableJson)) {
|
|
samplesTableJson = json;
|
|
|
|
//SamplesInfo sampleInfo = (SamplesInfo) JsonSerializer.decode(json, SampleInfo.class);
|
|
SampleInfo[] samples = (SampleInfo[]) JsonSerializer.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[][]{});
|
|
}
|
|
|
|
|
|
////////////////////// Puck Loading /////////////////////////////////
|
|
Boolean puckLoading;
|
|
Puck.Detection[] currentDetection;
|
|
void setPuckLoading(Boolean value){
|
|
if (value==null){
|
|
value = false;
|
|
}
|
|
if (value != puckLoading){
|
|
puckLoading = value;
|
|
getMainFrame().setPuckDatamatrix(null);
|
|
if (isBarcodeReaderScanPucks()){
|
|
if (puckLoading){
|
|
execute("barcode_reader.enable()", true);
|
|
execute("barcode_reader.polling = 100", true);
|
|
currentDetection = basePlate.getDetection();
|
|
} else if (getState().isInitialized()){
|
|
execute("barcode_reader.polling = 0", true);
|
|
execute("barcode_reader.disable()", true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void onPuckBarcode(String datamatrix){
|
|
if (puckLoading){
|
|
getMainFrame().setPuckDatamatrix(datamatrix);
|
|
System.out.println(datamatrix);
|
|
}
|
|
}
|
|
|
|
void onPuckDetectionChanged(){
|
|
if (puckLoading){
|
|
String datamatrix = getMainFrame().getPuckDatamatrix();
|
|
Puck.Detection[] detection = basePlate.getDetection();
|
|
for (int i=0; i< Controller.NUMBER_OF_PUCKS; i++){
|
|
Puck puck = basePlate.getPucks()[i];
|
|
if (isSelectedPuck(puck)){
|
|
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){
|
|
System.out.println("Detected puck at position: " + puck.getName() + " - Datamatrix: " + (datamatrix.isEmpty() ? null : datamatrix));
|
|
if (!datamatrix.isEmpty()){
|
|
getMainFrame().setPuckDatamatrix(null);
|
|
setPuckDatamatrix(puck, datamatrix);
|
|
}
|
|
} else if (detectedPuckRemoved){
|
|
System.out.println("Removed puck from position " + puck.getName() + " - Datamatrix: " + puck.getId());
|
|
setPuckDatamatrix(puck, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
currentDetection = detection;
|
|
}
|
|
}
|
|
|
|
void setPuckDatamatrix(Puck puck, String datamatrix){
|
|
if ( ((puck.getId()==null) && (datamatrix!=null)) ||
|
|
(puck.getId()!=null) && (!puck.getId().equals(datamatrix))){
|
|
System.out.println("Setting to: " + puck.getName() + " datamatrix: " + datamatrix);
|
|
|
|
puck.setId(datamatrix);
|
|
getMainFrame().refresh();
|
|
}
|
|
}
|
|
|
|
}
|