From 4c38bcba7c25811ca5f40bd327bdf817a48fab48 Mon Sep 17 00:00:00 2001 From: gac-S_Changer Date: Fri, 6 Jul 2018 09:56:19 +0200 Subject: [PATCH] --- config/devices.properties | 2 +- config/plugins.properties | 9 +- devices/led_ctrl_1.properties | 4 +- devices/led_ctrl_2.properties | 4 +- devices/led_ctrl_3.properties | 4 +- plugins/BarcodeReaderPanel.form | 118 ++++++++++ plugins/BarcodeReaderPanel.java | 162 ++++++++++++++ plugins/Expert.form | 342 +++-------------------------- plugins/Expert.java | 377 +++++--------------------------- plugins/HexiposiPanel.form | 81 +++++++ plugins/HexiposiPanel.java | 109 +++++++++ plugins/LN2.java | 27 ++- plugins/LaserUEPanel.form | 59 +++++ plugins/LaserUEPanel.java | 98 +++++++++ plugins/MXSC-1.10.0.jar | Bin 182951 -> 200678 bytes plugins/MjpegSource2.java | 6 +- plugins/PuckDetection.java | 169 -------------- plugins/PuckDetectionPanel.form | 184 ++++++++++++++++ plugins/PuckDetectionPanel.java | 250 +++++++++++++++++++++ plugins/RobotPanel.form | 101 +++++++++ plugins/RobotPanel.java | 106 ++++++++- plugins/WagoPanel.form | 167 ++++++++++++++ plugins/WagoPanel.java | 207 ++++++++++++++++++ plugins/Wayne.form | 46 ---- plugins/Wayne.java | 82 ------- script/devices/RobotTCP.py | 42 +++- script/local.py | 11 + script/motion/get_dewar.py | 2 + script/motion/mount.py | 2 + script/motion/put_dewar.py | 2 + script/motion/recover.py | 5 + script/motion/robot_recover.py | 2 - script/motion/unmount.py | 2 + script/test/TestBugPcAPI2.py | 6 +- 34 files changed, 1820 insertions(+), 968 deletions(-) create mode 100644 plugins/BarcodeReaderPanel.form create mode 100644 plugins/BarcodeReaderPanel.java create mode 100644 plugins/HexiposiPanel.form create mode 100644 plugins/HexiposiPanel.java create mode 100644 plugins/LaserUEPanel.form create mode 100644 plugins/LaserUEPanel.java delete mode 100644 plugins/PuckDetection.java create mode 100644 plugins/PuckDetectionPanel.form create mode 100644 plugins/PuckDetectionPanel.java create mode 100644 plugins/WagoPanel.form create mode 100644 plugins/WagoPanel.java delete mode 100644 plugins/Wayne.form delete mode 100644 plugins/Wayne.java create mode 100644 script/motion/recover.py diff --git a/config/devices.properties b/config/devices.properties index 41fc563..2ab3f36 100644 --- a/config/devices.properties +++ b/config/devices.properties @@ -1,5 +1,5 @@ img=ch.psi.pshell.prosilica.Prosilica|25001 "PacketSize=1522;PixelFormat=Mono8;BinningX=1;BinningY=1;RegionX=300;RegionY=200;Width=1000;Height=1000;MulticastEnable=Off"|||false -#gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://129.129.110.114/axis-cgi/mjpg/video.cgi||100| +gripper_cam=ch.psi.pshell.imaging.MjpegSource|http://129.129.110.114/axis-cgi/mjpg/video.cgi||-1| microscan=ch.psi.pshell.serial.TcpDevice|129.129.110.200:2001||| microscan_cmd=ch.psi.pshell.serial.TcpDevice|129.129.110.200:2003||| ue=LaserUE|COM4|||false diff --git a/config/plugins.properties b/config/plugins.properties index 00b35d6..5d37a10 100644 --- a/config/plugins.properties +++ b/config/plugins.properties @@ -1,15 +1,18 @@ +WagoPanel.java=enabled +LaserUEPanel.java=enabled +BarcodeReaderPanel.java=enabled +PuckDetectionPanel.java=enabled +HexiposiPanel.java=enabled MjpegSource2.java=enabled MXSC-1.10.0.jar=enabled LN2.java=enabled -Hexiposi.java=enabled +Hexiposi.java=disabled NewJPanel.java=disabled Expert.java=disabled RobotPanel.java=enabled -Wayne.java=disabled SmartMagnetConfig.java=disabled SmartMagnetPanel.java=enabled LaserUE.java=enabled -PuckDetection.java=disabled TestZMQ.java=disabled RobotModbus.java=disabled RobotTcp.java=disabled diff --git a/devices/led_ctrl_1.properties b/devices/led_ctrl_1.properties index 7c71df6..ff1c589 100644 --- a/devices/led_ctrl_1.properties +++ b/devices/led_ctrl_1.properties @@ -1,5 +1,5 @@ -#Wed Jun 27 09:59:11 CEST 2018 -maxValue=1.0 +#Fri Jun 29 16:49:51 CEST 2018 +maxValue=0.4 minValue=0.0 offset=0.0 precision=2 diff --git a/devices/led_ctrl_2.properties b/devices/led_ctrl_2.properties index 7c71df6..ff1c589 100644 --- a/devices/led_ctrl_2.properties +++ b/devices/led_ctrl_2.properties @@ -1,5 +1,5 @@ -#Wed Jun 27 09:59:11 CEST 2018 -maxValue=1.0 +#Fri Jun 29 16:49:51 CEST 2018 +maxValue=0.4 minValue=0.0 offset=0.0 precision=2 diff --git a/devices/led_ctrl_3.properties b/devices/led_ctrl_3.properties index 7c71df6..ff1c589 100644 --- a/devices/led_ctrl_3.properties +++ b/devices/led_ctrl_3.properties @@ -1,5 +1,5 @@ -#Wed Jun 27 09:59:11 CEST 2018 -maxValue=1.0 +#Fri Jun 29 16:49:51 CEST 2018 +maxValue=0.4 minValue=0.0 offset=0.0 precision=2 diff --git a/plugins/BarcodeReaderPanel.form b/plugins/BarcodeReaderPanel.form new file mode 100644 index 0000000..3e615f6 --- /dev/null +++ b/plugins/BarcodeReaderPanel.form @@ -0,0 +1,118 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/BarcodeReaderPanel.java b/plugins/BarcodeReaderPanel.java new file mode 100644 index 0000000..cb269c2 --- /dev/null +++ b/plugins/BarcodeReaderPanel.java @@ -0,0 +1,162 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; +import java.util.concurrent.CompletableFuture; + +/** + * + */ +public class BarcodeReaderPanel extends DevicePanel { + + volatile boolean enabled; + public BarcodeReaderPanel() { + initComponents(); + this.startTimer(100); + } + + + CompletableFuture future; + + @Override + public void onTimer(){ + if ((getDevice()!=null) && enabled){ + if ((future==null) || (future.isDone())){ + future = Context.getInstance().evalLineBackgroundAsync("barcode_reader.get()"); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (BarcodeReaderPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonEnable = new javax.swing.JButton(); + buttonDisable = new javax.swing.JButton(); + buttonRead = new javax.swing.JButton(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Commands")); + + buttonEnable.setText("Enable"); + buttonEnable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableActionPerformed(evt); + } + }); + + buttonDisable.setText("Disable"); + buttonDisable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonDisableActionPerformed(evt); + } + }); + + buttonRead.setText("Read"); + buttonRead.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReadActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonEnable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonDisable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonRead) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDisable, buttonEnable, buttonRead}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonEnable) + .addComponent(buttonDisable) + .addComponent(buttonRead)) + .addContainerGap()) + ); + + deviceStatePanel1.setDeviceName("barcode_reader"); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + deviceValuePanel1.setDeviceName("barcode_reader"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed + execute("barcode_reader.enable()", false); + enabled = true; + }//GEN-LAST:event_buttonEnableActionPerformed + + private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed + enabled = false; + execute("barcode_reader.disable()", false); + }//GEN-LAST:event_buttonDisableActionPerformed + + private void buttonReadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReadActionPerformed + enabled = false; + execute("barcode_reader.read(5.0) ", true); + }//GEN-LAST:event_buttonReadActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonDisable; + private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonRead; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private javax.swing.JPanel jPanel3; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Expert.form b/plugins/Expert.form index 64d9d05..f513673 100644 --- a/plugins/Expert.form +++ b/plugins/Expert.form @@ -16,206 +16,16 @@ - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -228,11 +38,12 @@ - + - - - + + + + @@ -240,16 +51,14 @@ - + - - - - - - - + + + + + @@ -263,8 +72,9 @@ + - + @@ -312,12 +122,17 @@ - + - + + + + + + @@ -584,121 +399,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/plugins/Expert.java b/plugins/Expert.java index 7f11523..3249ef2 100644 --- a/plugins/Expert.java +++ b/plugins/Expert.java @@ -2,17 +2,13 @@ * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. */ -import ch.psi.pshell.core.Context; import ch.psi.pshell.ui.Panel; import ch.psi.utils.State; import ch.psi.utils.swing.SwingUtils; import java.awt.Component; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.JComponent; import javax.swing.JSpinner; import javax.swing.JTextField; -import javax.swing.SwingConstants; /** * @@ -47,6 +43,12 @@ public class Expert extends Panel { protected void doUpdate() { } + @Override + public boolean isActive() { + return true; + } + + void execute(String statement){ execute(statement, false); } @@ -89,15 +91,6 @@ public class Expert extends Panel { // //GEN-BEGIN:initComponents private void initComponents() { - panelRobot = new javax.swing.JPanel(); - buttonEnable = new javax.swing.JButton(); - buttonDisable = new javax.swing.JButton(); - jPanel2 = new javax.swing.JPanel(); - buttonPositionsHexiposi = new javax.swing.JButton(); - panelSafety = new javax.swing.JPanel(); - buttonReleasePsys = new javax.swing.JButton(); - buttonEnableAll = new javax.swing.JButton(); - buttonReleaseLocal = new javax.swing.JButton(); panelCommands = new javax.swing.JPanel(); buttonMount = new javax.swing.JButton(); buttonUnmount = new javax.swing.JButton(); @@ -128,128 +121,8 @@ public class Expert extends Panel { jLabel6 = new javax.swing.JLabel(); jLabel7 = new javax.swing.JLabel(); spinnerDrySpeed = new javax.swing.JSpinner(); - jPanel3 = new javax.swing.JPanel(); - buttonPuckDetCheck = new javax.swing.JButton(); - buttonPuckDetStop = new javax.swing.JButton(); - buttonPuckDetStart = new javax.swing.JButton(); - panelRobot1 = new javax.swing.JPanel(); - buttonHeater = new javax.swing.JToggleButton(); - buttonStream = new javax.swing.JToggleButton(); - - panelRobot.setBorder(javax.swing.BorderFactory.createTitledBorder("Robot")); - - buttonEnable.setText("Enable"); - buttonEnable.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonEnableActionPerformed(evt); - } - }); - - buttonDisable.setText("Disable"); - buttonDisable.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonDisableActionPerformed(evt); - } - }); - - javax.swing.GroupLayout panelRobotLayout = new javax.swing.GroupLayout(panelRobot); - panelRobot.setLayout(panelRobotLayout); - panelRobotLayout.setHorizontalGroup( - panelRobotLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelRobotLayout.createSequentialGroup() - .addContainerGap(32, Short.MAX_VALUE) - .addComponent(buttonEnable) - .addGap(27, 27, 27) - .addComponent(buttonDisable) - .addContainerGap(32, Short.MAX_VALUE)) - ); - - panelRobotLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonDisable, buttonEnable}); - - panelRobotLayout.setVerticalGroup( - panelRobotLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelRobotLayout.createSequentialGroup() - .addContainerGap() - .addGroup(panelRobotLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(buttonEnable) - .addComponent(buttonDisable)) - .addContainerGap()) - ); - - jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Hexiposi")); - - buttonPositionsHexiposi.setText("Positions"); - buttonPositionsHexiposi.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonPositionsHexiposiActionPerformed(evt); - } - }); - - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() - .addContainerGap(76, Short.MAX_VALUE) - .addComponent(buttonPositionsHexiposi) - .addContainerGap(74, Short.MAX_VALUE)) - ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addComponent(buttonPositionsHexiposi) - .addContainerGap()) - ); - - panelSafety.setBorder(javax.swing.BorderFactory.createTitledBorder("Safety")); - - buttonReleasePsys.setText("Release PSYS"); - buttonReleasePsys.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonReleasePsysActionPerformed(evt); - } - }); - - buttonEnableAll.setText("Enable Motion"); - buttonEnableAll.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonEnableAllActionPerformed(evt); - } - }); - - buttonReleaseLocal.setText("Release Local"); - buttonReleaseLocal.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonReleaseLocalActionPerformed(evt); - } - }); - - javax.swing.GroupLayout panelSafetyLayout = new javax.swing.GroupLayout(panelSafety); - panelSafety.setLayout(panelSafetyLayout); - panelSafetyLayout.setHorizontalGroup( - panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSafetyLayout.createSequentialGroup() - .addContainerGap() - .addGroup(panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(buttonEnableAll, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(panelSafetyLayout.createSequentialGroup() - .addComponent(buttonReleasePsys) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(buttonReleaseLocal))) - .addContainerGap()) - ); - panelSafetyLayout.setVerticalGroup( - panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSafetyLayout.createSequentialGroup() - .addContainerGap() - .addComponent(buttonEnableAll) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(buttonReleaseLocal) - .addComponent(buttonReleasePsys)) - .addContainerGap()) - ); + buttonRecover = new javax.swing.JButton(); + buttonEnableAll = new javax.swing.JButton(); panelCommands.setBorder(javax.swing.BorderFactory.createTitledBorder("Commands")); @@ -431,30 +304,44 @@ public class Expert extends Panel { spinnerDrySpeed.setModel(new javax.swing.SpinnerNumberModel(1.0d, 0.1d, 10.0d, 1.0d)); + buttonRecover.setText("Recover"); + buttonRecover.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRecoverActionPerformed(evt); + } + }); + + buttonEnableAll.setText("Enable Motion"); + buttonEnableAll.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonEnableAllActionPerformed(evt); + } + }); + javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(panelCommandsLayout.createSequentialGroup() .addContainerGap() - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonRecover, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(buttonMoveHeater, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(buttonMoveGonio, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonMovePark, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonGetGonio, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonPutGonio, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonMount, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonUnmount, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonGetDewar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonPutDewar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonDry, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(buttonMovePark, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonGetGonio, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonPutGonio, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonMount, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonUnmount, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonGetDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonPutDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonDry, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGap(30, 30, 30) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(buttonMoveScanner, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonMoveHome, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(buttonMoveDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(buttonMoveScanner, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonMoveHome, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonMoveDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(panelCommandsLayout.createSequentialGroup() .addComponent(jLabel7) @@ -464,8 +351,9 @@ public class Expert extends Panel { .addComponent(jLabel6) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addComponent(buttonHomingHexiposi, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(30, Short.MAX_VALUE)) + .addComponent(buttonHomingHexiposi, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonEnableAll, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonGetDewar, buttonGetGonio, buttonHomingHexiposi, buttonMount, buttonMoveDewar, buttonMoveGonio, buttonMoveHeater, buttonMoveHome, buttonMovePark, buttonMoveScanner, buttonPutDewar, buttonPutGonio, buttonUnmount}); @@ -507,139 +395,26 @@ public class Expert extends Panel { .addComponent(buttonDry) .addComponent(spinnerDryTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel6)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(spinnerDrySpeed, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel7)) - .addContainerGap()) - ); - - jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Puck Detection")); - - buttonPuckDetCheck.setText("Ckeck"); - buttonPuckDetCheck.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonPuckDetCheckActionPerformed(evt); - } - }); - - buttonPuckDetStop.setText("Stop"); - buttonPuckDetStop.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonPuckDetStopActionPerformed(evt); - } - }); - - buttonPuckDetStart.setText("Start"); - buttonPuckDetStart.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonPuckDetStartActionPerformed(evt); - } - }); - - javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); - jPanel3.setLayout(jPanel3Layout); - jPanel3Layout.setHorizontalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap() - .addComponent(buttonPuckDetCheck) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE) - .addComponent(buttonPuckDetStop) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE) - .addComponent(buttonPuckDetStart) - .addContainerGap()) - ); - - jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonPuckDetCheck, buttonPuckDetStart, buttonPuckDetStop}); - - jPanel3Layout.setVerticalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(buttonPuckDetCheck) - .addComponent(buttonPuckDetStop) - .addComponent(buttonPuckDetStart)) - .addContainerGap()) - ); - - panelRobot1.setBorder(javax.swing.BorderFactory.createTitledBorder("Dryer")); - - buttonHeater.setText("Heater"); - buttonHeater.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonHeaterActionPerformed(evt); - } - }); - - buttonStream.setText("Air Stream"); - buttonStream.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - buttonStreamActionPerformed(evt); - } - }); - - javax.swing.GroupLayout panelRobot1Layout = new javax.swing.GroupLayout(panelRobot1); - panelRobot1.setLayout(panelRobot1Layout); - panelRobot1Layout.setHorizontalGroup( - panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelRobot1Layout.createSequentialGroup() - .addContainerGap(24, Short.MAX_VALUE) - .addComponent(buttonHeater) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(buttonStream) - .addContainerGap(25, Short.MAX_VALUE)) - ); - - panelRobot1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonHeater, buttonStream}); - - panelRobot1Layout.setVerticalGroup( - panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelRobot1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(buttonHeater) - .addComponent(buttonStream)) - .addContainerGap()) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonEnableAll) + .addComponent(buttonRecover)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) - .addComponent(panelRobot1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(panelRobot, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(panelSafety, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jPanel2, jPanel3, panelRobot, panelRobot1, panelSafety}); - layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() - .addComponent(panelSafety, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(panelRobot, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(panelRobot1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(23, Short.MAX_VALUE)) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) ); }// //GEN-END:initComponents @@ -657,30 +432,10 @@ public class Expert extends Panel { }//GEN-LAST:event_buttonMountActionPerformed - private void buttonEnableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonEnableActionPerformed - execute("robot.enable()", true); - }//GEN-LAST:event_buttonEnableActionPerformed - - private void buttonDisableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDisableActionPerformed - execute("robot.disable()", true); - }//GEN-LAST:event_buttonDisableActionPerformed - - private void buttonReleaseLocalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleaseLocalActionPerformed - execute("release_local()", true); - }//GEN-LAST:event_buttonReleaseLocalActionPerformed - - private void buttonReleasePsysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleasePsysActionPerformed - execute("release_psys()", true); - }//GEN-LAST:event_buttonReleasePsysActionPerformed - private void buttonHomingHexiposiActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHomingHexiposiActionPerformed execute("homing_hexiposi()"); }//GEN-LAST:event_buttonHomingHexiposiActionPerformed - private void buttonPositionsHexiposiActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPositionsHexiposiActionPerformed - this.showDevicePanel("hexiposi"); - }//GEN-LAST:event_buttonPositionsHexiposiActionPerformed - private void buttonUnmountActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonUnmountActionPerformed String segment = (String) spinnerSegment.getValue(); int puck = (Integer) spinnerPuck.getValue(); @@ -715,18 +470,6 @@ public class Expert extends Panel { execute("put_gonio('force=" + force + ")"); }//GEN-LAST:event_buttonPutGonioActionPerformed - private void buttonPuckDetCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetCheckActionPerformed - execute("check_puck_detection()", true, true); - }//GEN-LAST:event_buttonPuckDetCheckActionPerformed - - private void buttonPuckDetStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStopActionPerformed - execute("stop_puck_detection()", true); - }//GEN-LAST:event_buttonPuckDetStopActionPerformed - - private void buttonPuckDetStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStartActionPerformed - execute("start_puck_detection()", true); - }//GEN-LAST:event_buttonPuckDetStartActionPerformed - private void buttonMoveParkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonMoveParkActionPerformed execute("move_park()"); }//GEN-LAST:event_buttonMoveParkActionPerformed @@ -758,22 +501,15 @@ public class Expert extends Panel { execute("dry(" + dryTime + ", " + streamTime + ")"); }//GEN-LAST:event_buttonDryActionPerformed - private void buttonHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHeaterActionPerformed - execute("set_heater(" + (buttonHeater.isSelected() ? "True": "False") + ")", true); - }//GEN-LAST:event_buttonHeaterActionPerformed - - private void buttonStreamActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStreamActionPerformed - execute("set_air_stream(" + (buttonStream.isSelected()? "True": "False")+ ")", true); - }//GEN-LAST:event_buttonStreamActionPerformed + private void buttonRecoverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRecoverActionPerformed + execute("robot_recover()"); + }//GEN-LAST:event_buttonRecoverActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton buttonDisable; private javax.swing.JButton buttonDry; - private javax.swing.JButton buttonEnable; private javax.swing.JButton buttonEnableAll; private javax.swing.JButton buttonGetDewar; private javax.swing.JButton buttonGetGonio; - private javax.swing.JToggleButton buttonHeater; private javax.swing.JButton buttonHomingHexiposi; private javax.swing.JButton buttonMount; private javax.swing.JButton buttonMoveDewar; @@ -782,15 +518,9 @@ public class Expert extends Panel { private javax.swing.JButton buttonMoveHome; private javax.swing.JButton buttonMovePark; private javax.swing.JButton buttonMoveScanner; - private javax.swing.JButton buttonPositionsHexiposi; - private javax.swing.JButton buttonPuckDetCheck; - private javax.swing.JButton buttonPuckDetStart; - private javax.swing.JButton buttonPuckDetStop; private javax.swing.JButton buttonPutDewar; private javax.swing.JButton buttonPutGonio; - private javax.swing.JButton buttonReleaseLocal; - private javax.swing.JButton buttonReleasePsys; - private javax.swing.JToggleButton buttonStream; + private javax.swing.JButton buttonRecover; private javax.swing.JButton buttonUnmount; private javax.swing.JCheckBox checkDatamatrix; private javax.swing.JCheckBox checkForce; @@ -801,13 +531,8 @@ public class Expert extends Panel { private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel5; private javax.swing.JPanel panelCommands; - private javax.swing.JPanel panelRobot; - private javax.swing.JPanel panelRobot1; - private javax.swing.JPanel panelSafety; private javax.swing.JSpinner spinnerDrySpeed; private javax.swing.JSpinner spinnerDryTime; private javax.swing.JSpinner spinnerPuck; diff --git a/plugins/HexiposiPanel.form b/plugins/HexiposiPanel.form new file mode 100644 index 0000000..65d0c18 --- /dev/null +++ b/plugins/HexiposiPanel.form @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/HexiposiPanel.java b/plugins/HexiposiPanel.java new file mode 100644 index 0000000..64ae671 --- /dev/null +++ b/plugins/HexiposiPanel.java @@ -0,0 +1,109 @@ + + +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; + +/** + * + */ +public class HexiposiPanel extends DevicePanel { + + /** + * Creates new form HexiposiPositionPanel + */ + public HexiposiPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + discretePositionerPanel.setDevice(device); + } + + @Override + public void setEnabled(boolean enabled){ + super.setEnabled(enabled); + discretePositionerPanel.setEnabled(enabled); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + discretePositionerPanel = new ch.psi.pshell.swing.DiscretePositionerPanel(); + jPanel1 = new javax.swing.JPanel(); + buttonHoming = new javax.swing.JButton(); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Initialize")); + + buttonHoming.setText("Homing"); + buttonHoming.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHomingActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHoming) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(buttonHoming) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(discretePositionerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// //GEN-END:initComponents + + private void buttonHomingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHomingActionPerformed + try { + Context.getInstance().evalLineAsync("hexiposi.move_home()").handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + + }//GEN-LAST:event_buttonHomingActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonHoming; + private ch.psi.pshell.swing.DiscretePositionerPanel discretePositionerPanel; + private javax.swing.JPanel jPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/LN2.java b/plugins/LN2.java index 4fdeb64..3d11573 100644 --- a/plugins/LN2.java +++ b/plugins/LN2.java @@ -3,11 +3,15 @@ */ import ch.psi.pshell.core.Context; +import ch.psi.pshell.plot.TimePlotBase; import ch.psi.pshell.swing.StripChart; import ch.psi.pshell.ui.App; import ch.psi.pshell.ui.Panel; import ch.psi.utils.State; +import ch.psi.utils.swing.SwingUtils; +import java.awt.Dimension; import java.io.File; +import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -16,6 +20,7 @@ import java.util.logging.Logger; */ public class LN2 extends Panel { final StripChart stripChart; + TimePlotBase plot; public LN2() { initComponents(); stripChart = new StripChart(this.getTopLevel(), false, App.getStripChartFolderArg()); @@ -27,23 +32,30 @@ public class LN2 extends Panel { } catch (Exception ex) { showException(ex); Logger.getLogger(LN2.class.getName()).log(Level.WARNING, null, ex); - } + } + plot = (TimePlotBase) SwingUtils.getComponentsByType(stripChart.getPlotPanel(),TimePlotBase.class)[0]; } //Overridable callbacks @Override public void onInitialize(int runCount) { - } @Override public void onStop() { + //saveImage(); super.onStop(); } + @Override public void onStateChange(State state, State former) { + if ( (state == State.Closing) || + ((state == State.Initializing) && (former != State.Invalid)) + ){ + saveImage(); + } } @@ -51,6 +63,17 @@ public class LN2 extends Panel { public void onExecutedFile(String fileName, Object result) { } + public void saveImage(){ + getLogger().severe("Saving image"); + try { + String fileName = new File(getContext().getSetup().expandPath("{images}/ln2/{date}_{time}.png")).getCanonicalPath(); + getLogger().severe("File: " + fileName); + plot.saveSnapshot(fileName, "png", new Dimension(1200,800)); + } catch (Exception ex) { + getLogger().log(Level.SEVERE, null, ex); + } + getLogger().severe("Done"); + } //Callback to perform update - in event thread @Override diff --git a/plugins/LaserUEPanel.form b/plugins/LaserUEPanel.form new file mode 100644 index 0000000..c9c5f8d --- /dev/null +++ b/plugins/LaserUEPanel.form @@ -0,0 +1,59 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/LaserUEPanel.java b/plugins/LaserUEPanel.java new file mode 100644 index 0000000..017fb77 --- /dev/null +++ b/plugins/LaserUEPanel.java @@ -0,0 +1,98 @@ +import ch.psi.pshell.core.Context; +import ch.psi.pshell.device.Device; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class LaserUEPanel extends DevicePanel { + + public LaserUEPanel() { + initComponents(); + } + + @Override + public void setDevice(Device device){ + super.setDevice(device); + if (device!=null){ + historyChart.addDevice("Laser Distance", device); + } else { + for (Device d: historyChart.getDevices()){ + historyChart.removeDevice(device); + } + } + } + + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (LaserUEPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + if (ret == null){ + SwingUtils.showMessage(this, "Return", "No code detected", 20000); + } else { + SwingUtils.showMessage(this, "Return", "Detected code: " +ret, 20000); + } + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel2 = new ch.psi.pshell.swing.DeviceStatePanel(); + try { + historyChart = new ch.psi.pshell.swing.HistoryChart(); + } catch (java.lang.ClassNotFoundException e1) { + e1.printStackTrace(); + } catch (java.lang.InstantiationException e2) { + e2.printStackTrace(); + } catch (java.lang.IllegalAccessException e3) { + e3.printStackTrace(); + } + deviceValuePanel1 = new ch.psi.pshell.swing.DeviceValuePanel(); + + deviceStatePanel2.setDeviceName("ue"); + + deviceValuePanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Value")); + deviceValuePanel1.setDeviceName("ue"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(historyChart, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(historyChart, javax.swing.GroupLayout.DEFAULT_SIZE, 307, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(deviceStatePanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deviceValuePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + }// //GEN-END:initComponents + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel2; + private ch.psi.pshell.swing.DeviceValuePanel deviceValuePanel1; + private ch.psi.pshell.swing.HistoryChart historyChart; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/MXSC-1.10.0.jar b/plugins/MXSC-1.10.0.jar index 504236fbf30911414762aa8e45ed3ec5cbbafff2..c51970ffe9294afa88fc3b6fdd2bd4a6df6d0715 100644 GIT binary patch delta 63518 zcmb@uWmFw`8tsj{yE_DTcXxMpcPHo}xVyVcaF;*`?oMzC?(PzJNxFMxx@Yc(d)Lbc zPEl0{SZlAnpQ`=)pDIm;-OGi8SCjz-g8};WRTjM)4^IYP8oevq7SQnG@V+ZJofmpZ`2 z&8on3f1J#y4%`6#`{X?xV9r1G5$gjt{;{=a2+V@~`zV4lFfGWh|EPt}6?pZJEj$n4 zH{jp<2t0vG&BC81)BAN*OX>-uk zYn)EUC7~-taw~IED@9gbTrnp1Z{~OWjE6N3rRfe|&wbCIyPkcIF*mpYpTerQ2SAR1uzlbHcN_ca+#kP^1bBp z-_#EPrdMv5*vxOR!RwB*%uib2O*4~#wHq0)S-Gx)mXSj{3QQLMMc_2uf?AbLWe(2+ zHO$n_@d#esD@qR)jxWIBG`f{3F65JeM7rcG-(e47S zG}d{^y{e~z#xh_-t$X3}_DXXbq5yZbBgFyjiC}5%B|#B3qTf8eC$Fz zS0Pq3ZSIqyBH}%Gqon9y=_r(Vf%a4>3me>%Id6X0W;!3*rRUR_A*(F}h*xWBxsP<@ z0VyyYO#KsWz1%Q(e#ZBxAA7azfJ_OtpkQRWGDyMQjA=w{VisdYI(d{}5*9C_AD73F zaJgrPE&4=N2)o_qlpytV8p^i00`(0JD@7h-Jnc^P8$3)?`(~f9JM?(+JVCS_msv32 zal5UM)Zx$ZmUr;8SHF5HH%BpD0;!O>DemmD8Dg>vpwkj}k0AQrW??jaK z)JV7)%rOSaj%%r|hY`#_B~}nsrOg+DQjyYHGf)sqX8V>9vZ@7&D-yVD$wKNiG{_v3%ZKYeac>)SY=>fIZa^fHgSVUD= zb>o$o&eTqVLh*s(BW4h`G{9TPB!)HJ??+7V%Qs%51ITpgW$;vM2uR1ceDElqx|Jn< zqK0Zm+C__j041O$ix7)jMim{S$u_Z22i&hgpj19Ajvz`S%*Zm`{o^HMVd*I?`#jPT z>-=?6Qwgf$yyEiML#6ULTZ}JA8{R{up?#1fhijlhU4BCtcnD>degMGY)f2UW;6hKj zF{cQ|*b_-8C72x@&;nh!A#Qi>X$-7UA_$YBl_-SUTbb2F%y9#8$@05`CD347)d;|v znRQ7Cpil0?^rQ*q%64Pcv+bv+AoK+n;w5&?_K2P&kWS4OHo085%z<8v%g@IXk=~pl zz%0~fIzi%ilA-#&fGv)RGC!z3c{*M?>!$uNv1lM&7O)xclmf_^GP>mCF>9m}dLC

