001package jmri.jmrix.openlcb.swing.idtool; 002 003import java.awt.event.*; 004import java.io.*; 005 006import javax.swing.*; 007import jmri.jmrix.can.CanSystemConnectionMemo; 008import jmri.util.swing.WrapLayout; 009 010import org.openlcb.*; 011import org.openlcb.implementations.*; 012import org.openlcb.swing.*; 013 014 015/** 016 * Pane for identifying a physical node by 017 * doing memory operations (hence lighting its activity lights) 018 * until cancelled. 019 * 020 * @author Bob Jacobsen Copyright (C) 2024 021 * @since 5.7.4 022 */ 023public class IdToolPane extends jmri.util.swing.JmriPanel 024 implements jmri.jmrix.can.swing.CanPanelInterface { 025 026 protected CanSystemConnectionMemo memo; 027 Connection connection; 028 NodeID nid; 029 030 MimicNodeStore store; 031 MemoryConfigurationService service; 032 NodeSelector nodeSelector; 033 034 public String getTitle(String menuTitle) { 035 return Bundle.getMessage("TitleIdTool"); 036 } 037 038 static final int CHUNKSIZE = 64; 039 040 JButton gb; 041 JButton cb; 042 boolean cancelled = false; 043 boolean running = false; 044 045 @Override 046 public void initComponents(CanSystemConnectionMemo memo) { 047 this.memo = memo; 048 this.connection = memo.get(Connection.class); 049 this.nid = memo.get(NodeID.class); 050 051 store = memo.get(MimicNodeStore.class); 052 EventTable stdEventTable = memo.get(OlcbInterface.class).getEventTable(); 053 if (stdEventTable == null) { 054 log.error("no OLCB EventTable found"); 055 return; 056 } 057 service = memo.get(MemoryConfigurationService.class); 058 059 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 060 061 // Add to GUI here 062 var ns = new JPanel(); 063 ns.setLayout(new WrapLayout()); 064 add(ns); 065 nodeSelector = new org.openlcb.swing.NodeSelector(store, Integer.MAX_VALUE); 066 ns.add(nodeSelector); 067 068 var bb = new JPanel(); 069 bb.setLayout(new WrapLayout()); 070 add(bb); 071 072 gb = new JButton(Bundle.getMessage("ButtonId")); 073 bb.add(gb); 074 gb.addActionListener(this::pushedGetButton); 075 076 cb = new JButton(Bundle.getMessage("ButtonCancel")); 077 bb.add(cb); 078 cb.addActionListener(this::pushedCancel); 079 080 setRunning(false); 081 } 082 083 public IdToolPane() { 084 } 085 086 @Override 087 public void dispose() { 088 // and complete this 089 super.dispose(); 090 } 091 092 @Override 093 public String getHelpTarget() { 094 return "package.jmri.jmrix.openlcb.swing.idtool.IdToolPane"; 095 } 096 097 @Override 098 public String getTitle() { 099 if (memo != null) { 100 return (memo.getUserName() + " ID Tool"); 101 } 102 return getTitle(Bundle.getMessage("TitleIdTool")); 103 } 104 105 void pushedCancel(ActionEvent e) { 106 if (running) { 107 cancelled = true; 108 } 109 } 110 111 void setRunning(boolean t) { 112 if (t) { 113 gb.setEnabled(false); 114 cb.setEnabled(true); 115 } else { 116 gb.setEnabled(true); 117 cb.setEnabled(false); 118 } 119 running = t; 120 } 121 122 int space = 0xFF; 123 124 NodeID farID = new NodeID("0.0.0.0.0.0"); 125 126 static final int PERIOD = 250; // delay in milliseconds 127 128 MemoryConfigurationService.McsReadHandler cbr = 129 new MemoryConfigurationService.McsReadHandler() { 130 @Override 131 public void handleFailure(int errorCode) { 132 setRunning(false); 133 if (errorCode == 0x1082) { 134 log.debug("Stopping read due to 0x1082 status"); 135 } if (errorCode == 0x1081) { 136 log.error("Read failed. Address space not known"); 137 } else { 138 log.error("Read failed. Error code is {}", String.format("%04X", errorCode)); 139 } 140 } 141 142 @Override 143 public void handleReadData(NodeID dest, int readSpace, long readAddress, byte[] readData) { 144 log.trace("read succeed with {} bytes at {}", readData.length, readAddress); 145 // fire another from same address 146 if (!cancelled) { 147 // send after a delay 148 jmri.util.ThreadingUtil.runOnLayoutDelayed(() -> { 149 service.requestRead(farID, space, 0, 150 CHUNKSIZE, 151 cbr); 152 }, PERIOD); 153 } else { 154 setRunning(false); 155 cancelled = false; 156 log.debug("Complete"); 157 } 158 } 159 }; 160 161 162 /** 163 * Starts reading from node and writing to file process 164 * @param e not used 165 */ 166 void pushedGetButton(ActionEvent e) { 167 setRunning(true); 168 farID = nodeSelector.getSelectedNodeID(); 169 service.requestRead(farID, space, 0, CHUNKSIZE, cbr); // assume starting address is zero 170 } 171 172 byte[] bytes = new byte[CHUNKSIZE]; 173 int bytesRead; // Number bytes read into the bytes[] array from the file. Used for put operation only. 174 InputStream inputStream; 175 int address; 176 177 /** 178 * Nested class to create one of these using old-style defaults 179 */ 180 public static class Default extends jmri.jmrix.can.swing.CanNamedPaneAction { 181 182 public Default() { 183 super("Openlcb ID Tool", 184 new jmri.util.swing.sdi.JmriJFrameInterface(), 185 IdToolPane.class.getName(), 186 jmri.InstanceManager.getDefault(jmri.jmrix.can.CanSystemConnectionMemo.class)); 187 } 188 } 189 190 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(IdToolPane.class); 191}