Made it connect/disconnect more correctly.
[FinalKeyGui.git] / src / fkgui / SerialWorker.java
1 package fkgui;
2
3 import java.awt.Menu;
4 import java.awt.MenuItem;
5 import java.util.List;
6
7 import jssc.SerialPort;
8 import jssc.SerialPortEvent;
9 import jssc.SerialPortEventListener;
10 import jssc.SerialPortException;
11
12 import org.eclipse.swt.widgets.Display;
13
14
15 public class SerialWorker extends javax.swing.SwingWorker<Void, String> implements SerialPortEventListener {
16         public String dev;
17         public String pass;
18         private SerialPort serialPort;
19         SerialState state;
20         private ConsoleMsg delegate; 
21         
22         public enum SerialState { Connecting, Connected, Disconnected };
23
24
25         public SerialWorker(ConsoleMsg d) {
26                 delegate=d;
27                 state = SerialState.Disconnected;
28         }
29         
30         public void connect(String d, String p)
31         {
32                 dev=d;
33                 pass=p;
34                 
35                 serialPort = new SerialPort(dev);               
36
37                 state = SerialState.Connecting;
38                 postStateChange( state );
39                 
40                 execute();
41         }
42         
43         public void disconnect()
44         {
45                 if(serialPort != null && serialPort.isOpened() )
46                 {
47                         try {
48                                 serialPort.writeByte( (byte)'q'); //Machine commands with uppercase X
49                                 Thread.sleep(400);
50                                 serialPort.closePort();
51                         } catch (Exception e) {
52                                 // TODO Auto-generated catch block
53                                 e.printStackTrace();
54                         }
55                 }
56                 state = SerialState.Disconnected;
57                 postStateChange( SerialState.Disconnected);
58         }
59
60         public String expectString(String expect, int timeOut)
61         {
62                 
63                 //Read from port, and if not found within 2 seconds, exit with null
64                 String in=new String();
65                 int msLeft=timeOut;
66                 while(true)
67                 {
68                         try {
69                                 if( serialPort.getInputBufferBytesCount() > 0)
70                                 {
71                                         in += serialPort.readString(serialPort.getInputBufferBytesCount());
72                                         
73                                         if( in.contains(expect))
74                                         {
75                                                 return(in);
76                                         }
77                                 } else {
78                                         Thread.sleep(10);
79                                         if(timeOut>0)
80                                         {
81                                                 msLeft -=10;
82                                                 if( msLeft < 1)
83                                                 {
84                                                         break;
85                                                 }
86                                         }
87                                 }
88                         } catch (Exception e)
89                         {
90                                 //I don't care
91                         }
92                 }
93                 
94                 return( null );
95         }
96         
97         
98         @Override
99         protected Void doInBackground() throws Exception {
100                 publish("Trying to connect to "+dev);
101                 /**
102                  * Connection strategy:
103                  * Open the port, wait for "The Final Key" followed by # on next line, (getLoginHeader)
104                  *      * If not coming, press q and try once more.
105                  * When [Granted] record [Keyboard: and query full list with Xk
106                  * 
107                  */
108                 
109                 int numAccounts=0;
110                 try {
111                         System.out.println("Port opened: " + serialPort.openPort());
112                         System.out.println("Params setted: " + serialPort.setParams(9600, 8, 1, 0));
113
114                         int mask = SerialPort.MASK_BREAK + SerialPort.MASK_ERR + SerialPort.MASK_RLSD;
115                         serialPort.setEventsMask(mask);
116
117                         serialPort.addEventListener(this);
118                         String test = expectString("The Final Key", 1000);
119                         if( test != null )
120                         {
121                                 publish("Ready to log in, press button now.");
122                                 publish("Waiting for button press...");
123                         } else {
124                                 //Try logging out.
125                                 serialPort.writeByte( (byte)'q');
126                                 publish("State error, try again.");
127                                 disconnect();
128                                 return null;
129                         }
130                         
131                         if( expectString( "Pass:", 0 ) != null )
132                         {
133                                 publish("Logging in...");
134                         } else {
135                                 publish("Error: Did not get password prompt. Unplug and try again.");
136                                 disconnect();
137                                 return null;
138                         }
139
140                         enterString(pass);
141
142                         serialPort.writeByte( (byte)13 );
143                         pass = "";
144                         
145                         
146                         if( expectString( "[Granted]", 200 ) != null )
147                         {
148                                 publish("Access Granted.");
149                         } else {
150                                 publish("Error: Access Denied.");
151                                 disconnect();
152                                 return null;
153                         }
154
155                         publish("Getting account list...");
156                         serialPort.writeByte( (byte)'X'); //Machine commands with uppercase X
157                         expectString("[auto]", 200);
158                         serialPort.writeByte( (byte)'l'); //Full list 
159
160                         
161                         String accounts = new String();
162                         
163                         int timeOut = 10000;
164                         while(true)
165                         {
166                                 
167                                 if( serialPort.getInputBufferBytesCount() > 0 )
168                                 {
169                                         accounts += serialPort.readString();
170                                         String sub = accounts.substring( accounts.length()-3 );
171                                         if( sub.equals("\r\n>") )
172                                         {
173                                                 accounts = accounts.substring( 0, accounts.length()-3 );
174                                                 break;
175                                         }
176                                 } else {
177                                         Thread.sleep(10);
178                                         timeOut-=10;
179                                         if(timeOut < 1)
180                                         {
181                                                 publish("Error getting account list.");
182                                                 disconnect();
183                                                 return null;
184                                         }
185                                 }
186                         }
187                         
188                         //Trim first 3
189                         accounts = accounts.substring(3);
190
191                         String[] lines = accounts.split( "\r\n" );
192                         numAccounts=lines.length;
193                         for(String l:lines)
194                         {
195                                 String ac = l.substring(0,2);
196                                 String an = l.substring(2);
197                                 
198                                 //publish( "Account number: "+ac+" ["+an+"]");
199
200                                 Menu menu = new Menu(an+" ["+ac+"]");
201                                 MenuItem both = new MenuItem("User + Pass");
202                                 MenuItem usr = new MenuItem("User");
203                                 MenuItem psw = new MenuItem("Pass");
204                                 menu.add(both);
205                                 menu.add(usr);
206                                 menu.add(psw);
207
208                                 FireActionListener fal = new FireActionListener();
209                                 fal.action = "%";
210                                 fal.name = an;
211                                 fal.num = ac;
212                                 fal.port = serialPort;
213                                 both.addActionListener(fal);
214
215
216                                 fal = new FireActionListener();
217                                 fal.action = "p";
218                                 fal.name = an;
219                                 fal.num = ac;
220                                 fal.port = serialPort;
221                                 psw.addActionListener(fal);                     
222
223                                 fal = new FireActionListener();
224                                 fal.action = "u";
225                                 fal.name = an;
226                                 fal.num = ac;
227                                 fal.port = serialPort;
228                                 usr.addActionListener(fal);                     
229
230                                 delegate.getPopup().add(menu);
231                         }
232
233                 }
234                 catch (SerialPortException ex){
235                         System.out.println(ex);
236                 } catch (Exception e )
237                 {
238                         System.out.println("Other exception: "+e.getMessage() );
239                         e.printStackTrace();
240                 }
241
242                 if(numAccounts==1)
243                 {
244                         publish(numAccounts+" account.");
245                 } else {
246                         publish(numAccounts+" accounts ready.");
247                 }
248
249                 publish("Use the systray icon to trigger.");
250
251                 state = SerialState.Connected;
252                 postStateChange( state);
253                 
254                 return null;
255         }
256
257
258         private void enterString(String str) throws SerialPortException, InterruptedException {
259                 for(int i=0; i < str.length(); i++)
260                 {
261                         serialPort.writeByte( str.getBytes()[i] );
262                         Thread.sleep(20);
263                 }
264         }
265
266
267         private class MainWinMsg implements Runnable {
268                 private String msg;
269                 private ConsoleMsg delegate;
270                 MainWinMsg(ConsoleMsg d, String m)
271                 {
272                         delegate=d;
273                         msg=m;
274                 }
275                 public void run() {
276                         delegate.log(msg);
277                 }
278         }
279         
280         private class MainWinSerialChange implements Runnable  {
281                 private ConsoleMsg delegate;
282                 private SerialState state;
283                 private MainWinSerialChange(ConsoleMsg d, SerialState s )
284                 {
285                         delegate=d;
286                         state=s;
287                 }
288                 @Override
289                 public void run() {
290                         delegate.serialEvent(state);
291                 }
292         }
293
294         private void postStateChange(SerialState state)
295         {
296                 Display.getDefault().asyncExec( new MainWinSerialChange(delegate, state) );
297         }
298
299         @Override
300         protected void process(List<String> msgs) {
301                 for(String s : msgs)
302                 {
303                         
304                         Display.getDefault().asyncExec( new MainWinMsg(delegate, s) );
305                 }
306         }
307
308         @Override
309         public void serialEvent(SerialPortEvent event) {
310                 
311                 System.out.println("Event!" + event.getEventType() );
312
313                 if(event.isBREAK())
314                 {
315                         if(state!=SerialState.Disconnected)
316                         {
317                                 disconnect();
318                                 System.out.println(">>Break);");
319                         }
320                 }
321                 if(event.isERR())
322                 {
323                         if(state!=SerialState.Disconnected)
324                         {
325                                 disconnect();
326                                 System.out.println(">>Error");
327                         }
328                 }
329                 if(serialPort == null)
330                         System.out.println(">>Null");
331
332         }
333
334
335 }