8d95a4c71e030e13a7fd27a02d0d629a52be4edd
[FinalKeyGui.git] / src / fkgui / FkManager.java
1 package fkgui;
2
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ActionListener;
5 import java.io.File;
6 import java.io.FileOutputStream;
7 import java.nio.charset.StandardCharsets;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.Vector;
11
12 import jssc.SerialPort;
13
14 import org.eclipse.swt.widgets.Display;
15
16 import com.sun.corba.se.impl.ior.ByteBuffer;
17
18 import fkgui.FkActionEventListener.FkActionEvent;
19 import fkgui.FkActionEventListener.FkActionEventType;
20
21 public class FkManager implements ActionListener {
22         private static FkManager instance = null;
23         private SerialWorker com = null;
24         static final char ENTER_KEY = (char)13;
25         static final char PAUSE_CODE = (char)23; 
26         static final char SPACE_KEY = (char)32;
27         private Comparator<Account> sortMethod = null;
28         
29         public class Account
30         {
31                 public String name;
32                 public String num;
33                 private Boolean showNumInName;
34                 public Account( String acNum, String acName )
35                 {
36                         name = acName;
37                         num = acNum;
38                 }
39
40                 //Used by the ListView
41                 public String toString()
42                 {
43                         if( showNumInName )
44                         {
45                                 return( "["+num+"] "+name);
46                         }
47                         return(name);
48                 }
49
50                 public Account showNumInName(Boolean showAccountId) {
51                         showNumInName=showAccountId;
52                         return this;
53                 }
54         }
55                 
56         private Vector<Account> list;
57         private String banner = "Noname";
58         private String keyLayout = "USPC";
59         private Vector<String> supportedLayouts;
60         
61         protected FkManager()
62         {
63                 list = new Vector<Account>(256);
64                 supportedLayouts = new Vector<String>(4);
65         }
66         
67         public static FkManager getInstance()
68         {
69                 if( instance == null )
70                 {
71                         instance = new FkManager();
72                 }
73
74                 return( instance );
75         }
76         
77         public void setWorker( SerialWorker sw )
78         {
79                 com = sw;
80         }
81         
82
83         private class FkActionEventMsg implements Runnable  {
84                 private FkActionEventListener delegate;
85                 private FkActionEvent event;
86
87                 private FkActionEventMsg(FkActionEventListener d, FkActionEventType t, String data, Account acc, char act )
88                 {
89                         delegate=d;
90                         event=new FkActionEvent(t, data, acc,act) ;
91                 }
92                 @Override
93                 public void run() {
94                         if( delegate != null )
95                         {
96                                 delegate.fkActionEvent(event);
97                         }
98                 }
99         }
100         
101         
102         private Boolean checkState()
103         {
104                 int t=0;
105                 String msg="";
106                 Boolean stateOk=false;
107
108                 try {
109                         com.serialPort.writeByte((byte)SPACE_KEY);
110                         while( t < 100 )
111                         {
112                                 t++;
113                                 Thread.sleep(5);
114                                 
115                                 if( com.serialPort.getInputBufferBytesCount() > 0 )
116                                 {
117                                         msg += com.serialPort.readString();
118                                         if( msg.endsWith("\r\n>") )
119                                         {
120                                                 stateOk=true;
121                                                 msg="";
122                                                 break;
123                                         }
124                                 }
125                                 
126                         }
127                 
128                 } catch(Exception e)
129                 {
130                         stateOk=false;
131                 }
132                 flushSerial();
133                 if( !stateOk )
134                 {
135                         return(false);
136                 }
137                 return(true);
138                 
139         }
140         
141         private class TrigTask implements Runnable
142         {
143                 private Account acc;
144                 private char action;
145                 private FkActionEventListener delegate;
146
147                 public TrigTask(Account ac, char act, FkActionEventListener d )
148                 {
149                         acc=ac;
150                         action=act;
151                         delegate=d;
152                 }
153                 
154                 @Override
155                 public void run() {
156                         
157                         int t=0;
158                         String msg = "";
159
160
161                         try {
162                         
163                                 //First check that we get a prompt
164                                 if( !checkState() )
165                                 {
166                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.STATE_ERROR, "EXCEPTION",acc,action) );
167                                         return;
168                                 }
169
170                                 //Drain any previous input.
171                                 while( com.serialPort.getInputBufferBytesCount() > 0 )
172                                 {
173                                         com.serialPort.readBytes();
174                                 }
175                                 
176                                 //if it's not '%' we need to type which action.
177                                 if(action != '%' )
178                                 {
179         
180                                                 //If the action is to delete or override, we start by deleting the account number.
181                                                 //Those commands are xd or xo so we type an x before the action.
182                                                 if( action == 'd' || action == 'o' )
183                                                 {
184                                                         com.serialPort.writeByte((byte)'x');
185                                                 }
186                                                 com.serialPort.writeByte((byte)action);
187                                 }
188
189                                 com.serialPort.writeBytes(acc.num.toLowerCase().getBytes());
190                                 Thread.sleep(100);
191
192                                 //Verify that the device asks confirmation about the account number and action we requested, else return STATE_UNEXPECTED_ACTION_RESULT
193                                 //Wait until a ?\r\n is found
194                                 //Since we flushed the buffer, all we should see is an echo 
195                                 t=0;
196                                 while( t < 2 )
197                                 {
198                                         t++;
199                                         Thread.sleep(50);
200                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
201                                         {
202                                                 msg += com.serialPort.readString();
203
204                                                 if( msg.contains(" ?\r\n") )
205                                                 {
206                                                         System.out.println("Got '"+msg+"'");
207
208                                                         String expect;
209
210                                                         if(action=='d'||action=='o')
211                                                         {
212                                                                 expect = "x"+action+"%"+acc.num.toLowerCase();
213
214                                                                 if(action=='d')
215                                                                 {
216                                                                         expect += "\r\nDel "+acc.name+" [y/n] ?\r\n";
217                                                                 } else {
218                                                                         expect += "\r\nOverride "+acc.name+" [y/n] ?\r\n";
219                                                                 }
220                                                         } else if(action=='%')
221                                                         {
222                                                                 expect=acc.num.toLowerCase()+"\r\n\r\n[U][S][P] "+acc.name+" ?\r\n";
223                                                         } else {
224                                                                 expect=""+action+"%"+acc.num.toLowerCase();
225                                                                 String actStr = (""+action).toUpperCase();
226                                                                 if(actStr.compareTo("S")==0)
227                                                                 {
228                                                                         actStr="SHOW";
229                                                                 }
230                                                                 expect += "\r\n\r\n\r\n["+actStr+"] "+acc.name+" ?\r\n";
231                                                         }
232
233                                                         String cut = msg.substring(0, expect.length());
234
235                                                         if( cut.compareTo(expect ) != 0 )
236                                                         {
237                                                                 System.out.println("Expected: '"+expect+"' Got: '"+cut+"'");
238                                                                 msg="Error: unexpected reply, disconnect it and close this program, this indicates either hardware-error or another program trying to communicate with it.";
239                                                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.UNEXPECTED_ACTION_RESULT_ERROR, msg, acc, action) );
240                                                                 com.serialPort.writeByte((byte)9); //tab is unsupported in all inputs, should cause the device to go into a state where q will lock it.
241                                                                 com.serialPort.writeByte((byte)'q');
242                                                                 com.serialPort.closePort();
243                                                                 return;
244                                                         }
245                                                 }
246                                         }
247                                 }
248
249                                 if( action == 'd' || action == 'o' )
250                                 {
251                                         com.serialPort.writeByte((byte)'y');
252                                         Thread.sleep(100);
253                                 }
254
255                                 t=0;
256                                 int waitfor =  ((action=='o'||action=='d')?200:700);
257                                 while( t < waitfor )
258                                 {
259                                         t++;
260                                         Thread.sleep(50);
261                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
262                                         {
263                                                 msg += com.serialPort.readString();
264                                                 //System.out.println( msg );
265                                                 if( msg.contains("[done]") || msg.contains("[deleted]") )
266                                                 {
267                                                         if( action == 'd' )
268                                                         {
269                                                                 list.remove( acc );
270                                                         }
271                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_OKAY, msg, acc, action) );
272                                                         return;
273                                                 } else if( msg.contains("[abort]") )
274                                                 {
275                                                         //System.out.println("FkManager: Action Abort");;
276                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, msg,acc,action) );
277                                                         return;
278                                                 }
279                                         }
280                                 }
281                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, msg,acc,action) );
282
283                         } catch (Exception e1) {
284                                 System.out.println("TrigTask Exception:");
285                                 e1.printStackTrace();
286                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, "EXCEPTION",acc,action) );
287                         }
288                         
289                 }
290                 
291         }
292         
293         public void trig(Account acc, char action, FkActionEventListener delegate)
294         {
295                 TrigTask trigTask = new TrigTask(acc,action,delegate);
296                 new Thread(trigTask).start();
297         }
298         
299         
300         
301         private class SortByName implements Comparator<Account>
302         {
303                 @Override
304                 public int compare(Account o1, Account o2) {
305                         return o1.name.compareTo(o2.name);
306                 }
307         }
308         
309         private class SortById implements Comparator<Account>
310         {
311                 @Override
312                 public int compare(Account o1, Account o2) {
313                         int a = Integer.valueOf(o1.num, 16);
314                         int b = Integer.valueOf(o2.num, 16);
315                         return( a - b );
316                 }
317         }
318         
319         
320         
321         public void listAddAcc(String num, String name)
322         {
323                 list.addElement( new Account(num,name) );
324                 
325                 Collections.sort(list, sortMethod);
326         }
327         
328         public void listClear()
329         {
330                 list.clear();
331         }
332         
333         //Return the full list
334         public Vector<Account> getList()
335         {
336                 return(list);
337         }
338         
339         //Return a vector of accounts matching the keyword
340         public Vector<Account> getList(String key)
341         {
342                 Vector<Account> res = new Vector<Account>();
343                 String k = key.toLowerCase();
344                 for( Account a : list )
345                 {
346                         if( a.name.toLowerCase().contains( k ) ) 
347                         {
348                                 res.add(a);
349                         }
350                 }
351                 
352                 return(res);
353         }
354
355         public String[] getAvailableLayouts()
356         {
357                 String[] layouts = supportedLayouts.toArray(new String[supportedLayouts.size()]);
358                 return(layouts);
359         }
360         
361         public String addAvailableLayout( String str )
362         {
363                 //available formats are in order and of the form: '  N. Layout' so we cut
364                 //space space N dot and space.
365                 String l = str.substring(5);
366                 supportedLayouts.add(l);
367                 return(l);
368         }
369         
370
371
372         @Override
373         public void actionPerformed(ActionEvent e) {
374                 Account f=null;
375                 for( Account a : list )
376                 {
377                         if( a.num.compareTo( e.getActionCommand().substring(1, 3)) == 0 )
378                         {
379                                 f=a;
380                                 break;
381                         }
382                 }
383                 if(f!=null)
384                 {
385                         trig(f, e.getActionCommand().charAt(0), null);
386                 }
387         }
388
389         public void setCurrentLayout(String str) {
390                 System.out.println("FkManager: Got current layout:" + str );
391                 keyLayout =str;
392         }
393
394         public String getCurrentLayout()
395         {
396                 return( keyLayout );
397         }
398
399         private class NewAccountTask implements Runnable
400         {
401                 private String seq;
402                 private Account acc;
403                 FkActionEventListener delegate;
404                 public NewAccountTask(String sequence, FkActionEventListener d, String accountName)
405                 {
406                         seq=sequence;
407                         delegate=d;
408                         acc = new Account( "00", accountName );
409                         System.out.println("NewAccountTask ctor");
410                 }
411                 @Override
412                 public void run() {
413                         System.out.println("NewAccountTask run");
414                         Boolean noTimeOut = false;
415
416                         //First check that we get a prompt
417                         if( !checkState() )
418                         {
419                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.STATE_ERROR, "EXCEPTION",acc,'A') );
420                                 return;
421                         }
422                         
423                         String data="";
424                         int timeOut;
425                         try {                   
426                         //First type x a and wait for account title
427                                 
428                                 com.serialPort.writeByte((byte)'x');
429                                 com.serialPort.writeByte((byte)'a');
430                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WAITING, "WAITING",acc,'A') );
431
432                                 timeOut = 6000;
433                                 while(timeOut > 0)
434                                 {
435                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
436                                         {
437                                                 String in = com.serialPort.readString(); 
438                                                 data += in;
439                                                 System.out.println("Datain:" +in);
440                                                 if( data.contains("Account Title, (0-31):") )
441                                                 {
442                                                         System.out.println("Found");
443                                                         break;
444                                                 }
445                                         } else {
446                                                 timeOut -= 50;
447                                                 Thread.sleep(50);
448                                         }
449                                 }
450                                 
451                                 if(timeOut > 0 )
452                                 {
453                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WORKING, "WORKING",acc,'A') );
454
455                                         for(int p=0; p < seq.length();p++)
456                                         {
457
458                                                 if( com.serialPort.getOutputBufferBytesCount() > 1 )
459                                                 {
460                                                         Thread.sleep(100);
461                                                         System.out.println("[SLEEP]");
462                                                 } else {
463                                                         if( seq.charAt(p) == PAUSE_CODE)
464                                                         {
465                                                                 Thread.sleep(100);
466                                                                 System.out.println("[DELAY]");
467                                                         } else {
468                                                                 if( seq.charAt(p) == ENTER_KEY )
469                                                                 {
470                                                                         System.out.println( "[ENTER]" );
471                                                                 } else {
472                                                                         System.out.println( "Type from pos ("+p+"):" + seq.charAt(p));
473                                                                 }
474         
475                                                                 com.serialPort.writeByte( (byte)seq.charAt(p) );
476                                                                 Thread.sleep(5);
477                                                         }
478                                                         
479                                                 }
480                                                 
481                                                 if(  com.serialPort.getInputBufferBytesCount() > 0 )
482                                                 {
483                                                         System.out.print("Reading "+com.serialPort.getInputBufferBytesCount()+ " bytes: ");
484                                                         data="";
485                                                         while( com.serialPort.getInputBufferBytesCount() > 0 )
486                                                         {
487                                                                 String in = com.serialPort.readString();
488                                                                 data += in;
489                                                                 
490                                                         }
491                                                         if( data.contains("[generate]") )
492                                                         {
493                                                                 noTimeOut=true;
494                                                                 System.out.println("1: noTimeOut");
495                                                         }                                                       
496                                                         System.out.println(data);
497                                                 }
498                                         }//While typing
499                                         System.out.println("All chars typed, waiting for [save entry ");
500                                         
501                                         int step=0;
502                                         
503                                         timeOut = 30000;
504                                         while( timeOut > 0 || noTimeOut )
505                                         {
506                                                 
507                                                 if( com.serialPort.getInputBufferBytesCount() > 0 )
508                                                 {
509                                                         String in = com.serialPort.readString();
510                                                         //System.out.println("Read>"+in);
511                                                         data += in;
512                                                         System.out.println("Data:"+data);
513                                                         
514                                                         //Check for abort first, in that case, we don't want to do anything.
515                                                         if( data.contains("[abort]") )
516                                                         {
517                                                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, "ERROR:"+data,null,'A') );
518                                                                 return;
519                                                         }
520                                                         
521                                                         //If we're generating a password, we don't want to timeout
522                                                         if( data.contains("[generate]") )
523                                                         {
524                                                                 noTimeOut=true;
525                                                                 System.out.println("2: noTimeOut");
526                                                                 
527                                                         }
528                                                         
529                                                         //If we're at step0 and have the saveentry string and there's a ] after it, we're good to fetch the account number.
530                                                         if( step==0 && data.contains("[save entry ") && (data.lastIndexOf(']') > data.lastIndexOf("[save entry ")) )
531                                                         {
532                                                                 int begin = data.lastIndexOf("[save entry ")+12;
533                                                                 String subStr = data.substring(begin);
534                                                                 int end = subStr.indexOf(']');
535                                                                 subStr = subStr.substring(0,end);
536                                                                 if( subStr.length()==1)
537                                                                 {
538                                                                         subStr = "0"+subStr;
539                                                                 }
540                                                                 acc.num = subStr;
541                                                                 listAddAcc( acc.num, acc.name);
542                                                                 System.out.println("Account: "+acc.num+" " + acc.name);
543                                                                 
544                                                                 //Cut data, so that the [done] step1 looks for will not be the one after [generate].
545                                                                 data = data.substring(begin+end);
546                                                                 
547                                                                 System.out.println("Found [save entry, looking for done.");
548                                                                 step++;
549                                                         }
550                                                         
551                                                         if( step==1 && data.contains("[done]") )
552                                                         {
553                                                                 System.out.println("Found [done] in: {"+data+"}");
554                                                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_OKAY, "DONE:"+data,acc,'A') );
555                                                                 return;
556                                                         }
557
558                                                 } else {
559                                                         Thread.sleep(50);
560                                                         timeOut -= 50;
561                                                 }
562                                         } //While !timeout 
563                                 } //If !timeout
564                                 
565                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, "TIMEOUT:"+data,null,'A') );
566
567                         } catch (Exception e) {
568                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, "EXCEPTION",null,'A') );
569                         }
570                         
571                 }
572
573                 
574         }
575
576         private void flushSerial() {
577                 try {
578                         Thread.sleep(10);
579                         com.serialPort.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
580                         
581                         System.out.println("Flushed "+com.serialPort.getInputBufferBytesCount()+" bytes.");
582                         while( com.serialPort.getInputBufferBytesCount() > 0 )
583                         {
584                                 com.serialPort.readBytes();
585                         }
586                         
587                 } catch(Exception e)
588                 {
589                         System.out.println("FkManager flushSerial Exception:"+e.getMessage() );
590                 }
591                 
592         }       
593         
594         public void createAccount(String strAccountName, String strUserName,
595                         Boolean autoPassword, int autoPassLen, Boolean autoPassAllSpecials,
596                         String autoPassSpecials, String strPassword, Boolean seperatorTab,
597                         FkActionEventListener delegate) {
598                         
599                         StringBuilder sb = new StringBuilder(256);
600                 
601                         
602                         
603                         sb.append(strAccountName);
604                         sb.append(ENTER_KEY);
605                         sb.append(PAUSE_CODE);
606                         sb.append(strUserName);
607                         sb.append(ENTER_KEY);
608                         sb.append(PAUSE_CODE);
609                         
610                         if( autoPassword )
611                         {
612                                 sb.append('2'); //Select automatic password
613                                 sb.append(PAUSE_CODE);
614                                 sb.append(autoPassLen);
615                                 sb.append(ENTER_KEY);
616
617                                 
618                                 if( autoPassAllSpecials )
619                                 {
620                                         sb.append('1'); //Allow all characters
621                                 } else {
622                                         if( autoPassSpecials.length() > 0 )
623                                         {
624                                                 sb.append('2'); //Allow only characters specified below
625                                                 sb.append(PAUSE_CODE);
626                                                 sb.append(autoPassSpecials);
627                                                 sb.append(ENTER_KEY);
628                                         } else {
629                                                 sb.append('3'); // Allow no special characters
630                                         }
631                                 }
632                         } else {
633                                 //Manual entered password
634                                 sb.append('1'); // Select manual password
635                                 sb.append(PAUSE_CODE);
636                                 sb.append(strPassword);
637                                 sb.append(ENTER_KEY);
638                         }
639                         
640                         sb.append(PAUSE_CODE);
641
642                         //Tab/Enter sep
643                         if( seperatorTab )
644                         {
645                                 sb.append('1'); //Select tab seperator
646                         } else {
647                                 sb.append('2'); //Select enter seperator
648                         }
649                         
650                         String seq = sb.toString();
651                         
652                         System.out.println("Seq ["+seq.replace(PAUSE_CODE, 'ø').replace(ENTER_KEY, 'å')+"]");
653                         
654                         NewAccountTask newTask = new NewAccountTask(seq, delegate, strAccountName);
655                         new Thread(newTask).start();                    
656                 
657         }
658
659         public void sortById(boolean byId) {
660                 if( byId )
661                 {
662                         sortMethod = new SortById();
663                 } else {
664                         sortMethod = new SortByName();
665                 }
666                 if(list != null )
667                 {
668                         Collections.sort(list, sortMethod);
669                 }
670         }
671
672         public void setBanner(String _banner) {
673                 banner = _banner;
674                 
675         }
676         
677         public String getBanner()
678         {
679                 return(banner);
680         }
681         
682         public boolean isStringValidForFk(String str)
683         {
684
685                 char passChars[] = {
686                                 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
687                                 'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
688                                 'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i',
689                                 'j','k','l','m','n','o','p','q','r','s','t','u','v','w','x',
690                                 'y','z','!','"','#','$','%','&','@','?','(',')','[',']','-',
691                                 '.',',','+','{','}','_','/','<','>','=','|','\'','\\', 
692                                 ';',':',' ','*'// <- 92 (idx 91)
693                                 };
694
695
696                 int len = str.length();
697                 for(int i=0; i<len; i++)
698                 {
699                         boolean valid=false;
700
701                         for(char c : passChars)
702                         {
703                                 if(str.charAt(i)==c)
704                                 {
705                                         valid=true;
706                                 }
707                         }
708
709                         if(!valid)
710                         {
711                                 System.out.println("FkManager.isStringValidForFk(); Invalid character '"+str.charAt(i)+"' at pos "+i+" in '"+str+"'");
712                                 return false;
713                         }
714                 }
715
716                 return true;
717         }
718
719         
720         
721         ///
722         private class BannerTask implements Runnable
723         {
724
725                 private FkActionEventListener delegate;
726                 private String bannerTxt;
727                 
728                 public BannerTask(String txt, FkActionEventListener d )
729                 {
730                         bannerTxt=txt;
731                         delegate=d;
732                 }
733                 
734                 @Override
735                 public void run() {
736                         
737                         int timeOut=0;
738                         String data="";
739                         String msg = "";
740
741
742                         try {
743                         
744                                 //First check that we get a prompt
745                                 if( !checkState() )
746                                 {
747                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.STATE_ERROR, "EXCEPTION",null,'b') );
748                                         return;
749                                 }
750
751                                 //Drain any previous input.
752                                 while( com.serialPort.getInputBufferBytesCount() > 0 )
753                                 {
754                                         com.serialPort.readBytes();
755                                 }
756                                 
757                                 com.serialPort.writeByte((byte)'x');
758                                 com.serialPort.writeByte((byte)'b');
759                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WAITING, "WAITING",null,'b') );
760
761                                 timeOut = 6000;
762                                 while(timeOut > 0)
763                                 {
764                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
765                                         {
766                                                 String in = com.serialPort.readString(); 
767                                                 data += in;
768                                                 System.out.println("Datain:" +in);
769                                                 if( data.contains("Banner (0-31):\r\n") )
770                                                 {
771                                                         System.out.println("Found");
772                                                         break;
773                                                 }
774                                         } else {
775                                                 timeOut -= 50;
776                                                 Thread.sleep(50);
777                                         }
778                                 }
779                                 
780
781                                 if(timeOut > 0 )
782                                 {
783                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WORKING, "WORKING",null,'b') );
784
785                                         for(int p=0; p < bannerTxt.length();p++)
786                                         {
787                                                 com.serialPort.writeByte( (byte)bannerTxt.charAt(p) );
788                                                 Thread.sleep(5);
789                                         }
790
791                                         while( com.serialPort.getInputBufferBytesCount() > 0 )
792                                         {
793                                                 com.serialPort.readBytes();
794                                         }
795
796                                         com.serialPort.writeByte( (byte)ENTER_KEY );
797
798                                         timeOut = 3000;
799                                         while(timeOut > 0)
800                                         {
801                                                 if( com.serialPort.getInputBufferBytesCount() > 0 )
802                                                 {
803                                                         String in = com.serialPort.readString(); 
804                                                         data += in;
805                                                         System.out.println("Datain:" +in);
806                                                         if( data.contains("[done]\r\n") )
807                                                         {
808                                                                 System.out.println("Found");
809                                                                 break;
810                                                         }
811                                                 } else {
812                                                         timeOut -= 50;
813                                                         Thread.sleep(50);
814                                                 }
815                                         }
816                                 }
817
818                                 if( timeOut > 0 )
819                                 {
820
821                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_OKAY, "Saved:"+data,null,'b') );
822                                 } else {
823                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, "TIMEOUT:"+data,null,'b') );
824                                 }
825
826                         } catch(Exception e)
827                         {
828                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, "EXCEPTION",null,'b') );
829                                 return;
830                         }
831                 }
832
833         }
834
835         public void saveBanner(String bannerTxt, FkActionEventListener eventListener) {
836                 BannerTask bannerTask = new BannerTask(bannerTxt, eventListener);
837                 new Thread(bannerTask).start();
838         }
839
840         
841         private class LayoutTask implements Runnable
842         {
843
844                 private FkActionEventListener delegate;
845                 private String layout;
846                 
847                 public LayoutTask(int _Layout, FkActionEventListener d )
848                 {
849                         layout = ""+_Layout;
850                         delegate=d;
851                 }
852                 
853                 @Override
854                 public void run() {
855                         
856                         int timeOut=0;
857                         String data="";
858                         String msg = "";
859
860
861                         try {
862                         
863                                 //First check that we get a prompt
864                                 if( !checkState() )
865                                 {
866                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.STATE_ERROR, "EXCEPTION",null,'k') );
867                                         return;
868                                 }
869
870                                 //Drain any previous input.
871                                 while( com.serialPort.getInputBufferBytesCount() > 0 )
872                                 {
873                                         com.serialPort.readBytes();
874                                 }
875                                 
876                                 com.serialPort.writeByte((byte)'x');
877                                 com.serialPort.writeByte((byte)'k');
878                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WAITING, "WAITING",null,'k') );
879
880                                 timeOut = 6000;
881                                 while(timeOut > 0)
882                                 {
883                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
884                                         {
885                                                 String in = com.serialPort.readString(); 
886                                                 data += in;
887                                                 System.out.println("Datain:" +in);
888                                                 if( data.contains("Select keyboard layout:\r\n") && data.contains("\r\n% ") )
889                                                 {
890                                                         System.out.println("Found");
891                                                         break;
892                                                 }
893                                         } else {
894                                                 timeOut -= 50;
895                                                 Thread.sleep(50);
896                                         }
897                                 }
898
899                                 if(timeOut > 0 )
900                                 {
901
902
903                                         com.serialPort.writeByte( (byte)layout.charAt(0) );
904
905
906                                         while( com.serialPort.getInputBufferBytesCount() > 0 )
907                                         {
908                                                 com.serialPort.readBytes();
909                                         }
910
911                                         com.serialPort.writeByte( (byte)ENTER_KEY );
912
913                                         timeOut = 3000;
914                                         while(timeOut > 0)
915                                         {
916                                                 if( com.serialPort.getInputBufferBytesCount() > 0 )
917                                                 {
918                                                         String in = com.serialPort.readString(); 
919                                                         data += in;
920                                                         System.out.println("Datain:" +in);
921                                                         if( data.contains("test.\r\n#") )
922                                                         {
923                                                                 System.out.println("Found");
924                                                                 break;
925                                                         }
926                                                 } else {
927                                                         timeOut -= 50;
928                                                         Thread.sleep(50);
929                                                 }
930                                         }
931                                 }
932
933                                 timeOut = 30000;
934                                 while(timeOut > 0)
935                                 {
936                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
937                                         {
938                                                 String in = com.serialPort.readString(); 
939                                                 data += in;
940                                                 System.out.println("Datain:" +in);
941                                                 if( data.contains("Correct [y/n] ?") )
942                                                 {
943                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WORKING, "WORKING",null,'k') );
944                                                         System.out.println("Found");
945                                                         com.serialPort.writeByte((byte)'y');
946
947                                                         Thread.sleep(500); //sleep before returning the result, give the UI plenty of time to catch up.
948
949                                                         break;
950                                                 }
951                                         } else {
952                                                 timeOut -= 50;
953                                                 Thread.sleep(50);
954                                         }
955                                 }                               
956
957                                 if( timeOut > 0 )
958                                 {
959                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_OKAY, "Saved:"+data,null,'k') );
960                                 } else {
961                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, "TIMEOUT:"+data,null,'k') );
962                                 }
963
964                         } catch(Exception e)
965                         {
966                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, "EXCEPTION",null,'k') );
967                                 return;
968                         }
969                 }
970
971         }
972         
973         public void saveLayout(int layout, FkActionEventListener eventListener) {
974                 LayoutTask lt = new LayoutTask(layout, eventListener);
975                 new Thread(lt).start();
976         }
977         
978         
979         private class BackupTask implements Runnable
980         {
981
982                 private FkActionEventListener delegate;
983                 private File file;
984                 
985                 
986                 public BackupTask(File f, FkActionEventListener d )
987                 {
988                         file=f;
989                         delegate=d;
990                 }
991                 
992                 /*
993                  * 
994                  * uint8_t crc8(const uint8_t *addr, uint8_t len)
995                 {
996                         uint8_t crc = 0;
997
998                         while (len--) {
999                                 uint8_t inbyte = *addr++;
1000                                 for (uint8_t i = 8; i; i--) {
1001                                         uint8_t mix = (crc ^ inbyte) & 0x01;
1002                                         crc >>= 1;
1003                                         if (mix) crc ^= 0x8C;
1004                                         inbyte >>= 1;
1005                                 }
1006                         }
1007                         return crc;
1008                 }*/
1009                 
1010                 byte crc8( byte[] dat, int begin, int len )
1011                 {
1012                         int crc = 0;
1013                         
1014                         int idx=0;
1015
1016                         while( len-- != 0 )
1017                         {
1018                                 int inbyte = dat[begin+idx];
1019                                 idx++;
1020                                 
1021                                 for(int i=8; i!=0; i--)
1022                                 {
1023                                         int mix =  (( crc ^ inbyte) & 0x01);
1024                                         crc >>=1;
1025                                         if( mix != 0 )
1026                                         {
1027                                                 crc ^=0x8C;
1028                                         }
1029                                         inbyte >>=1;
1030                                 }
1031                         }
1032                         return((byte)crc);
1033                 }
1034                 
1035                 @Override
1036                 public void run() {
1037                         
1038                         int timeOut=0;
1039                         String data="";
1040
1041                         int state=0;
1042
1043                         try {
1044
1045                                 //First check that we get a prompt
1046                                 if( !checkState() )
1047                                 {
1048                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.STATE_ERROR, "EXCEPTION",null,'e') );
1049                                         return;
1050                                 }
1051
1052                                 //Drain any previous input.
1053                                 while( com.serialPort.getInputBufferBytesCount() > 0 )
1054                                 {
1055                                         com.serialPort.readBytes();
1056                                 }
1057                                 com.serialPort.writeByte((byte)'X');
1058                                 com.serialPort.writeByte((byte)'e');
1059
1060                                 
1061                                 timeOut = 6000;
1062                                 
1063                                 ByteBuffer bin = new ByteBuffer( 67000 );
1064
1065                                 while(timeOut > 0)
1066                                 {
1067                                         if( com.serialPort.getInputBufferBytesCount() > 0 )
1068                                         {
1069                                                 
1070                                                 int n = com.serialPort.getInputBufferBytesCount();
1071                                                 while(n-->0)
1072                                                 {
1073                                                         bin.append( com.serialPort.readBytes(1)[0]);
1074                                                 }
1075
1076
1077                                                 data += new String(bin.toArray());
1078
1079                                                 if( state==0 && data.contains("[RDY]\r\n") )
1080                                                 {
1081                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WAITING, "WAITING",null,'e') );
1082
1083                                                         state=1;
1084                                                 }
1085
1086                                                 if( state==1 && data.contains("[OK]\r\n[BEGIN]" ) )
1087                                                 {
1088                                                         state=2;
1089
1090                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_WORKING, "Working",null,'e') );
1091                                                 }
1092
1093                                                 if( state==2 )
1094                                                 {
1095                                                         timeOut=3000;
1096                                                         if( data.contains("[END]") )
1097                                                         {
1098
1099                                                                 //data = data.substring(0, data.length()-5 );
1100                                                                 
1101                                                                 bin.trimToSize();
1102                                                                 
1103                                                                 byte[] arr = bin.toArray();
1104                                                                 
1105                                                                 byte[] clean = new byte[66000];
1106                                                                 
1107                                                                 state=0;
1108                                                                 int idx=0;
1109                                                                 int cc=0;
1110                                                                 String errors="";
1111                                                                 for(int i=0;i< arr.length; i++ )
1112                                                                 {
1113                                                                         //Find [BEGIN]
1114                                                                         if(state==0 && i+6 < arr.length)
1115                                                                         {
1116                                                                                 if(arr[i] == '[' &&arr[i+1] == 'B' &&arr[i+2] == 'E' &&arr[i+3] == 'G' &&arr[i+4] == 'I' &&arr[i+5] == 'N' &&arr[i+6] == ']' )
1117                                                                                 {
1118                                                                                         i+=7;
1119                                                                                         state=1;
1120                                                                                         idx=0;
1121                                                                                 }
1122                                                                         }
1123                                                                         
1124                                                                         if(state==1)
1125                                                                         {
1126                                                                                 
1127                                                                                 if( idx < 66000 )
1128                                                                                 {
1129                                                                                         clean[idx] = arr[i];
1130                                                                                         cc++;
1131                                                                                         
1132                                                                                         if( cc==33  )
1133                                                                                         {
1134                                                                                                 cc=0;
1135
1136                                                                                                 byte c = crc8(clean,(idx-32),32);
1137                                                                                                 
1138                                                                                                 if( c != clean[idx] )
1139                                                                                                 {
1140                                                                                                         errors += "CRC Error: Bytes "+(idx-32)+" to "+(idx-1)+" have CRC "+c+" but the CRC sent from FinalKey in byte "+idx+" is "+clean[idx]+"\n";
1141                                                                                                 }
1142                                                                                         }
1143                                                                                         
1144                                                                                         idx++;
1145                                                                                 } else {
1146                                                                                         if( arr[i] == '['  &&arr[i+1] == 'E' &&arr[i+2] == 'N' &&arr[i+3] == 'D' &&arr[i+4] == ']' )
1147                                                                                         {
1148                                                                                                 FileOutputStream fout = new FileOutputStream( file );
1149                                                                                                 fout.write( clean );
1150                                                                                                 fout.close();
1151                                                                                                 
1152                                                                                                 if( errors.length() == 0 )
1153                                                                                                 {
1154                                                                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_OKAY, "Done" ,null,'e') );
1155                                                                                                 } else {
1156                                                                                                         Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ERROR, errors ,null,'e') );
1157                                                                                                 }
1158                                                                                                 return;
1159                                                                                         } else {
1160                                                                                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.UNEXPECTED_ACTION_RESULT_ERROR, "Read past the end?" ,null,'e') );
1161                                                                                         }
1162                                                                                 }
1163                                                                         }
1164                                                                         
1165                                                                         
1166                                                                 }
1167                                                                 
1168                                                                 
1169                                                                 break;
1170                                                         } else {
1171                                                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.PROGRESS_UPDATE, ""+bin.size() ,null,'e') );
1172                                                         }
1173                                                 }
1174
1175                                         } else {
1176                                                 timeOut -= 50;
1177                                                 Thread.sleep(50);
1178                                         }
1179                                 }
1180                                 Display.getDefault().asyncExec( new FkActionEventMsg(delegate, FkActionEventListener.FkActionEventType.ACTION_ABORTED, "Timed out" ,null,'e') );
1181                                 
1182                                 
1183                         } catch (Exception e) { 
1184                                 
1185                         }
1186                 }
1187         }
1188
1189         public void backup(File f, FkActionEventListener delegate) {
1190                 BackupTask bt = new BackupTask(f, delegate );
1191                 new Thread(bt).start();
1192         }
1193         
1194         
1195
1196
1197 }