jH|d+Ez^Ew0 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 JSD-6F{|6&2?*{+? delta 46971 zcmZU)19T*9*EJkF6Wg}!iEZ1qGf_`6v2EM7C$?>CVmp84zTfBlzUTXU)#|#s>Z{-2 zk9@#XApeX=z5^fpJAxGku0Z&EadVpzFedOnXBU)#HUB-!qy}6M{?D-^ZD39iq`yDr zESB}&1q2AF0t^U;I1M z+<`xV|2anR12_-_{_DGCS~R8{G!cP-UXp9QfJp&b(B7&Ci2_FlWRC|2aRJ}ik%eLi zC4cf3hNS?3Xp*J`q<|q>;Mi}rld9`&`g8?~Y9}YrTP>)SFEr5?Qqx-i@6;A3wav&a zRMoqfW%yX~Nb}5{jB8lCejIH!GxUzzZx3~Dy?5PaUIHF&`QA5q%qNj&(7Y=WaPNv? z-ctcMmjdqb(VLWHnIA$$pGvviPVvMn-(IW(Kg2cxf5y)qRGkB$y0fm~oX8oi@3Wao|%xV_s* zz6!n_2i*~Kj^V;Uy;N%k4I!xd=(tT_`DjV}QNp!Om0HW-Kx5BuSG%gC9}18hP@4I@ zw;S_xF%1(b+NpG>Zi+w*Ms7xf5N~a-T!9A&(pcZ?n_)EN4%956ZPz-mwEP(|z zM8r>i)Xc1DVdK>R0+xf#n5bXMHrQJADmZMsO~9*7VaPJohg)TVa4Yynis}}S$|F`J z1|o|>bc|^%%%(kv^@L^ak2wJJh9(k8N^iOj*j~7zjvRjJG#3E}@n8G~n^wnOsbN~+ z$yN|Ajxo8!&A)7vWe3VIW#cq#~-Y@(({Ob}k-d!;V?PvhK?yA7q-<$*K zb-&15Lxf&a4}bm{^caTQ%RX0e&RyZn;vIuRIPOB4%fO#2{w1@3Wr8Dv0@Z(l3sS>v zOGO3QpcXOAQq(B9;imi>MU9lW%DU0*>^9(WmvgGf&Y9Z+;_iFF9{>-7n=8b-naEoe zP^5-lFtxCegSp5Sq){;dJq=ZMbvPfX4S6O#U@lLM46R2%X!JoCkqercflB(f zmwQrETk^tAtC^&LN~Sk%0`LGq#AU^ahB7t`?X`h@P#&yhf<7p4$_6&C{3SRtn3x!e ztX}+)-lR{qgDpgTNY_sN^sFmOx|QoWCoE-k?yCtD4#P?sTQeJKlMA$=Gpn(}Ukt%_ z5@zpG^r}Y({!f~K^ZOx|X0Q2(pbpP$BB?3~)x>WrrL(9+^-KE%3Mb^NnT;vq=G5o;@4d$#v|%Qi3M2A!)ElyoCA>n9y%&}l`h`m>_yuKN04{Ifz73N+&%;+1>XS=jKV0L zGz%;7a8gLPrK;`C>lnqFVcP=p1k#qI-Wn$g?4uUv3)A43X7F>`_HRL^mWrm?li8s#{@OMgIK&%640XXFSaKZ_!dcsv^qPKQn zFF|PmLHU~^f6mpA$_FPvXkB@9#G@|U8c#^JZrc}GlawU6%q2{&+#6%7@`mq?s^ENF zrtGHEn}E4)^zpV>^#e{^)%PbsKl?|;D8h9gH6TiW0sG0nS6}6sNh5?H`Gn$0GO)Yg zM)0E!AhlI=OD!-UpPvhq&>2*4KYFIq)38sxwx`ly-smNhtizeetgFTe+tk0MHeUQ} z>+1JB=<)s-6k*WMV%0gDbWX@9Bma5Wuu_z8{JxD1Bl-&}gVi4#gEBFOr5RzIzSv}I%GvtD&0f1?#41FR<%1EgXfIpc##OKS+CtH#A*esiG0=4|Mlf0~I zbC9euIg-C~_rd>~M7ZGc;kC%RJ>nHEfnfNQDJV1Ot~HFwkN;jGLuX`Rq6vSX^=FS9>#>Yd@}V%pR!^ii|EW9r*JD$wz5j@F#5-rI6)tp*zPDXX9`lr zF8fd4E2v&kF7GVrzR{0_B{+|KqIDx;{MMzX`w$m1AH|c=_VqV7g1BtktiX+JHD8^F zDtg={OB;7lP&MBh8^)JiVZzS4-O0e&qK2RHFFhZNu#BA+nhr1EyF{ha$YW)U08Qzx zbPqcS`m}_u$64=(32O$D)FNxGxoe794vPdTI$o25nLIT|Wb>XEi8qxR!|u%1oA89A z(Zx6~(9tAekQN;$j-oSe+{xCLD8tsN>G!TD2BeV<7=d67c^X~W%2rOT*+e%YS26%& z$w)L1cdw}1xKcQFu&rc(MCN!WV26G*n4&r9Q1ARq$dIDG^+(EZCLOQog)GgP>q%ar zZg%v&T=|6 zhHPi@hE(CFw65L|eK1j*cgm6MpZ9phyus{?)~;!5%`p6q@LbF@>f*yHG+l#m*Vg2f zX2$x(D_Kl}--4m?$W+8C0e48bb(Vhj`REgVq}ler+TWl$pm{UShf1En5*wys>fT9P z73txUz_?&R1x%!W;?NNr& zqMr8%x{z^=fRfUb236&OH^8)14O*a8=F*=QF3d;A=GY8&1y27S0^~6L?hfU*JJAyJ z&p1KBoFW=(C!|q2j)&O*Z{5s;pxtr9!x;J19HI?ZaUdSYUEA2gFH11s_(A*l`{^+8 zdZOw9Q?M~vUOolBpP|Ymn zM4}_xAlXpKAr^L{JfI>{aRY84T=r<71b8g+s1h%dDQ#<#qD1jHN>MoiJtP0{mM}Fp zaE*mrewIv#!dW%^tQ2J)1fTAxR85biLE~G?9V?yVG*O!JL5SiXDk~nbb5&{M23pfT z{VpYk-{CS408?BB3l{+zc@| z(lgjfQZ~0Be%pZ{A%;2gW8h=;Gi|v6`#GIJ{5QNx{aHOfSDmxllqTA>hS%G)2g4WK z5))^zC`$4(3y%yb9P0F}ydo^EE}tOo?X#@1F(a2B!Vzly$37G%Vby{^)Y&`HVtI{kK^kc|GT`bL$7Yr{*wrHNF|kwcPIy)iI;M z`d?z|x;_vtY%eU&T#-^ib@!>Ay{|iRhSorrks3Jey$!fv%)4^*p5X^9>ox$BOJW*A z6O$vE@JXKW-3^esC5CO>Zjv9i+6yM1F!LtCC2H4pV*)PG6&HGD>#f5UC+&G9oRcQ? zXHF{I2Q3!-h=Jb7lB(snR3aOXfH`M>NkkzK67dGiKR76*JJ)`2^7-BNa7D=?P7n|A z?5iD19&!lw-;r@+LORK=(~u@^4g<~Bon?e~j7R>Y$#P5K62qyRo1CjTWBD;F*ULPmxt;)YnGRDU;4-Ys+a#p#g=acmj zZGi8yP9_V+NnR6{UiGbAEqY)HaSog5X$m;NwFGS5l`iCD{k{PK%vgu!7@PI#DsG`VSjkf9T8qu46W5Q?VPk^2e%lDPx~-u5zYmDjYB&-*)1v=kqz^=8Myb@&Ipx1#pE{D?1RvLcoS7 zjRRyd^8P?3XX1QjqGpCIv0Z!C2Ic0^izee<;^rDumzzc` z(hov1!wTL#$;3EZ+D>(kMszRZI@b_7U*kdLz(#lSldwhdqzw#ui?Cm~sTVmces+bz zz0$S$P0q=UTiy>^Z{hpN|d9gmuQV;NF$kI$-4QRdGT*uisra6+{lW^_*$2jOHp3o(`9r*Dn_Z)9&k#BK}@oL5n`zcsE@O4fm@IOxP=l6}+w(I{3|bjxi;*S9fed5?lru4wR_@Io#DnDfZMvSVGsiO2oy2#pNlF}Okk=48BpCy9wJ=+cI>>lNL_>!jR509R5c9y+7C!S(nInWXqCRjW6KwkjPxtA^bgMC zy+ZpY9F0#-P1>~GOk2ssM^h_qsnpK%gXKqxqZ@>-DLQsyJsDANDu$iKPvHL%RUm+%fc`2c6XC#z zz~BCA9yTu0SK42i#|~(6Yz{Cvz%_0~4pk5}=+h|ZB(>HLSP@ZFQ41YIOV9yWGKMU5 z7(I9!oCAFUTzT0gUeBSGc?Ob^iT~GbfcTP^FkT0h z4X%*Lc=EyMOf6y*y6HMqG|EZJEim#_wBg7IJDB|=;b?B2B-tGGxp!MU+hN;mt+pg# zvUgc5ti!!Q_OQaNIT)-ta`4ec#>fOc=Jl=C9E8Z(>o&LsfhGzBvOqn!1cE{GW!)J` zzB}3oO$XccURxYAmsQLmK!9v$3hMD5RTaZ8U3a#M!m=)thD$mzMa-3yT|;-xi`sSb zA3e+y%zZbAD5xR}y4;=ZpUi4@w?P?>!0p&z+-Z-dxPLTqW;Gmaz2wV9avlM5R1`zH zntB_19q8W*vz;okVrME30OB&R4g52+US!igPR(dySQi18F2 zznb?iukZUw%;5GE z;)PF;{}K28`5VfFUIIrJ!vX=#U;zQ)|D*mTlP3eC1L%!y44s`b)uBC97SKK}(@E{k zZlDZ*1`zs@$`Im+Fw&%d{|+VhlNmEoWyka|6;8%%H(ioYW2Q;1yvbEu)bTgCJFqFC zlEV=ABO1oMm38^z>Z(<(+EoSz1512=spPGX^CV!3?{VF0%1u9u?`E1G2rX|tO4+eA zV(cu&0niFB+tMqyFNLLkZ9o!Vo~qNguSK4oqBFGbskV_3#ky`V6xlKoHkYzxGayBy zrkSf%I{*`nhHbrNG*H>G&93LbBi(d!^-av3xix%bL*~NJi6Qj<Z>bN^6Hgq?oET6B6!Ga^!(=3 z4&$MA&i-RQtV@>9pZA|VV*>lF(J61S6d(O41Y=M25#7U2BHv39z*svctAm8JBnVXz z*a47zAacpYjU9aZ`TFIDkI7z*a@pcE`Z=+6Q!G=MvKTc@R)4(Df5*u8EFRt-|Bexd zhbpL0)%G`usIY4LF6I?%J|R_&zQ}8+A9Gl!kp6REX;H{oag1J{a=a=20(ZkHO5GO0 zn)|Y2wUFKVqZAEoI zeYZSUhlHd+gx3uh>Wc(zIoy)3sWQ9rH_C$~N%#r^M|2B*=dXxLzH`NFtRSJ^AaX^? zD`MDKBS18KPoa-FRB!jkGmO$O%A*BL|H3<`Hx8S+_~v$ue-1|QYN3%QKz>UM{>Ksh z2VLr1hO)*U3%GfX=$>8SWGpX3a4`LHGza z`Dd>>bC=qcJ+9gn{73$__M7^kJ51De3GsI$q7(@kT27hgh3*T~2LC!<9!W~HiXi#l z*yO(CwlW|x{xYjS9Lp4e!z7SO6RKtsDq>6)x0Ay4u-Ff`3@%5|f97hEW>TlZZ0KBR46Og)lQI8mQFmpZ>8_ zPT|EWhC%&SW9A$l#{p7R3a4ug>qdTe6f0WwbdbbaO-_IlrWtB>>hD(rz`uL_A;`@Z z|MH!(0)kgXD?dC;SD<3VmSxc$%nJF@G1#^3`EJ*5gG%?_a}Tm9PO*N-WPsxm>h&$x zNm!1CIihmD(U3b@Kq6cz{e8ZZ)DHc5EJ7Z{9tPFZPd1^?e{;<@|j{mKw$R zA*-8nT5*ipyt2q^_Af1OfWqSoNZHo$SwX^To;CJ?y_Nz6gM;!yYoBIkS(lk#mD>yq z_qda-Zi~E*=bLEp$c5|Rca1`IVoy1oNBw#>{P-NSM79#(#)0{9c_qe4E?<4=oXAyL zP3fLG>yL~d_u&{&5%P;pd(tC?eSB?V-!#fjsZIU26!M$%rpZqq`ZP2;vf5Ag};WX-GMsb_MyIn?JOKd@m(KoUvAh?uhJ{aQPX%)^S8mX;9S zcza>adHwuPK)h<%#FtyWoT(zX+Mtx28uMVj;FsXNV!1RLIXSMI^+Yat)!d0tW>wt2bsA zF9lO@M(xQhhm$%o$K*zL(1Z;Jv7i1PrY+=)=c0*vn+>o-7yYRI%Fy`D@gT^*CR>C=an%OV z05^NHWi2i`I$C(ihXaLdj+S;hS~$t*{f34*hS-Jus6%&9W{4#Y;}QN+Llu-IPPhc% z3sEbI3VSIi;EhqOii{JA;sywZj=$0`sdFVV6{MIn5p#P)6$pOk1t1lhA0koRN`O&Z z{G{=R;1>i7C($sPYL=k{>^N>Eq52kB^Y-=DtR?4srbn{YgC7!%EMK4D5Fp=QI(XPqn4^; ztK+Yw>eSc))_A&a)e3FJHnISNJZ}|Wjz(T08(v1{d7Gf2j*>mg0#|nB;@MMw47i>w zmSV^kZ%@NNYrWIpn0}*DX~U=90IED@wtBpD>uaA>@uQQI4IAzLm}&N?;$gJdDH^W~CSeD84`rWP}+(McyyrB?6>ij~576;drzsO}nCLg2@qUX?U}MN39{=vWb-0e+**TJci3 z8g;v{XT?pDc_U>d(f6^;n(@+Xgn`bg^{!oKG~i50%Ws390O=*@5qcvsNM7!lp0IQf z`-G|&RzndCSSPV|*g0;)OMlyJh#=wxhNO$XN-9LR*EZY3lg8VD=&;s|5>8U}n40x} zq$`Kc4n?3fa%xgI*#(N!sU_d0a59Z`NX&jDcUrgnn`kFsS`uo^?zmhe_Qa7{lKh;}dW}>P?#l1_EMFR(u4;OYQ*$g#`F0>&l}DqVfqh)3sL=5`qgV_LmhR zs-bK#k``IankXVSUe0a!;W200x;4Y^=*K?AUTq^>iDO;LNcz;&#AmiX9Vo>$N#t4GUwXt^C6r~S3Hpk;zLaH|v3 z#-HB(oK{y-*fz8v;euQ>B{J^7I$@SVAyi6;Zj2SWJ&X^z!$olW9f|X4UI0Upsn6)9 zN@g9C{j$KAGFsL{c?!VW@04Z+8q4I7JqJ)k4@H<&(M(UOvG*?FxpXa<)j6#ccw(n>I)nX|UWyGUm=ifKDDhDC2(WUe?YkJ(AeLs%+sZ3oAue z&kzyB#2`XB2(e-@VTI9jjGlNRRO`7>ATx{me(NAu81Ev{R_k%TacOX#ozh;H0&ccS z69DYCGuOo}xPy-lOoPQPRvuM|Q&k<{ctjJ?I3kzg!O34 zi9utb(I72|Lph^W&x=qaS1cU8Lu8c{uZjNh0rKC)pD|_-ZBw%1A7Ektd z5lDrZT`lO@4?%J>cI6SKl&CHj+z6-i9P z_HzPoJ=;-L74!XTd@&*reHxNmRm4|ewOcA*MkyRugh^Nce;T-W)CPJUKy3y*!pxaK z#s{D}?{Q^&Pg&0cJT(PS4r!mKdDP?BY-JJ>tkfwlpbRaEasJ%aA206&vSkeNl{dVJ zk`NU-MU^|Ya?BmNxVP5~Xfwm&bC&2mF6|wp?r@0o&-`e5Sb2;s>GXlO0t}5eBct3V z*8_16_%tOef9BQv!8JS#I* zzZ>udb_EwLtTGeA7zv4#REuoD*3$=M9iT0$-+uVbkSg(gfBnSdYG!0#!NQp|VpNZD zzmUCcnS@mfg%O}l5nwg+fSQ|RmA|P2*G4UXz7av_Y5vgJWs$M6-o;Tb+Tm94heNRE@!Jb^4d8$!%M}h=2g>c6w-ciQIL6RDTuW(wA8nXi=3i6D?B2%k&8$ zbguT;rGhtfWK|>t@9zRIu8WbB2+(ylQ{!1&&TeKOyqf|*Pa(1dWGbK$JGMW;X@6)u zTut`D^p#iS+t>yh@}p;#n5)irHW730N)b5I#ZQ4f=QWHzV3pk?rBt#6DFNmh$b`An zw0yfyn@l`MwV_3ej7U7329*!q1Z(z3nFF>Ok}O$v7NwlZ`<|`a2_(c)!)361Xy=^c z-AvOB3-R@D_@keuXybfJ>yHV8ak+UgR1@AK3{S`~g&mBll!&^iDQtF2PrZ^wOc5F- zB2-^?CCu>V9%`_S;QtWuMgW4ZG8_G{`+6zQ;SxK1d+$Z>@?ELGEw%8esnpox=aGU| za%~ExCh{!X`0}YDJ=H4O!y$B_ENyM=gTC(UDUw&SJ z{atC5wxn?c5kJ^Nv)uJ$-)#4yH6js7Jd&jJsr|uVdskr4wm8x&HCxX{&r=_^s2fzg zkF84qDko=bB?zIo?i?(y6C7KURS~T5t>E@F)mL8d z`;2JYW*Su$FU!$psMKE~tW!HkhW%!#c>pFQ>|zE@446`MbFpv-8kWyHMN3I1T=o>G zsiBeEBjEChw~)W%XvPq;Ea>LcdMgw6)q-!A^t*|$OzD|T?^0z1(iv0(>BdEITA}8`K5;Litj47wO$^wS^ zJVVr%p>_<311>9M=dqH+EX_;y?@_84@}tjbs3hi26(noxQVXIO#}Q0PeC*Ka=GxiQ zW=qTmg4!*50%H~zA0I6e?8PTep1)YyWCF+PP$M;<8=X}Ay*m15Uc3oj+$FJ~^AV)R zEd|V$lZ=G^DDf?aUQFi|K_HdNPq}p`n}{sSak!Q!2p!*Bp5;lpuxJ%O9?G}hB0C?@ znV;W}jM1G%l>5E2>VJy9BwIA<=Vctt1szDdf&Mp5vq8!M9sdHGy$1}C|g>SAG*#Ul1HKh;c6Bw}2m4^m(b=;_7qDDFmkI`t zTcPB*lz)(#!|`2WM%)B1_LA7p_!38B?;DCfjEso>C`dr&xI$HNxxv zD^vd4kbz+H1L0`@H!ouQPhRvtND4>lCKoj5qzSbaDq$C-N%g=&{S$a$kV76P%!tDO zBI&1Jwwf$e8RoGK`b61ZfiuHTI$X!c;&nK_lG@td-3ne4^aw0f5`;OhhRBj~&vdkx z8T}*3{D=6;Ds`U=G52+=s^jBmm`5~?51^+}h6B2;uwk_MEA|qlAPm737FkLMIpsCH zdCu65oP{(ig~^bLUEQUak3PQ}j3k2^( zPaDN;l;x{NNKHr~6#pPG*rb+Nq@h`gTac8Zz`+aarhTTQVA>&slvKh5nQMTd6Cuut zbG=2{Me9t07~k#bMII4`ke2qEMxmk|T>9MHc`u0V2&KigL1I`tKHU^lC$LZ$KZSL= zHwH8gP4{nX0OL)4kH}Z(?RnJ*!Z4A47d6C1%c;S|$v+|^f6?Lbsmi&AwK>4v6eyd< z^VniKe1D3j_b7n9f~gK2>@$gF3AFsn(XAYv{kb4C3EuxTJpUVf(LvV~mXp6<0#gHY z?dKR#`Sj-8pmS+(Ol=q+1pSnXz=8dPb0tf_OO=|5m|iZ(&93*kRpZ>|J{Cy%N%5b6 z-zfVVc@iPp2Es1y7g~?-_1C&T-`>Et(Xv_`9JYj!tnt;Zb0Y4U*)gSl(AK{=2OZd9 zLiWi({HmvgduW{}XhpY5CbTb1dd3IzS?$4$&*A@?lOq0IGo7e~8v)@Hi+|mfH*CZK z-FkYhl6G%8&18!87PUxhOO<8npF~st{D(n8lx&8tN-Ph}*@u=m=s{(IF+5O7kaUn4 zRd6kB;{y7h3WxJ7JA^SCiK$IGo;9e^`UEq~Sb6j8NC4mHIj#USmf0ga4xoq~hA?|p z$Gp)SHIjSLv6L&tTpIl-icg`4mCoOEH7yQpN^o29>Jc#Hg00T#Z}A*T<#1L9VP2{2P?K1FUKg_iFLSg7IML2$^yI1v@P}QfYCx(tlZ{5 zWey#oee@#vE?c$_sPzY+XFYIWJ*QO!bDPXN?NUaeB^12JGbnPVWOtEl$-I}-WaCi1 z=KPZKE&s;m#hUtUaF>hbl8%ly=35-Y(y4hW^Xo^4)mlW_PlcAEp7!n? z{J*0z`3oY`;#YAi@a1pE``6;`;B3iYn{4n1{4H7c9vB%gBBVYz%5T6Z=BI=x=--@2 zJnyGc3QC%DX=j8kU!_ZC8Th0w;Vr>?26-k4e7L^~+&3%v+=XU3%Eq$}u1wO7 znlJeOVCk9!DPdQd`t$JAnWBc}t6vuQ;^eTqPfHJ^XThX%G#_yNjlFIMJnko1JMq>H*J;hSzaE z@V3d@ndV2c%@HvkyS6b7t`M)@g|Lc>=lcJbx$Gby+sQJIz%+pWqi0kVf;9fjgHp97 zt3v1yl#oHQRD%2J_8Ynz4B41-@MsIYsgwGW@;`yTDGu@|S1`cxtUR}PU9=u;^1QxI zP3Z%Uu}}FAXRfbNr%EU|5`G!pqG#F@XQ7FSmd|IFWt9QDs@#b9GIbt*lR=`^Wnqx5 z3yI@GO=czu&A042xBGEYBiLLfg%QD)F2;L)c$^swOAT`VaAHHNcX_~3vxzXSt2vHm zm1Z3P{BmX4B_O&(j}Fw%ViO^T@>tc%k2ILOaP9-X_7OD-pq^?YP}qJAe5SSYFRxeu}UQ zVUYiX@eGv^Kwy7xKd8V@g1{EH;+yZy8nr%uX}oUz`k0;F4b;&?LV#}vSz<)fLw+&u z*c@dWq!lYQ=Q~-$A2MfQWWxGkvU?mO?bF++&<^&4tdaHslbr{{03QLXLoW#`DA8|z zw*)s@nZJTvHV^F2^31*pc`sU&-0Ya_! z_{|r#{_dKoL%Wd;s_chky!A};nM>Sisj)A23aFMz^NtMt-!1^bCAs)USm%fcS21#X z{$h-0I(be4JMq0`7IbjMzUFQ6=2We5+2>R)FHPWyQJLyvlD)9C47c$*n97G>7Ov=Q z@M|t#_Tx&8ddt8$yU-8QryPiByJ(v~&~5Tvey#w6lkh&B+*UEnZ91Ve`*DSqFtncY zFBZ@ApK>ih_R4rPylhk($am*|X&DYX;t5a7Gp^=6T$#~qI?gBFI^tuwK2obffrD*( zt)cK*e4fb7(+(NqwbPIPFSapA?8%Xzz{JT>ufWg%?Z0dHM@P{)vXDB&*V>Jl|D7s? zFu(&VEr2_Q+7-i6A#0J;YU-_RWqF_j~ z$M-qTVkEdV43lT>FU-wmw2tN8Ctb45{=poT+h^^ofiY^vCFw!*EsNlwH-)+QvT`yn z%P_o3DbWtin%#EOMJvx8i@(H|`#jE$PVn)XqvisE*2l^*MVj=B&QVBl9sI&O%xXaH zbv6-dDC(0fn<#_%8<)P|UN?Wm4nJoCrEP?$Djv|u6Yq-MGT5U%Y^`tS%G2o74U4!_ z@D+0xGX#z(@IxcGuzZ03N65kmlTcVm_IU^908EGFP#P>~h5P}B#=t~YX0=pG06UL_ zHf!Ul5iY8qxM)(`8Wkbi@rT^bjW91N(9>9+nEV3yZ8Fu_jNvmwA85JP8RHwiC#BIq zA2WX9bxVY5kP`k_#YdQ7Ez00;!g#??YjlWLom0@Nz*V9V>r&IMv6}T3vD>_{?S?oB z0OPo80s3X|dzOU2O&0N(5XD!5cB7K^o;br~i1pU=KM7is^xX5k?Py-yF}=F*OxRaw zL+aZkO&3ImE%cX&FroD4<2iScdk%pN>;E0RSqgPag&yy2c{W(%L=u(D$-Fc1<6{r; zfK&37*!1dKydid&`)o!XGgq%PU{84AN4apKiBk4iIImnD^P+dfUT8G(D8HHFg z>qE#B-`b}~X^67)gYp*4wd5edc_sgcj2fqZ$(TH;TKJtV=_ zQ-QD<(XKk~JKpQx`$~OaR=@ z4Y2(ySNRV1|COs6?sdx-p_qiG5JY3b2n7XO=D&ykN3PmPeXvK<(t61i$Ptjr=!Ccz zCLY?D80WtouV=Zvy!gtaE^GJlBNBn)HQ;Lk*bx5UZ+a{fb_{!Qm!G4c8?S`hG2`8L zn=)HL+phMO?1KtNHOxFS83GFVA?m#(DLHJ_k*I6gPxoxQ^Jk~>;vG!ro0LeCi5Dgb zAjYa_iFi503MWKNQjOeyuma9wR8<1T8`*3VeQPcCU7>OApS0jaNV^VWu_@!lDZuyV zR|1RTu=fKRj|>8~<2z*wx##4T#)W6x=|jh|uv3?1(#w-Zy_)_QvH<$gH-oMi(R$q% z*{#;QnP#CE^1O-1Rb6IU)#Au1qg7D<(5kN^^u9?jCmoT`G`!up^v4Ig z$BPF~nA{-Z00od-n2(VeohG*Kxj3D4;M?D zUYAeVD;sMY()2LhQ=el?sXuNHC(=3WH#?ld`F%_t^CN1zWDoD0eqPsSLy&%LB<*_3PeL0_kC6P#MAxSv0q|!%w#xXP#Z_6N5Lf8GYPL z=KwojqVABM0hLyNotiik_0|<4-_Y@|n<{b8>?XIaz;%i3Sfly2j#m@L(&(NU`zEGm z0>+k*8nZmqQI@w4m#(Zs+oDP$>A{wiuOZ^vV@uMZ)@8QQL7LlEh<($0?USF$ou2Sa zUd=$jring0pYW!{oi zvkHU&K^S{O;%NVV#4EMU1mXpCMphHu1K0!0BD^B?dk6c5$Vquyyng1?`8)@fMRY~$ zCk&QF;-GOj)xN^kHV+G?m+&mTZyI^a?57UZA+^m0QjOvvd}!aca^5zt4Yo;s6*c}T z9$#9!MRtYn_h|azm%dS4FF<;QkQt1c3CE-h-6-DU2lI11$yw2i6wvfMB&2PkjS*7bj|ObVQRE{q@L#;BGzYj6C}Lh(B-`W{4j#1R`fv z51}X=xvsE@qrWyB8U?jciZ&cZO8J`+X(N`XorN%SzT`EgW&{~;)C-=xEM?({M8AV71TU(35kNd0U(zcoyw?|IEiwXR+Lt?f2FQRge`I^Zh*@!rOK2Qm*3x+ z$vONM)v-&P76ZfJ1sy}FMQ0x!BOI+x<0OdX?n>(bIXPrO12tKxeGIi$4BdJ|ft=nw zoTfjK)EUjsHD#mU6GWZH=ofKS>_B5(%eNHnt~zEdmO5S~ZJbK*LjVmO0}fhcI(8*( zs-(RnuRxxg!Uvt|aBuWqys*0q92y^kJ$=2eO1_s-_Kf zlX02ox;Dc>abDA@U0kuN$NM)Dx-L!y%v#?nTm?ruI!;$L^agfU<2sNe8%tC(mG#xt zRk@gzkSargtP|Hi8vtc>bvMUQvH>!T0b}{G*k@Q8o^>r$78ZD&E!ph;t47G@ zsF@5^R9l)1PfEsth_oV=NIHqMhQDl(xtXNY#vAoK!WzWxtpvmc46V>8YGvsorsiYC zC!L{1MuLP9O^*?KX`6J3KGY6(p|4C4ziRITh2vVp4y7MzSlw3o{@rXr)ViPlcLN>A ze@Ri%k3Th6dY2uwVwx_PmP?kiWFNUjxm_6!geIT~`pyu3W*h4x1OH5Jdi|27A`pLS z4^RS?vC5Imb-X{pitd&O8~@9qjZ#_p{{e77kH4+2iQ*DK#+X=nIkq2JRasY4h0*D^c%!0=BA9W) z$SH`G8WO`x>S7DAZCVO$@6_!4)a*W~*?m*9`|0L?BAeDfX1>^2(NcX(+9EHC%#GG9 z!PSP0iTTzTsZ0w#QLj|foM@@SZIIe1b5nYCa!nPk zd|LgbxdZys2ocW7TQv^J8s=F&2R6B*y|eP&L=TlICZ^4dI&t=Z|Q)g{tW3E)M4 zLOU{S#4{%@4PAB8>JI2U`(iM}k`|01W?v%)OW)0>$D-(CXKht|O$n-K+i0D{Fbpa3 zinMw(YZFdLbaAw#o=i`gf}*+_l+=di(uP(MrCAL%6#7IkrUsi(wfvX>8 z0_&1OGWEPWYfEZk)!3sHsVSqg6-By#c{U8jjmiTP<-{O+HD;I=I?D~BmHkvl zX&BF0(VDqcH5HV4+vQkCQCx79b$PnTXrlFn7F}3JN5_8=1J=Ijsjf*^t?UPX!6vn> zla7E*s@o(VH=ESAZ+c>EB9q_p&L^w-@@@3w`Z{ ze)d9tt)OQJOp2Hne5O4;$sCn`=kRQmcOlS`Kqms72^>eD9Rhd*-c-2{fw*4WAd4GS zag(?i*QkA%Mhrx?G0EZyVF{cii_NOIOWduBE#e+k+)MiI6Zfm| z9=wlv$=q&L@qpNhk(Zq9^kctq!dJyM@gT`PB#Z5;h>IO6TnsBzu@l~Z#J#ALc7x(_ zeJ{#PIT@XLi+lfC@*bS(@3b8W-e$wHm0xKh!Fm;+Ua|$HX34 z>{Z1+@whCWP{osCzbX#E`zmJ?AqQzj16E7@D5S!3a99;j;lzul#WS*aRuzZDbE-H@ z;CXB{kIzlU8*l34;i0pz`*}OVcyuux- zcvZZH`>u_jokK^HY}`OGA4clX%UyAAPZGd`De;;dTU6Ks7;mqOH&pSacuN&;BL$Bk z5B9QQsHrO z!#>#6xV3g4Rbd0HR^bW)R}xrH;7Mxo1cChot|Q(uI7fwlXW&j1u7TBf{z-kRSK$?S zS%qt<#Y;rpNYrL(b}yNkk@{w-!b7lKg-b|ti{>sXD(oPkIDwl;?bQVCA>GfzVPGBp z`+B0n3xM%{KeaiR9NMC}cM%otBcYqAi(AO7PDk_dqQZr6kqVbns|Tq4twh~M;5_o* zgXDv(W}jDoR9FeCRM<)_8_4qy6S$q4Zz6Chfk%k9jYKY^;u->L3A{@Fex1N;1nwe{ zog}=Qz*Qu&jz*Gmv=>PgwvdjE)be@)HxRgkz;YVR1>`}8wyb6Gqbhz9Kda&w@hdX5 z%bzNK1rXHtAb75_*~ zmOzz+B&m`^l2u8O+_L0RvFKJMujG@ZfGUNguqvfV>BPy9rA$?7A+;jVT9w*JZB?nA zl&wmC?MaDO>Oi0)?pn56!Mv)PI#ucZ+=T%&8e_TvUhTXa^@}^%b$w*xVR#W2M>JO&0H6vXL2o zkkXI%+0D;SKF#|eR8GS&uhu?;%1%5_1xMD`kR!{NWE(cC(qP(w{WYjem)5UPNou?i>EX_3`wPTYSo;7s=Dm4czvxVNe8{vpc9;$2M19QYOgwI`A~|# zV6v}AR4vAB&t`aU({wvG-{4}Vkxs;b!BdHTd{w1kc*K#06Bt2YB!N-XlecI|ExJ*g z%6gnYb$F~M+j?;D;3QckRl8heC!QHRbdNGivT?a;-e-NAufj+lEsas7vC=qyTyIOO z%j@yjQM)Wp4=3%8Axq;`X@Yc;DiuhDD%3)qEKO9UN!sBm^{FNCn}`aFVWBKdR;4M@ zRJ=GyMXEGSIvJ;s?i<;*bYU&TQLzfl3v{-`6+2y)PEn;(r5P&J!$K7nA&_QDr>WBE zbg=Z-=tI|!zd3kt^CdWRvL!};ddh+0hM#PCeJszY2sM2(!q6;>*3pFHaRLXO)3woC zPDxcwG|#9XY@M)D)Z)>tjDBz;Hy1`KF{NQtc1o=O_^hdpz zEoHWB?&X3cJs24UF-$psmEn(Q6Ec8}%xSjuzrJwVo{`9v zwX|0oG33-Aa&fiRQZSWbqN=HgRcb6xX;nQony$Zqi=3{b630J(O>1GKZXU8LBDi%p za>kGEI-W`~%yA0pGFo|KwRi`bYQB@FCrw1+rCj%N;)2`8kZE)a)~g5W>a{B|{r;gZ7vo3(m>#A+Kc^p3`_Kr zi*}SNk7^5LOg)`T2D_zM((Fb{yy>%I;>Eiu%MI01F?xZHn@co3%`7yVL38UXwY@EG zL~M*fqNh6_oy8b|^CFd{G?(LZ{zK_edx2(QUezM=@dlTFmfa!NZ%5>O`t`{0{lugD zq2Q<|1D$zBqn8Ffh{r@q@Xo!2_F!!jN`Bz!moh>B$Geb`ofA6R=KRYNqG8j{Gfms4 zgP1V&CtfRUc4+41J|Ut1T7rvS`*n_DehhBXi633uSjJUfq$TUjq;*zVhcRTdCwmjW zD73Ok>Ab{$aeyS-H*-nsG`u`kR;m9;c))pRt;v=fe6lOpeq< zaKkLu#Bf-R$^|(`p{#4OGD+IB9Z>7ED0*f+HpEP0bmMQr>6X*H)<(jpx64tA>W3(E zO2$TzqiP)Ef(UFx(%dCJ5u#Z?YI|fU0xZ`qtqT@^)h#KHb~2UX?q8DlwJ#M@o;tc< z_%zD4-3yLh*#t}pR2v0k&P*NRTX&gLy zG!d-9B9TB671io&DG;xmtberlESSmgqJtINt6e_F~op?I7&b@=!K zZBHsm8B9lE)iH%E#Y%w3Z#42KSCf93li^^mA?{SGT-polYlKQZWcb3%0x#oY&Fuy^h%W1TZaz*RZ?DDupT7Nz>|pJGQ=g-d)1C>?yVI(wjr(~hkpaonF*O*EgN;iq zind957qC6_pG*u|X*A`=_~zOc_bIW;(yB$x-p!L90h1TogyuGx3Far=0UBCVe_5nQ zMl|H4oaU4qE1!lPE}`E+##_D62NP0>DwRrQD(}H_Ro<27Hu?p}ma5Tl|C&F4aQ-dF z#3~n7Er?=s`edaLuTgUoS0qn`Rg$F`{S;MIwSbyGYY#_5f&MG;IPFSV+ew%F_s5Z> zhV*Lwf2-8H{P(t9o7RrRJXsW@ul1z)#_{hz$Ah=Kf0twJp&HI)j7?{Zp0Vk#PSLZn zh8G!lv4%N)@uK0SaJGh*!8sa#KG(qK8TfnyFE{W72EGt3((uKwLc=Rzm4+{Y)f&Fk zz?T_#je*x1_;LeZVc;tbe3gOM8F;;cuQu=o17Bm{YYlvzfj1iXdIR5J;2RBmlYwtG z@GSyeP_mXPa7a(TI-UJ1G0B$uC%>y@OhPj0AhLaral^-sw4 zO_Cds8yc99JD%hQCFBMs$qmj84N1tIKypJ9azm2jPTb4_h3N3%+t>)`9%mzSgPxsn zHVRpzx8hWFh6<>EX2Y1!CbyEcLUVw_FFfR3}th20OZbgZ2cXH)mEqR_NBJ9#tfj*g!$ z-JDc&idGYUvT;sD4%x3yMLt^0*kYW9B`kw2#g%q8PQ)^H0y~e5V&}7QY&o0BE?{%m zg*eKKky@#ZGZ)8_%fj#_e5HBd!o-M?`Wn7LFN|Wt;9K|({X~xSGN;Gg`7hR5hVQd{ z=#C!}j$vz10jU^dIA+FmEP(dT+{R9ev(q=TPUw<<891_Q6YN5Y6gKa;-&xUPxVw$5C{jsxROc!Td%Uo!{X6Dp;Ms@_*bI`VK+gQn_ zR(0$Tc$jF2f&$f0N+t%2M056K>w(UmS8ql^!(6+~p!M1?{^%^RK0ozyfXa zD&LGrzJSgGxJ)VGJZI~+z0qw8=HkG)(XGsQ#xR*XdVT zyJ1?dY`kNRl6@zkPGbw_E`hsgVX61ktF5nrHDU;U?1s%exLXSYr@)b(1p;vdZ*W&DTO2DBv;_OW#8rWNOop?LW-ofJ1(EsA>T_PHP*n7l(Kh8eD z;yIxYwYDE2eSQP`ct((&7i6CW*)==ZCvo;Eu>)yw_8Ah(_4+-U$a!Y{@GLSN~`%Fx$3vC8ZtNyn;$j!VpX>}HQye@UW#wQ0jOfgWb{>O}RWp>MFC z2KMa?8ru%`9c@16;O6sxeK$Oz{SaqABK=dG{cI~~LpZ_%N8;?4ZS2=L`;CSWXTQhU zA4dK8P3l)9)nC%2eq~bqswVXpCDpHPQh%vlA7_8cvK(iBY4qRrK?s4n-e1VTc0bzs z_(#)DSH?dZi(Fz8S(#eoe4EIM)FR7mA{Qq_g6IB|B(&Nlbg3?XL_+|M<;%h#^kBTK z0VE7YaOlCfCJat98rOBQ!NnC_Iz5-elR z+21{c;}K{vLr~{MGbHM(C=OY6>ujWcjI{i)R9_0o#^`H*!<4y9ZxCd!TNdimwq_f& z)CUHwsDE2AX>ndjOhBkT>jSGs;;?P!qOMrHWZw^DYUUy3v+FL1S1A2cD z4R8ZJeSM!LWl6dvRJ6iiT;NEcz2@trdfgh0Ww`ey-K974Ku5bzHEDD3H=?$7nzlrh zIoG!&<}|r~#@@wsdKViL3pO!pRwOqXMWR6CNKCa>5$LYRDJf0#YYus%E$RX}X3*W# zMDXSWC&;$x|JV69Hjy+37nnhR5?RtnSo)+I^Kv!Ki-U+P2hEEk%VCVjVTRQP%U6kk zrxY{BoDkCj=hiTEFazf{GhA+?a4}4{l}vCFk>wbHwUCu=-Twn&nyvN>_5jysGBHau25V1DWXaUF8T;vM+kSeF-qz~akeO+dG4yYP ze4BBaUD|4Yz_!{Gp=Y{%TNwJ7ZhtTgeRXGlKNN<3I<-9v{q-o?-T(tAiUwLy6eo|n zh{$r0$6Z-2V^l6P6m~UTYRO{UTn(luw_9oSwT=3s{e4@OoBDERxeX<5!-MuR$`v=6 z-3Rr}Bq0!KBJhwdK!Y{?9&nm*A8$I8lvWsXRBW502b1Q}l8M-49uGq>Pu+8pBHsHZMJr7qhWGhlt;Y=LN_UQ++$BSmr zHu(gd&r;iGxNV=FNcP(jiQ!sH=5bx-z`w~nq02mJPe_g3e=rOqO!q$%hLO5|tDgjoa@c<8peAK&S*KxmpIcEad5jGQbBQ5a$44LrfXClSWOM}bkM>&@XX zOfAI_UVI@8lXdFFFig>Zsh7eqRi|DKLy?~9Uv7YDlUl7qRW^ja0p$%RS#%&f2h34(mwMVLhKT?UsyvxGyv#V|T-gxp+nu0)AHqyuTQ1yUQ?SiO@3zr<(Nde@gSMi6063g+dd_LC530l<>`;P}FloJEVVQ9`+l{V865W><`wR z{mBNfzt{-&H!EaE*s1IvRsxJw0Q*1uTRtI3HTVrO*mC zKx?=a+Q7ZoYA3XV#~~Y@gZA(SbbybbBYX>;;14*CJD@WUKo{N$a(HLx%6mgD9|GO@ zSm@5DLJvL*dh&UHkjHDG7e5Dj^Hq?~*FhhC6ZGYGLqEP9`tv<7fIkBR`Kxd|e;)?% zuV66$6@~~7CkQVL6)oUI(GiA;o-kY-4m9ym>{l% z0 z3MmGaQVmo~E8$G(3aFK?gL>%>SSZ~Gi=+o(v9tr0NW0-IX)i35o`kcd7hsw68k{5j z56+d|$MVN;p7cGOFZ~M3r6X{G1K>P|11@v~;UY&STpKF^oCWA0dR?9 zD6Do2$MR@@xYRKPE_0j$YaFv-ts{cvQdsJk50^VCV2Ps|7CCC+O2=Zj%5gTVb1aAT zj#Y5AV?AteTo2bcZbEt!TN=OJTdS5_UKj!cON3*yUUc4bBblu=5sp)Oi;?=G+Z?ocmy(^Er6j`6@i&d<&j* zz6<-EAHV_U=Wx*Z3q0lg8=jV3@QfUQXXP*)lr!LvoCW*k*6@Vf4i3wm;CVR*UXXjj zi*i4Icu5`%FUw=$6}b>zm8ZdL@=SPLo(pftmGGu~Cd$=en?>-BycXV-H^O`JZScN) zCww5^10TxU;3N4__*i}#K9OIAPvy7aGx=TQe+Zw;pTHOL*YKtMD|{vY179m1_(loA zw@O?1PHB(jPVl+X1>RS3;YVdS{H%y!UJdOGeq3-9oOL>QT zlux-=`JVff-+90#c*y1DX|9$$-PMt2xN>=>E04Eu_2XHt5xk{q0&nG-#9O;g=51Vm zvw2%rl(%!$@N8E-(uue(oIJ-`$rFaG%Hrx=-TAyQlDfLGD?6usg?-^TL0SoZ-h zbbrn#y1(I*+~4!b?!WmI593okf=}`|d7;O}PxfT+Q#{%HR8J0{>FLK$^9<#Gr+Y^8 zS)K`ewr46Y_7w9oJY_uMnUCcPtgGfFo<+RWb2g89&gFAGt9hAc4WH+^0?X^LZUbN7 zxt&*dw(=@Z1F!Zx%@=xJU6$Joq_b}C|k@gRm=Gr zbs@i8J&#|hUc#?Z*YWl0jeLW;gz**o74~Z z&Fbg;7WF%RtNJ7Ie&e@!C4Rft%{O^N{0?s>-|TJ6@AP)!cX@mByS;sX`4;a0cFTuLA`Tu;Y_`AL<`Fp-=`TM>b`3JsR_=mo`_(#6`_{YB8 z{1e|E{;BT(|IGI^mJjpKeQ)tEeDCuweV_5Kd|zVu2mZD1Xa13YpYd<}D*x8+=im85 z`~!bFf6w27|KM-OfAn|aKl!`xpZ$6K7eDS={t^5)|7fI7;=lWg_#gga{-=K~|H~gk zx{CkpU&xR6&*A_0&&PI`3Ff~X^;{){|7PLv-z{YSL&D{MRCxT)2-W|x@cQ2pKL2~d z@BdH){9lTo|2q+X^8Y2m0WQ)oF{B4n5efuFMxc$z40IGN0=Xh9&;!f)qGe#HXcZVG zS_e)NZ2}XqJVgWpGeq0K>B1i<7T&-dksXMM_JK;#A#kSX7+4}Y1uhcD1uhkx18b39 zFS-P75IKRnMAyIrA~*0L(z`^rz+TZka7gqByexVKUPJnSU6B{~0Cjwf`aTo+fuBX+ zz(1mY&?N>2!(vddl^7E2D24{RiDAKkVt8=47!e#NMg|MTsNiHVI(VuW6PzW+21~`b z;CwMYxL8aGF2(YB;-ugTQ4qXL6b9FciNOt6zFtfU-X7g`H9BM7j2z3;Z zP@b3*%13&jCF*8&uP7Rfb`Jp;d9y&)~hRV=?HmWDnRXNSHP%R)bi zb3(sj`46!$4C36dB0^hMyBRgkKjog+CCtgufEEhW`|Ira8o2X=&pAwD#hGv|O<@t+&{g)?YlB zcD#5fZMfK;Rw&|WGsKRxsMwiyrr4EMhrF}I?zH8iA#H_tIBl(XB<*VPXxa_pv9z0! zzFX``+a~s=?GpRa_K3&R9!L6V@kH7olzmZuJel^U*q`>kIFR<4IGFY&(m#l&(tbw% zZ>aB2?DvS+nhxTbbVWRy?iGj91LC>#7UFPvC-HoGH}OJxPo(>b7t@D`m(s_Hm(wSS zSJI~0gS^)4vyAr2iql%y5dYGD70( zjJD#NjP_XWBEHS&BfiV%FFwf_EWXbeD}Kl*6hCIn5IFaFH9Mf{ak+cWu7egGb2(Uvswyf zo-2himm`0T6wbT?W!6b)nHwaQd7U_td4rUh`J$AieXVq>{+W^fjgoXnxCi%t^8f?q zb3q3WBE{v6fq^`PlyJ55?c!miB=qQv1X=)J!qH z(4vpleC8KgKHi>pus(+yYkZg0(d@p?=srkaw!@558d)GScOwgq!`^e4Tk6a_QWqA$ zJ4eC-kIjOhX+bdAf(eENolFZZ!lq`Vt+T#@{VNz?GNgYg+IwYHPnqks$rb%xgn@lRreF$dnr|%(Qb{vYYV}o)V z;EWkNAhI3iAal+hIAa@>#Gy1dHxAJ-%x!?O89{z(5H8;V^GISR#J0oioh*!n`NY6~ z7Q~^v(V%9sS>~WRGZzkjYCH={6L3H$v93}98z)U0smL7UY}+79 z%|Vvh2I*o_u>Uk;n4QgG)*5pkppVy~qLE2XY?kcjQAF#WT~11MRjJg?L3Jhn zrY^wgZ`~Q{W+hf;_x%`^-S@Cz=$md2H2NI%BV45)GnIX6IwN`gb<;k&C*B9VyYYpj zV4z}GJ&v)f*RZSCv8y+awJU}97QB;KUO^hQtN?Z(!&HFNb>x6s6o7q zWx#Z;p20K&4=`{S14}w)?-}?l1D{~v;|<);z`YIJ-M~2pHvW@xtgViC0jn2x4$Bg4 z*|!o$+!Zm7Ky*OtLVTR$mx9Bxq%17Alt79~^Q5^fi{GUlkB;AsW7)#*;rANUgZ$qA z2T)4`1PTBE00;m?SlqXuIs)+l14LNdx0E~rUIzn2SlqYuLjt`54MbSnOautQylnyi z0Cksv$N>|V6bl0sx8_CycLD=LSlqW@Ndn0N4MbSnOy3zaPdys|00);gOadN%ISXJ^ z)v+^YckkWZ+$1;2ZjvPle@i|kcA~1cN4%5ii+YF{418K z#a3F&vj`-hD2=v7Yg^k|tG2b(R@++j^<%5;^T(Sx_wFZ~h0>6mGiPSboH=vm%$d2o z_{CEv0APlA!~yO21UHAcIjrJ;5hqx2fCqyN9kt^z?w@4LQw$yF=4mGie8zz)o?yav zxEXSw4WDJ`IVUyWW$1g{e4m?>+&s^O7a011iZ4206#kGgKT`3>D!!z6mka^_IAJvY zM8%&vVLT2n!_OFcnVX-h_=<|ZP`r+DpDwGLlCOBzZI^Q#Fb!XILNUI7#?b2w{ZhqW zIce|{2Q74%SN$~$dxN3haPwOyzKL%!?sq)=JwtEv;_oo@2X6kz&7V|!SMdUv3wiO+ z%=8{Z?>njafSLZ6?eZ5V{uTem&EK8)A^w92|K#Q)Uf^RVoWy@I^lxtdkDE`J`l%C& z@H2)!Ps1Fj{q@Dl8;R*d4+loZO_* z{)I+TMLLUq+ex?#ZZa9Cv&bw}WZOlK6N19Ulif~{EApHoUw9m1lyEvlfhc6gBBqX3 zhGK`)F2*>;STT;9@jRTMiizBxXn_@a(QQ{P(qKxH#Om@)HQ+WL`%siEw za^^din`u0(;AT2EGq{<_%`9%t<7PHDbC|i3n<^g8CHsqc49#a;p5mQ7ulJGHobwd# zdFfC320q`Wc#A$>vF**80mVD{s=qw?rHEr1bwzvm=S4qOyi@M`^`z^r+@}mRRGk0aPoABm48<@p=9rx5 z5<}+dsyLr~MtBwP^upqgp4)wq;;p;%{p&{`YgN4S4S!UByv!jIBKTy0~g_r+s;o~mFyLQMVb-!(rHtsb^8@wi|Cpx`%8VN4`Sn*!E zOWK(*Z<(ZUR8HjYCQpB}$Pzrrw}G zvLqA<7?_Ex8aunodm{n*>-GnO}~Z6o9dgFwISrL zYTV%4>?;rYh^w~S7xs1b`NPDcHZO0gsc$6~v8sW8bg8bZYpria8_!h$7Z$#F83p3C#Vu*$`1OwmiGjD`#U$r<+}*k6zB;=dILQP z%VzW&jE(*-L!!PZ$`nK827PP&!RVa!Kwq~sD@_h0nRi@t6Pvb1I?I=k+=;_afV9i( z>EE<})*o(J*Jd0A0+O+8fu1h^RIxG9Sy2Abl%~K3XG?{pUqz{s9 zMWAcAS=#!-WJjLp@9~j=h>R=gbh_ed7midrQR9plYkfEzqV?<%e~=I?%HA6c^|jJ~ zENm?5+tOFg2&ogz&RXy9OLoHv#U*E9DQj(isEc-$*+_@cEVsIhH^AEqb^3xA`oaMo zn@DS4cOb&FWWlUMWTXxgi~pkvB^Q!yH~WJ9B;HQjs5Z=ODJ~&HD|5+F`sO1P3>Q@6 zi};rWeSQ9_2A+=rvh~_14k7O}%;ei`eZJ0(O}<{aA$s~K8=yN*>(<1ldy*`dC_p8D zR>NaU;#^7BsV+d?6`{?=Zi|y=MO`tkxMbBZ`38m9kPf>jNobdUbD+~-UMD-^v4s6` z$L;S61k0<#Vc%tqfk+=wbBCYWWxdgpD@!$DZYnkAS5Y>kiiLE{q;+ekk2c;Fzs!q@ z&mxGN&N9OT4Q*u|9eS9Tkg}03CthZMxU->6eBC+4sgymtg%l$q^Yuw-cMq*s7xryg z9*a})b+hT1V|Px9r3nS*grGLC`B zG|BM=W}e*{j8Hp`WX7d9S;1P0gB;%Uk=z>7<9gY7Xn>Q>+VL&DA@caFK%~uo2)S*s zphgCv2$>#;EDEge4pO`~LLCP(BTCyCB$O+90K+4#En<+}#UrU46XcbP#(7$-mO=!f zn$2*|d6QMyHCbi9uBlMCy{lxsy#0-Frq~Xgx)_ zI3g|LkC{dli;Sz+ocxBdacV<heQ26U4{wdv;`qHXjbC-jH)us+t6juT~YSojypTWVa4Sv4EuV! z1D%nol_`AJ+UMU&f^j{moMH-DhZ&4LCcKg{m!zonF71mWeJI>T8J)3z{WzjM(AC#% z9C?GWf!1gq6u$)d$>{jrtZXub1;rz^tEj6=^=_|Rx$-pc3_G3Z?dN6_d54)lnFkn4 zo{X_O<$5%W^@;h8!Xv&f8KilTl+SDz4MS4spFIZcqj3 zb|a}JZXzww#g@Gu34OCBZV|U?;x@5M!##K_1(n!3SolJLFaE1GzaHxeeQc!&@2cHABH+2KWyCLR`F)i9gfhoF53W6qG4@?}Z7 zUh++xhA`^%4`p2D>52n-YLhGH7kPU2R3gMt6VTms+6Pk(18Q_TX zkZ(xt$ok8unE0)Z${I7GkV!VOt+=j^XK|uh+fB;SM1-*kbw7|Bf33VkDbrd0l+Z~x)7*|0%_WV}&e_wx+is-EX%FJ6sBzQ1$q{QeVa(QLe-Toypcb|R<~YY`n}9{`N~l)O3JaG z)!|O!k!l)>s>~y?{1vBJ3R5G-5pzj@l~mEl+*T&hW=Q5LjlZv$H%NZ8YFWo#F)V&0 zen@mvoErK06vjb23IOmxJ}0vT<#YZkd&+ucpK11#K+B$BPh9I1YgzT`beSouo{6f-;V%C@MAP83Hg5 ztn?4yn$qK7?KldyL!cB^41$_}Z69Q*&cdmKkTwX~QAjU61R10;b(tpyK&L)y0J2NV z1|g@kZ~!c&a_#`QO69x(a1)TrKwfF-Amk5#$1=Z&)YSJu&T$ykQCf5q3fgyAaQ~_I z*$x(|cqOo7Y=#N297ifg2s2&^X91>zJ9mRVM}wP+uBCcCW_m9{dEZ3spU!a40btYq0gm06zQ;g^PB z5-(|$OXiZB0o($1xE030ZBRmeIqa4yj3u*;0VgiT3nW*Ssf-<_V_M1wAZfGTO7PLNn5X+vil|I2;@c@jP}OdVs3-0C+Gb56 z|E?N@xgqN3?cBI4SgX;hsQ=f=CSg6MLWqSt3#8IK<&=XT}&uvLR|u(o(M-_LEPS>X$b&|pL9)~@FeK) z6y1m8Pz6uJ5;!hZoo^@+Q*|k>muFyuM(oA_ZNv!+af1w7I#lCE43aJKpb|F`pN%%t zgCTQEi_O4)Kh_M}GF;Q977oH9iq^-VVGtG%!Uf4jdnv*CV`D+4H$kou>RcqN@d0pB z*R%&z>wd6W4#YyVA?xJ?SuR7Ci~|Z-GAv&9)k|ZJk@#X-l9hTj<%>yGe2U4<$@lM# zl#~0gKh<;Foc!FrMRxt&X`kCk^2Tk(Eh8R+Bj6f;gqGxuyp!S~K-`+r3hv~|@21?y zWhp1;B~Sh!<>bp_=bAWqN%G_mQ%=4DuN+~*f&o~PY{HMpg#S9N2}`62x8YSO6v<9H zOSGg^H5SE?ByD2}7i_1&!ZW{=(b)^C2BQ zP=cdi8WvDQD}jQU~QI^UR#&Iupl_ z`#mum-jiU%YEZv`BAJ7nf~nwO3(Ap-*QqdxGm}$Pp4eh|&Qxq)fKw9x4S7})v?Jwz z-P4mDuQY|@0e>SkCJQh73}JR1f|ZSjU=@4*AY3%{F~V(QRsfm46v?Yb6$$+W(aU#rQo6m+S|HrR>KVEl zvTrwdcl;M}SNs=pO�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 LINKnd4E6s22}IbI diff --git a/plugins/MjpegSource2.java b/plugins/MjpegSource2.java index a4f55f7..89ab9ef 100644 --- a/plugins/MjpegSource2.java +++ b/plugins/MjpegSource2.java @@ -35,9 +35,9 @@ public class MjpegSource2 extends SourceBase { super.doInitialize(); URL aux = new URL(url); stream = aux.openStream(); - // if (!stream.markSupported()) { + if (!stream.markSupported()) { stream = new BufferedInputStream(stream); - // } + } } Thread monitoredThread; @@ -102,7 +102,7 @@ public class MjpegSource2 extends SourceBase { if (endOfFrame >= 0) { stream.reset(); stream.skip(startOfFrame); - int length = endOfFrame - END_OF_FRAME.length; + int length = endOfFrame ;//- END_OF_FRAME.length ; byte[] data = new byte[length]; stream.read(data, 0, length); return data; diff --git a/plugins/PuckDetection.java b/plugins/PuckDetection.java deleted file mode 100644 index 8edf011..0000000 --- a/plugins/PuckDetection.java +++ /dev/null @@ -1,169 +0,0 @@ - -import ch.psi.pshell.device.DeviceBase; -import ch.psi.utils.Arr; -import ch.psi.utils.Chrono; -import ch.psi.utils.State; -import java.io.IOException; -import java.util.ArrayList; -import java.util.logging.Level; - - -public class PuckDetection extends DeviceBase{ - public static final int PUCKS_NUMBER = 30; - final String server; - public volatile Chrono chrono; - - public PuckDetection(String name, String server){ - super(name); - this.server = server.startsWith("tcp://") ? server : "tcp://" + server; - } - - - public static class PuckState{ - public boolean online; - public boolean mecSwitch; - public boolean indSwitch; - - void clear(){ - online = false; - mecSwitch = false; - indSwitch = false; - } - void set(boolean mecSwitch, boolean indSwitch){ - online = true; - this.mecSwitch = mecSwitch; - this.indSwitch = indSwitch; - } - - @Override - public String toString(){ - return "Online = " + online + "\ns1 = " + mecSwitch+ "\ns2 = " + indSwitch; - } - } - - PuckState[] pucks; - public PuckState[] getPucks(){ - return pucks; - } - - //From 1 to PUCKS_NUMBER - public PuckState getPuck(int id) throws Exception{ - assertInitialized(); - if ((id<=0) || (id>PUCKS_NUMBER)){ - throw new Exception("invalid puck id: "+ id); - } - return pucks[id-1]; - } - - - Thread thread; - Thread watchDog; - - @Override - protected void doInitialize() throws IOException, InterruptedException{ - doClose(); - super.doInitialize(); - pucks = new PuckState[PUCKS_NUMBER]; - for (int i=0; i present = new ArrayList<>(); - for (String line:msg.split("\t")){ - try{ - line = line.trim(); - String[] tokens = line.split(" "); - int id = Integer.valueOf(tokens[0].substring(1)); - present.add(id); - PuckState puck = getPuck(id); - if (tokens.length<3){ - puck.clear(); - } else { - puck.set(tokens[1].trim().equals("1"),tokens[2].trim().equals("1")); - } - } catch (Exception ex){ - getLogger().log(Level.INFO, null, ex); - } - } - for (int i=1; i<= PUCKS_NUMBER; i++){ - if (!Arr.containsEqual(present.toArray(), i)){ - pucks[i-1].clear(); - } - } - } - - @Override - protected void doClose(){ - if (watchDog!=null){ - watchDog.interrupt(); - watchDog = null; - } - if (thread!=null){ - thread.interrupt(); - thread = null; - } - } -} diff --git a/plugins/PuckDetectionPanel.form b/plugins/PuckDetectionPanel.form new file mode 100644 index 0000000..9e5eb14 --- /dev/null +++ b/plugins/PuckDetectionPanel.form @@ -0,0 +1,184 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> + <Title/> + <Editor/> + <Renderer/> + </Column> + </TableColumnModel> + </Property> + <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> + <TableHeader reorderingAllowed="true" resizingAllowed="true"/> + </Property> + </Properties> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="puck_detection"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/PuckDetectionPanel.java b/plugins/PuckDetectionPanel.java new file mode 100644 index 0000000..f17059a --- /dev/null +++ b/plugins/PuckDetectionPanel.java @@ -0,0 +1,250 @@ +import ch.psi.mxsc.Puck; +import ch.psi.mxsc.PuckDetection; +import ch.psi.mxsc.PuckState; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import ch.psi.utils.swing.SwingUtils; + +/** + * + */ +public class PuckDetectionPanel extends DevicePanel { + + public PuckDetectionPanel() { + initComponents(); + int row = 0; + for (String segment : new String[]{"A", "B", "C", "D", "E", "F"}){ + for (int puck=1; puck<=5; puck++){ + table.getModel().setValueAt(segment+puck, row++, 0); + } + } + } + + @Override + public PuckDetection getDevice(){ + return (PuckDetection) super.getDevice(); + } + + + @Override + protected void onDeviceCacheChanged(Object value, Object former, long timestamp, boolean arg3) { + for (int row=0; row< 30; row++){ + String name = table.getModel().getValueAt(row, 0).toString(); + //int id = row+1; + try { + Puck puck = getDevice().getPuck(name); + int id = puck.getIndex() + 1; + PuckState state = getDevice().getPuckState(id); + table.getModel().setValueAt(state.online, row, 1); + table.getModel().setValueAt(state.mecSwitch, row, 2); + table.getModel().setValueAt(state.indSwitch, row, 3); + table.getModel().setValueAt(puck.getDetection() == null ? "" : puck.getDetection(), row, 4); + table.getModel().setValueAt(puck.getImageDetection() == null ? "" : puck.getImageDetection(), row, 5); + } catch (Exception ex) { + ex.printStackTrace(); + table.getModel().setValueAt(false, row, 1); + table.getModel().setValueAt(false, row, 2); + table.getModel().setValueAt(false, row, 3); + table.getModel().setValueAt("", row, 4); + table.getModel().setValueAt("", row, 5); + } + } + } + + void execute(String statement, boolean showReturn){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (ex != null){ + showException((Exception)ex); + } else if (showReturn){ + SwingUtils.showMessage(this, "Return", String.valueOf(ret)); + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + jPanel3 = new javax.swing.JPanel(); + buttonPuckDetCheck = new javax.swing.JButton(); + buttonPuckDetStop = new javax.swing.JButton(); + buttonPuckDetStart = new javax.swing.JButton(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + table = new javax.swing.JTable(); + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Raspberry Pi ")); + + buttonPuckDetCheck.setText("Ckeck"); + buttonPuckDetCheck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetCheckActionPerformed(evt); + } + }); + + buttonPuckDetStop.setText("Stop"); + buttonPuckDetStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStopActionPerformed(evt); + } + }); + + buttonPuckDetStart.setText("Start"); + buttonPuckDetStart.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPuckDetStartActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(buttonPuckDetCheck) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 107, Short.MAX_VALUE) + .addComponent(buttonPuckDetStop) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 108, Short.MAX_VALUE) + .addComponent(buttonPuckDetStart) + .addContainerGap()) + ); + + jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonPuckDetCheck, buttonPuckDetStart, buttonPuckDetStop}); + + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonPuckDetCheck) + .addComponent(buttonPuckDetStop) + .addComponent(buttonPuckDetStart)) + .addContainerGap()) + ); + + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Detection")); + + table.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null}, + {null, null, null, null, null, null} + }, + new String [] { + "Puck", "Online", "Mechanical", "Inductive", "Detection", "Image" + } + ) { + Class[] types = new Class [] { + java.lang.String.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class + }; + boolean[] canEdit = new boolean [] { + false, false, false, false, false, false + }; + + public Class getColumnClass(int columnIndex) { + return types [columnIndex]; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return canEdit [columnIndex]; + } + }); + jScrollPane1.setViewportView(table); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addContainerGap()) + ); + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) + .addContainerGap()) + ); + + deviceStatePanel1.setDeviceName("puck_detection"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonPuckDetCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetCheckActionPerformed + execute("check_puck_detection()", true); + }//GEN-LAST:event_buttonPuckDetCheckActionPerformed + + private void buttonPuckDetStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStopActionPerformed + execute("stop_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStopActionPerformed + + private void buttonPuckDetStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPuckDetStartActionPerformed + execute("start_puck_detection()", false); + }//GEN-LAST:event_buttonPuckDetStartActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonPuckDetCheck; + private javax.swing.JButton buttonPuckDetStart; + private javax.swing.JButton buttonPuckDetStop; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTable table; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/RobotPanel.form b/plugins/RobotPanel.form index db2bf43..e223812 100644 --- a/plugins/RobotPanel.form +++ b/plugins/RobotPanel.form @@ -20,6 +20,7 @@ <Component id="jPanel2" alignment="0" max="32767" attributes="0"/> <Component id="jPanel3" alignment="0" max="32767" attributes="0"/> <Component id="panelState" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel4" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> @@ -27,6 +28,8 @@ <Group type="102" alignment="0" attributes="0"> <Component id="jPanel1" min="-2" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="jPanel4" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> <Component id="jPanel2" min="-2" max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/> <Component id="jPanel3" min="-2" max="-2" attributes="0"/> @@ -446,5 +449,103 @@ </Container> <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="panelState"> </Component> + <Container class="javax.swing.JPanel" name="jPanel4"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Tool"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jLabel5" min="-2" pref="52" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="ledOpen" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="4" max="-2" attributes="0"/> + <Group type="103" groupAlignment="2" attributes="0"> + <Component id="jLabel5" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="ledOpen" alignment="2" min="-2" max="-2" attributes="0"/> + <Component id="panelPowerCtr1" alignment="2" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.Led" name="ledOpen"> + <Properties> + <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> + <Font name="SansSerif" size="18" style="0"/> + </Property> + </Properties> + </Component> + <Component class="javax.swing.JLabel" name="jLabel5"> + <Properties> + <Property name="horizontalAlignment" type="int" value="11"/> + <Property name="text" type="java.lang.String" value="Open:"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelPowerCtr1"> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="buttonOpen" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace pref="18" max="32767" attributes="0"/> + <Component id="buttonClose" linkSize="3" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Group type="103" alignment="2" groupAlignment="1" max="-2" attributes="0"> + <Component id="buttonClose" alignment="1" max="32767" attributes="0"/> + <Component id="buttonOpen" alignment="1" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonClose"> + <Properties> + <Property name="text" type="java.lang.String" value=" Close "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonCloseActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonOpen"> + <Properties> + <Property name="text" type="java.lang.String" value=" Open "/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonOpenActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + </SubComponents> + </Container> </SubComponents> </Form> diff --git a/plugins/RobotPanel.java b/plugins/RobotPanel.java index edbd65a..a520adc 100644 --- a/plugins/RobotPanel.java +++ b/plugins/RobotPanel.java @@ -5,7 +5,6 @@ import ch.psi.pshell.swing.DevicePanel; import ch.psi.pshell.core.Context; import ch.psi.utils.State; import java.awt.Color; -import java.lang.reflect.Method; import java.util.Map; /** @@ -52,6 +51,7 @@ public class RobotPanel extends DevicePanel { Boolean empty = null; Boolean settled = null; Boolean moving = null; + Boolean open = null; Integer speed = null; String task = null; String mode = null; @@ -70,6 +70,10 @@ public class RobotPanel extends DevicePanel { settled = (Boolean) status.get("settled"); } catch (Exception ex) { } + try { + open = (Boolean) status.get("open"); + } catch (Exception ex) { + } try { speed = (Integer) status.get("speed"); } catch (Exception ex) { @@ -109,6 +113,7 @@ public class RobotPanel extends DevicePanel { ledPowered.setColor((powered == null) ? Color.GRAY : (powered ? Color.YELLOW : Color.DARK_GRAY)); ledEmpty.setColor((empty == null) ? Color.GRAY : (empty ? Color.GREEN : Color.YELLOW)); ledSettled.setColor((settled == null) ? Color.GRAY : (settled ? Color.GREEN : Color.YELLOW)); + ledOpen.setColor((open == null) ? Color.GRAY : (open ? Color.GREEN : Color.DARK_GRAY)); ledMoving.setColor((moving == null) ? Color.GRAY : (moving ? Color.YELLOW : Color.DARK_GRAY)); textTask.setText((task == null) ? "" : task); ledTask.setColor((task == null) ? Color.GRAY : (task.isEmpty() ? Color.DARK_GRAY : Color.YELLOW)); @@ -164,6 +169,12 @@ public class RobotPanel extends DevicePanel { ledTask = new ch.psi.pshell.swing.Led(); ledMode = new ch.psi.pshell.swing.Led(); panelState = new ch.psi.pshell.swing.DeviceStatePanel(); + jPanel4 = new javax.swing.JPanel(); + ledOpen = new ch.psi.pshell.swing.Led(); + jLabel5 = new javax.swing.JLabel(); + panelPowerCtr1 = new javax.swing.JPanel(); + buttonClose = new javax.swing.JButton(); + buttonOpen = new javax.swing.JButton(); jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Power")); @@ -428,6 +439,74 @@ public class RobotPanel extends DevicePanel { .addGap(2, 2, 2)) ); + jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Tool")); + + ledOpen.setFont(new java.awt.Font("SansSerif", 0, 18)); // NOI18N + + jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel5.setText("Open:"); + + buttonClose.setText(" Close "); + buttonClose.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCloseActionPerformed(evt); + } + }); + + buttonOpen.setText(" Open "); + buttonOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonOpenActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelPowerCtr1Layout = new javax.swing.GroupLayout(panelPowerCtr1); + panelPowerCtr1.setLayout(panelPowerCtr1Layout); + panelPowerCtr1Layout.setHorizontalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(buttonOpen) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE) + .addComponent(buttonClose)) + ); + + panelPowerCtr1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonClose, buttonOpen}); + + panelPowerCtr1Layout.setVerticalGroup( + panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelPowerCtr1Layout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelPowerCtr1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(buttonClose, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonOpen)) + .addGap(0, 0, 0)) + ); + + javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); + jPanel4.setLayout(jPanel4Layout); + jPanel4Layout.setHorizontalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + jPanel4Layout.setVerticalGroup( + jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel4Layout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) + .addComponent(jLabel5) + .addComponent(ledOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(panelPowerCtr1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(2, 2, 2)) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -436,12 +515,15 @@ public class RobotPanel extends DevicePanel { .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(panelState, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) + .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -509,32 +591,54 @@ public class RobotPanel extends DevicePanel { } }//GEN-LAST:event_buttonAbortActionPerformed + private void buttonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCloseActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".close_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonCloseActionPerformed + + private void buttonOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOpenActionPerformed + try{ + Context.getInstance().evalLineBackground(getDevice().getName() + ".open_tool()"); + } catch (Exception ex){ + this.showException(ex); + } + }//GEN-LAST:event_buttonOpenActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton butonStop; private javax.swing.JButton buttonAbort; + private javax.swing.JButton buttonClose; private javax.swing.JButton buttonDisable; private javax.swing.JButton buttonEnable; + private javax.swing.JButton buttonOpen; private javax.swing.JButton buttonPause; private javax.swing.JButton buttonResume; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; + private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; private javax.swing.JLabel jLabel8; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; private ch.psi.pshell.swing.Led ledEmpty; private ch.psi.pshell.swing.Led ledMode; private ch.psi.pshell.swing.Led ledMoving; + private ch.psi.pshell.swing.Led ledOpen; private ch.psi.pshell.swing.Led ledPowered; private ch.psi.pshell.swing.Led ledSettled; private ch.psi.pshell.swing.Led ledTask; private javax.swing.JPanel panelMotionCtr; private javax.swing.JPanel panelPowerCtr; + private javax.swing.JPanel panelPowerCtr1; private ch.psi.pshell.swing.DeviceStatePanel panelState; private javax.swing.JSpinner spinnerSpeed; private javax.swing.JTextField textMode; diff --git a/plugins/WagoPanel.form b/plugins/WagoPanel.form new file mode 100644 index 0000000..9864ffa --- /dev/null +++ b/plugins/WagoPanel.form @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> + <AuxValues> + <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> + <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> + <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> + <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> + <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> + </AuxValues> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Component id="deviceStatePanel1" max="32767" attributes="0"/> + <Component id="panelSafety" max="32767" attributes="0"/> + <Component id="panelRobot1" max="32767" attributes="0"/> + <Component id="panelDewar" alignment="0" max="32767" attributes="0"/> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="panelSafety" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelDewar" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="panelRobot1" min="-2" max="-2" attributes="0"/> + <EmptySpace min="0" pref="0" max="-2" attributes="0"/> + <Component id="deviceStatePanel1" min="-2" max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="ch.psi.pshell.swing.DeviceStatePanel" name="deviceStatePanel1"> + <Properties> + <Property name="deviceName" type="java.lang.String" value="wago"/> + </Properties> + </Component> + <Container class="javax.swing.JPanel" name="panelSafety"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Safety"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonReleasePsys" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonReleaseLocal" linkSize="2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonReleaseLocal" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonReleasePsys" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JButton" name="buttonReleasePsys"> + <Properties> + <Property name="text" type="java.lang.String" value="Release PSYS"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleasePsysActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JButton" name="buttonReleaseLocal"> + <Properties> + <Property name="text" type="java.lang.String" value="Release Local"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonReleaseLocalActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Container class="javax.swing.JPanel" name="panelRobot1"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder title="Dryer"/> + </Border> + </Property> + </Properties> + + <Layout> + <DimensionLayout dim="0"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="32767" attributes="0"/> + <Component id="buttonHeater" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace type="unrelated" max="-2" attributes="0"/> + <Component id="buttonStream" linkSize="3" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + <DimensionLayout dim="1"> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="3" attributes="0"> + <Component id="buttonHeater" alignment="3" min="-2" max="-2" attributes="0"/> + <Component id="buttonStream" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace max="-2" attributes="0"/> + </Group> + </Group> + </DimensionLayout> + </Layout> + <SubComponents> + <Component class="javax.swing.JToggleButton" name="buttonHeater"> + <Properties> + <Property name="text" type="java.lang.String" value="Heater"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonHeaterActionPerformed"/> + </Events> + </Component> + <Component class="javax.swing.JToggleButton" name="buttonStream"> + <Properties> + <Property name="text" type="java.lang.String" value="Air Stream"/> + </Properties> + <Events> + <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonStreamActionPerformed"/> + </Events> + </Component> + </SubComponents> + </Container> + <Component class="ch.psi.pshell.swing.ProcessVariablePanel" name="panelDewar"> + <Properties> + <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> + <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> + <TitledBorder justification="1" title="Dewar Light"/> + </Border> + </Property> + <Property name="deviceName" type="java.lang.String" value="led_level"/> + <Property name="showAdvanced" type="boolean" value="false"/> + <Property name="showButtons" type="boolean" value="false"/> + <Property name="showLimitButtons" type="boolean" value="false"/> + <Property name="showSlider" type="boolean" value="true"/> + <Property name="showStop" type="boolean" value="false"/> + </Properties> + </Component> + </SubComponents> +</Form> diff --git a/plugins/WagoPanel.java b/plugins/WagoPanel.java new file mode 100644 index 0000000..cacadcd --- /dev/null +++ b/plugins/WagoPanel.java @@ -0,0 +1,207 @@ +import ch.psi.mxsc.Controller; +import ch.psi.pshell.core.Context; +import ch.psi.pshell.swing.DevicePanel; +import java.util.concurrent.CompletableFuture; +import javax.swing.border.TitledBorder; + +/** + * + */ +public class WagoPanel extends DevicePanel { + + public WagoPanel() { + initComponents(); + this.startTimer(10000); + } + + + CompletableFuture future; + + @Override + public void onTimer(){ + if ((getDevice()!=null)){ + updateTitle(); + } + } + + void updateTitle(){ + Boolean roomTemp = (Controller.getInstance().isLedRoomTemp()); + if (roomTemp==null){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light"); + } else if (roomTemp==true){ + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (room temperature)"); + } else { + ((TitledBorder)panelDewar.getBorder()).setTitle("Dewar Light (LN2)"); + } + } + + + void execute(String statement){ + try { + Context.getInstance().evalLineBackgroundAsync(statement).handle((ret, ex) -> { + if (WagoPanel.this.isShowing()){ + if (ex != null){ + showException((Exception)ex); + } + } + return ret; + }); + } catch (Exception ex) { + showException(ex); + } + } + + @SuppressWarnings("unchecked") + // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents + private void initComponents() { + + deviceStatePanel1 = new ch.psi.pshell.swing.DeviceStatePanel(); + panelSafety = new javax.swing.JPanel(); + buttonReleasePsys = new javax.swing.JButton(); + buttonReleaseLocal = new javax.swing.JButton(); + panelRobot1 = new javax.swing.JPanel(); + buttonHeater = new javax.swing.JToggleButton(); + buttonStream = new javax.swing.JToggleButton(); + panelDewar = new ch.psi.pshell.swing.ProcessVariablePanel(); + + deviceStatePanel1.setDeviceName("wago"); + + panelSafety.setBorder(javax.swing.BorderFactory.createTitledBorder("Safety")); + + buttonReleasePsys.setText("Release PSYS"); + buttonReleasePsys.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleasePsysActionPerformed(evt); + } + }); + + buttonReleaseLocal.setText("Release Local"); + buttonReleaseLocal.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonReleaseLocalActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelSafetyLayout = new javax.swing.GroupLayout(panelSafety); + panelSafety.setLayout(panelSafetyLayout); + panelSafetyLayout.setHorizontalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonReleasePsys) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonReleaseLocal) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelSafetyLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonReleaseLocal, buttonReleasePsys}); + + panelSafetyLayout.setVerticalGroup( + panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSafetyLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelSafetyLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonReleaseLocal) + .addComponent(buttonReleasePsys)) + .addContainerGap()) + ); + + panelRobot1.setBorder(javax.swing.BorderFactory.createTitledBorder("Dryer")); + + buttonHeater.setText("Heater"); + buttonHeater.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonHeaterActionPerformed(evt); + } + }); + + buttonStream.setText("Air Stream"); + buttonStream.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStreamActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelRobot1Layout = new javax.swing.GroupLayout(panelRobot1); + panelRobot1.setLayout(panelRobot1Layout); + panelRobot1Layout.setHorizontalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonHeater) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(buttonStream) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + panelRobot1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {buttonHeater, buttonStream}); + + panelRobot1Layout.setVerticalGroup( + panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelRobot1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(panelRobot1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonHeater) + .addComponent(buttonStream)) + .addContainerGap()) + ); + + panelDewar.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Dewar Light", javax.swing.border.TitledBorder.LEFT, javax.swing.border.TitledBorder.DEFAULT_POSITION)); + panelDewar.setDeviceName("led_level"); + panelDewar.setShowAdvanced(false); + panelDewar.setShowButtons(false); + panelDewar.setShowLimitButtons(false); + panelDewar.setShowSlider(true); + panelDewar.setShowStop(false); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSafety, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelRobot1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelDewar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(panelSafety, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelDewar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelRobot1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(deviceStatePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + }// </editor-fold>//GEN-END:initComponents + + private void buttonReleasePsysActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleasePsysActionPerformed + execute("release_psys()"); + }//GEN-LAST:event_buttonReleasePsysActionPerformed + + private void buttonReleaseLocalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonReleaseLocalActionPerformed + execute("release_local()"); + }//GEN-LAST:event_buttonReleaseLocalActionPerformed + + private void buttonHeaterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonHeaterActionPerformed + execute("set_heater(" + (buttonHeater.isSelected() ? "True": "False") + ")"); + }//GEN-LAST:event_buttonHeaterActionPerformed + + private void buttonStreamActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStreamActionPerformed + execute("set_air_stream(" + (buttonStream.isSelected()? "True": "False")+ ")"); + }//GEN-LAST:event_buttonStreamActionPerformed + + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton buttonHeater; + private javax.swing.JButton buttonReleaseLocal; + private javax.swing.JButton buttonReleasePsys; + private javax.swing.JToggleButton buttonStream; + private ch.psi.pshell.swing.DeviceStatePanel deviceStatePanel1; + private ch.psi.pshell.swing.ProcessVariablePanel panelDewar; + private javax.swing.JPanel panelRobot1; + private javax.swing.JPanel panelSafety; + // End of variables declaration//GEN-END:variables +} diff --git a/plugins/Wayne.form b/plugins/Wayne.form deleted file mode 100644 index f6456c5..0000000 --- a/plugins/Wayne.form +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> - -<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> - <AuxValues> - <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> - <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> - <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> - <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> - <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> - </AuxValues> - - <Layout> - <DimensionLayout dim="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="18" max="-2" attributes="0"/> - <Component id="jButton1" min="-2" max="-2" attributes="0"/> - <EmptySpace pref="358" max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - <DimensionLayout dim="1"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="29" max="-2" attributes="0"/> - <Component id="jButton1" min="-2" max="-2" attributes="0"/> - <EmptySpace pref="85" max="32767" attributes="0"/> - </Group> - </Group> - </DimensionLayout> - </Layout> - <SubComponents> - <Component class="javax.swing.JButton" name="jButton1"> - <Properties> - <Property name="text" type="java.lang.String" value="jButton1"/> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/> - </Events> - </Component> - </SubComponents> -</Form> diff --git a/plugins/Wayne.java b/plugins/Wayne.java deleted file mode 100644 index 955c0e5..0000000 --- a/plugins/Wayne.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2014-2017 Paul Scherrer Institute. All rights reserved. - */ - -import ch.psi.pshell.ui.Panel; -import ch.psi.utils.State; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - */ -public class Wayne extends Panel { - - public Wayne() { - initComponents(); - } - - //Overridable callbacks - @Override - public void onInitialize(int runCount) { - - } - - @Override - public void onStateChange(State state, State former) { - - } - - @Override - public void onExecutedFile(String fileName, Object result) { - } - - - //Callback to perform update - in event thread - @Override - protected void doUpdate() { - } - - @SuppressWarnings("unchecked") - // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents - private void initComponents() { - - jButton1 = new javax.swing.JButton(); - - jButton1.setText("jButton1"); - jButton1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jButton1ActionPerformed(evt); - } - }); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(18, 18, 18) - .addComponent(jButton1) - .addContainerGap(358, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(29, 29, 29) - .addComponent(jButton1) - .addContainerGap(85, Short.MAX_VALUE)) - ); - }// </editor-fold>//GEN-END:initComponents - - private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - try { - this.runAsync("test/RobotCartesianScan"); - } catch (Exception ex) { - Logger.getLogger(Wayne.class.getName()).log(Level.SEVERE, null, ex); - } - }//GEN-LAST:event_jButton1ActionPerformed - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton jButton1; - // End of variables declaration//GEN-END:variables -} diff --git a/script/devices/RobotTCP.py b/script/devices/RobotTCP.py index 05c533c..662a2b5 100644 --- a/script/devices/RobotTCP.py +++ b/script/devices/RobotTCP.py @@ -40,6 +40,7 @@ class RobotTCP(TcpDevice, Stoppable): self.joint_motors = [] self.tool = None self.default_desc = None + self.tool_open = None #self.tool_trsf = [0.0] * 6 self.frame = FRAME_DEFAULT self.polling_interval = 0.01 @@ -52,7 +53,7 @@ class RobotTCP(TcpDevice, Stoppable): def doInitialize(self): super(RobotTCP, self).doInitialize() - self.reset = True + self.reset = True def set_tool(self, tool): self.tool = tool @@ -60,7 +61,8 @@ class RobotTCP(TcpDevice, Stoppable): self.evaluate("tcp_curtool=" + tool) if self.cartesian_motors_enabled: self.update() - self.set_motors_enabled(True) + self.set_motors_enabled(True) + self.is_tool_open() def get_tool(self): return self.tool @@ -395,18 +397,36 @@ class RobotTCP(TcpDevice, Stoppable): #self.waitState(State.Ready, -1) - #Tool - #This function can timeout since it synchronizes move. - #Better check state before otherwise it can freeze the communication + #Tool - synchronized as can freeze communication + """ + def open_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("open(" + tool + " )", timeout=timeout) + + def close_tool(self, tool=None, timeout=3000): + #This function can timeout since it synchronizes move. Checking state before otherwise it can freeze the communication. + self.waitState(State.Ready, -1) + if tool is None: tool = self.tool + return self.evaluate("close(" + tool + " )", timeout=timeout) + """ + #Tool - Not synchronized calls: atention to open/close only when state is Ready def open_tool(self, tool=None): if tool is None: tool = self.tool - return self.evaluate("open(" + tool + " )", timeout=3000) + self.evaluate(tool + ".gripper=true") + self.tool_open = True - #This function can timeout since it synchronizes move. Better check state before - #Better check state before otherwise it can freeze the communication def close_tool(self, tool=None): if tool is None: tool = self.tool - return self.evaluate("close(" + tool + " )", timeout=3000) + self.evaluate(tool + ".gripper=false") + self.tool_open = False + + def is_tool_open(self, tool=None): + if tool is None: tool = self.tool + self.tool_open = robot.eval_bool(tool + ".gripper") + return self.tool_open + #Arm position def herej(self): @@ -521,6 +541,7 @@ class RobotTCP(TcpDevice, Stoppable): self.speed = int(sts[3]) self.empty = sts[4] == "1" self.settled = sts[5] == "1" + #TODO: add tool open if cur_task is not None: if int(sts[6]) < 0: log("Task "+ str(cur_task) + " finished with code: " + str(sts[7]), False) @@ -547,7 +568,8 @@ class RobotTCP(TcpDevice, Stoppable): "settled": self.settled, "task": cur_task, "mode": self.working_mode, - "status": self.status + "status": self.status, + "open": self.tool_open }, None) if self.cartesian_motors_enabled: for m in self.cartesian_motors: diff --git a/script/local.py b/script/local.py index ca79cd3..e7b45da 100644 --- a/script/local.py +++ b/script/local.py @@ -4,6 +4,7 @@ import traceback from ch.psi.pshell.serial import TcpDevice from ch.psi.pshell.modbus import ModbusTCP +import ch.psi.mxsc.Controller as Controller run("setup/Layout") @@ -60,6 +61,16 @@ def system_check(robot_move=True): if not guiding_tool_park().read(): raise Exception("Guiding tool not parked") +def get_puck_elect_detection(segment, puck): + return str(Controller.getInstance().getPuck(str(segment).upper() + str(puck)).detection) + +def get_puck_img_detection(segment, puck): + return str(Controller.getInstance().getPuck(str(segment).upper() + str(puck)).imageDetection) + +def assert_puck_detected(segment, puck): + if get_puck_detection(segment, puck) != "Present": + raise Exception ("Puck " + str(segment).upper() + str(puck) + " not present") + def start_puck_detection(): run("tools/RestartPuckDetection") diff --git a/script/motion/get_dewar.py b/script/motion/get_dewar.py index 7555edf..b082cf6 100644 --- a/script/motion/get_dewar.py +++ b/script/motion/get_dewar.py @@ -5,6 +5,8 @@ def get_dewar(segment, puck, sample, force=False): #Initial checks assertValidAddress(segment, puck, sample) + assert_puck_detected(segment, puck) + robot.assert_no_task() robot.reset_motion() robot.wait_ready() diff --git a/script/motion/mount.py b/script/motion/mount.py index 14a5cda..815dce6 100644 --- a/script/motion/mount.py +++ b/script/motion/mount.py @@ -5,6 +5,8 @@ def mount(segment, puck, sample, force=False, read_dm=False): start = time.time() #Initial checks assertValidAddress(segment, puck, sample) + assert_puck_detected(segment, puck) + robot.assert_no_task() robot.reset_motion() robot.wait_ready() diff --git a/script/motion/put_dewar.py b/script/motion/put_dewar.py index 079411e..2f66fae 100644 --- a/script/motion/put_dewar.py +++ b/script/motion/put_dewar.py @@ -5,6 +5,8 @@ def put_dewar(segment, puck, sample, force=False): #Initial checks assertValidAddress(segment, puck, sample) + assert_puck_detected(segment, puck) + robot.assert_no_task() robot.reset_motion() robot.wait_ready() diff --git a/script/motion/recover.py b/script/motion/recover.py new file mode 100644 index 0000000..37e7d77 --- /dev/null +++ b/script/motion/recover.py @@ -0,0 +1,5 @@ +def recover(): + """ + """ + print "recover" + diff --git a/script/motion/robot_recover.py b/script/motion/robot_recover.py index 87e5d18..145e592 100644 --- a/script/motion/robot_recover.py +++ b/script/motion/robot_recover.py @@ -11,6 +11,4 @@ def robot_recover(): #Enabling enable_motion() - #barcode_reader.start_read(20.0) - robot.robot_recover() diff --git a/script/motion/unmount.py b/script/motion/unmount.py index 851ef30..d12f73f 100644 --- a/script/motion/unmount.py +++ b/script/motion/unmount.py @@ -5,6 +5,8 @@ def unmount(segment, puck, sample, force=False): #Initial checks assertValidAddress(segment, puck, sample) + assert_puck_detected(segment, puck) + robot.assert_no_task() robot.reset_motion() robot.wait_ready() diff --git a/script/test/TestBugPcAPI2.py b/script/test/TestBugPcAPI2.py index 037fbb0..0747cd0 100644 --- a/script/test/TestBugPcAPI2.py +++ b/script/test/TestBugPcAPI2.py @@ -1,6 +1,6 @@ import ch.psi.pshell.imaging.MjpegSource as MjpegSource MjpegSource2 = get_context().pluginManager.getDynamicClass("MjpegSource2") -add_device(MjpegSource2("gripper_cam", "http://129.129.110.114/axis-cgi/mjpg/video.cgi"), True) -gripper_cam.polling=100 -#gripper_cam.monitored = True +add_device(MjpegSource("gripper_cam", "http://129.129.110.114/axis-cgi/mjpg/video.cgi"), True) +#gripper_cam.polling=1000 +gripper_cam.monitored = True show_panel(gripper_cam) \ No newline at end of file