Commit 0db90c86b51bee47349c70ccdd6e9764de9074a2
authorManfred Steiner <sx@htl-kaindorf.at>
Sat, 8 Dec 2018 04:54:57 +0000 (05:54 +0100)
committerManfred Steiner <sx@htl-kaindorf.at>
Sat, 8 Dec 2018 04:54:57 +0000 (05:54 +0100)
111 files changed:
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
bad [new file with mode: 0644]
build.xml [new file with mode: 0644]
good [new file with mode: 0644]
jssc-2.8.0.jar [new file with mode: 0644]
manifest.mf [new file with mode: 0644]
measurements/2016-03-04-download-problem/logs [new file with mode: 0644]
measurements/2016-03-04-download-problem/p10i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p11i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p12.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p13.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p14i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p1i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p2i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p3i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p4i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p5i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p6i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p7i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p8i.png [new file with mode: 0644]
measurements/2016-03-04-download-problem/p9i.png [new file with mode: 0644]
nbproject/build-impl.xml [new file with mode: 0644]
nbproject/configs/crumb_2.properties [new file with mode: 0644]
nbproject/configs/empty.properties [new file with mode: 0644]
nbproject/configs/nano.properties [new file with mode: 0644]
nbproject/configs/sure.properties [new file with mode: 0644]
nbproject/genfiles.properties [new file with mode: 0644]
nbproject/project.properties [new file with mode: 0644]
nbproject/project.xml [new file with mode: 0644]
released/easyprogrammer.jar [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/ByteFifo.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/CpuTyp.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/LineTerminal.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/MemoryContent.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/ProgramFile.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/RSNOutputStream.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/data/Terminal.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.form [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.form [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSelectProgramFile.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.form [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.form [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/GUISwingWorker.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/SlidingWidthLayout.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/gui/TerminalArea.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal16.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Download.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Download16.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Information16.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Information24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop16.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_128x128.ico [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_16x16.ico [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_32x32.ico [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_64x64.ico [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/EasyProgrammer32.dll [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/version.txt [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/EasyProgrammer64.dll [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/version.txt [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammerLib.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega328P.hex [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega8L.hex [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_atmega16.hex [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/ExtendedLogRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogConfigRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogDebugRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFineRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinerRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinestRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogInfoRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogSevereRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogStackHandler.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWarningRecord.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWriterHandler.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/logging/Logger.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/manpage/easyprogrammer.1 [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/DebugOutputStream.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadFile.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadProtocol.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/Protocol.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/ResetProtocol.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialInterface.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfo.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfoFactory.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/serial/TerminalProtocol.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/server/IDEServer.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleClient.java [new file with mode: 0644]
src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleServer.java [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0cf9cee
--- /dev/null
@@ -0,0 +1,23 @@
+# Netbeans Java with ant
+**/nbproject/private/
+**/build/
+**/dist/
+
+# Netbeans Java with Maven
+**/target/
+
+# Netbeans Java with Gradle
+**/.gradle/
+**/.nb-gradle/
+
+# Netbeans C/C++
+**/nbproject/private/
+**/build/
+**/dist/
+**/.dep.inc
+
+# Codeblocks/Structorizer
+**/bin/
+**/obj/
+*.depend
+*.layout
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..4f15fa0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# Easyprogrammer
+
+## History
+
+Version |    Date   | Remarks
+--------|-----------|-----------------------------
+ 2.26   | 25.8.2016 | 1:1 movement from SVN server
+
diff --git a/bad b/bad
new file mode 100644 (file)
index 0000000..b7f6623
--- /dev/null
+++ b/bad
@@ -0,0 +1,144 @@
+root@len:~# usbdump -d 10c4:ea60 -a
+  0.000000 1<-- 
+  0.000041 1<-- 
+  0.007915 1<-- 
+  0.007956 1<-- 
+  0.028046 1<-- 
+  0.028176 1<-- 
+  0.098216 1<-- 
+  0.098254 1<-- 
+  6.066158 1<-- 72:  0d 0a 42(B) 6f(o) 6f(o) 74(t) 6c(l) 6f(o) 61(a) 64(d) 65(e) 72(r) 20( ) 56(V) 65(e) 72(r)  73(s) 69(i) 6f(o) 6e(n) 20( ) 32(2) 2e(.) 30(0) 35(5) 20( ) 5b([) 41(A) 74(t) 6d(m) 65(e) 67(g)  61(a) 31(1) 36(6) 2c(,) 32(2) 30(0) 31(1) 31(1) 2d(-) 30(0) 38(8) 2d(-) 32(2) 37(7) 2c(,) 53(S)  58(X) 5d(]) 20( ) 20( ) 20( ) 0d 0a 20( ) 2e(.) 2e(.) 2e(.) 20( ) 70(p) 72(r) 65(e) 73(s)  73(s) 20( ) 27(') 40(@) 27(') 0d 0a 2e(.)
+  6.116381 1<-- 1:  2e(.)
+  6.166489 1<-- 1:  2e(.)
+  6.216642 1<-- 1:  2e(.)
+  6.266846 1<-- 1:  2e(.)
+  6.315690 -->1 1:  40(@)
+  6.317352 1<-- 3:  0d 0a 40(@)
+  6.320949 -->1 1:  6d(m)
+  6.321695 1<-- 1:  6d(m)
+  6.322652 -->1 1:  30(0)
+  6.323409 1<-- 1:  30(0)
+  6.327046 -->1 1:  32(2)
+  6.327786 1<-- 1:  32(2)
+  6.329665 -->1 1:  40(@)
+  6.330409 1<-- 1:  40(@)
+  6.331938 -->1 1:  66(f)
+  6.332680 1<-- 1:  66(f)
+  6.334616 -->1 1:  31(1)
+  6.335351 1<-- 1:  31(1)
+  6.337155 -->1 1:  32(2)
+  6.337887 1<-- 1:  32(2)
+  6.339546 -->1 1:  38(8)
+  6.340351 1<-- 1:  38(8)
+  6.341754 -->1 1:  0a
+  6.443451 1<-- 4:  0d 0a 66(f) 3e(>)
+  6.446139 -->1 1:  50(P)
+  6.446150 -->1 1:  30(0)
+  6.446163 -->1 1:  30(0)
+  6.447236 -->1 1:  0c
+  6.447242 -->1 1:  94
+  6.447258 -->1 9:  bd 00 0c 94 da 00 0c 94 da
+  6.447303 -->1 26:  00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da  00 0c 94 da 00 0c 94 da 00 0c
+  6.447363 -->1 40:  94 da 00 0c 94 da 00 0c 94 00 03 0c 94 da 00 0c  94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c  94 da 00 0c 94 da 00 0c
+  6.447445 -->1 45:  94 38(8) 03 0c 94 da 00 55(U) 04 7f 04 8a 04 96 04 a6  04 b4 04 c3 04 d2 04 e3 04 ef 04 fd 04 0b 05 1a  05 26(&) 05 3f(?) 05 4b(K) 05 2b(+) 04 49(I) 04 6e(n) 61(a)
+  6.447526 -->1 5:  6e(n) 00 69(i) 6e(n) 66(f)
+  
+  7.049728 -->1 1:  50(P)
+  7.049805 -->1 1:  30(0)
+  7.049823 -->1 1:  30(0)
+  7.050864 1<-- 3:  3d(=) 30(0) 30(0)
+  7.050996 -->1 1:  0c
+  7.051020 -->1 1:  94
+  7.051032 -->1 1:  bd
+  7.051077 -->1 3:  00 0c 94
+  7.051119 -->1 4:  da 00 0c 94
+  7.051148 -->1 2:  da 00
+  7.051203 -->1 8:  0c 94 da 00 0c 94 da 00
+  7.051248 -->1 7:  0c 94 da 00 0c 94 da
+  7.051376 -->1 26:  00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da  00 0c 94 00 03 0c 94 da 00 0c
+  7.051409 -->1 4:  94 da 00 0c
+  7.051500 -->1 16:  94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c
+  7.051548 -->1 8:  94 da 00 0c 94 38(8) 03 0c
+  7.051613 -->1 12:  94 da 00 55(U) 04 7f 04 8a 04 96 04 a6
+  7.051665 -->1 8:  04 b4 04 c3 04 d2 04 e3
+  7.051725 -->1 11:  04 ef 04 fd 04 0b 05 1a 05 26(&) 05
+  7.051790 -->1 2:  3f(?) 05
+  7.051848 -->1 8:  4b(K) 05 2b(+) 04 49(I) 04 6e(n) 61(a)
+  7.051897 -->1 5:  6e(n) 00 69(i) 6e(n) 66(f)
+  7.062135 1<-- 13:  20( ) 38(8) 31(1) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  
+
+
+7.072293 -->1 1:  50(P)
+  7.072351 -->1 1:  30(0)
+  7.072371 -->1 1:  31(1)
+  7.073451 -->1 1:  00
+  7.073470 -->1 1:  40(@)
+  7.073475 -->1 1:  7a(z)
+  7.073512 -->1 34:  10 f3 5a(Z) 00 a0 72(r) 4e(N) 18 09 00 10 a5 d4 e8 00 00  e8 76(v) 48(H) 17 00 00 e4 0b 54(T) 02 00 00 ca 9a 3b(;) 00  00 00
+  7.073557 -->1 42:  e1 f5 05 00 00 80 96 98 00 00 00 40(@) 42(B) 0f 00 00  00 a0 86 01 00 00 00 10 27(') 00 00 00 00 e8 03 00  00 00 00 64(d) 00 00 00 00 00 0a
+  7.073638 -->1 48:  00 00 00 00 00 01 00 00 00 00 00 2c(,) 76(v) d8 88 dc  67(g) 4f(O) 08 23(#) df c1 df ae 59(Y) e1 b1 b7 96 e5 e3 e4  53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&) eb 89 8c
+  7.085477 1<-- 7:  3d(=) 30(0) 0c 0d 0a 66(f) 3e(>)
+  7.089387 -->1 1:  50(P)
+  7.090945 -->1 1:  30(0)
+  7.090960 -->1 1:  31(1)
+  7.092043 -->1 1:  00
+  7.092058 -->1 1:  40(@)
+  7.092077 -->1 5:  7a(z) 10 f3 5a(Z) 00
+  7.092115 -->1 18:  a0 72(r) 4e(N) 18 09 00 10 a5 d4 e8 00 00 e8 76(v) 48(H) 17  00 00
+  7.092166 -->1 23:  e4 0b 54(T) 02 00 00 ca 9a 3b(;) 00 00 00 e1 f5 05 00  00 80 96 98 00 00 00
+  7.092243 -->1 35:  40(@) 42(B) 0f 00 00 00 a0 86 01 00 00 00 10 27(') 00 00  00 00 e8 03 00 00 00 00 64(d) 00 00 00 00 00 0a 00  00 00 00
+  7.092378 -->1 25:  00 01 00 00 00 00 00 2c(,) 76(v) d8 88 dc 67(g) 4f(O) 08 23(#)  df c1 df ae 59(Y) e1 b1 b7 96
+  7.092476 -->1 19:  e5 e3 e4 53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&)  eb 89 8c
+  7.108808 1<-- 7:  3d(=) 10 00 0d 0a 66(f) 3e(>)
+  7.116337 -->1 1:  50(P)
+  7.116376 -->1 1:  30(0)
+  7.116389 -->1 1:  31(1)
+  7.117472 -->1 1:  00
+  7.117492 -->1 1:  40(@)
+  7.117507 -->1 3:  7a(z) 10 f3
+  7.117558 -->1 17:  5a(Z) 00 a0 72(r) 4e(N) 18 09 00 10 a5 d4 e8 00 00 e8 76(v)  48(H)
+  7.117603 -->1 15:  17 00 00 e4 0b 54(T) 02 00 00 ca 9a 3b(;) 00 00 00
+  7.117649 -->1 15:  e1 f5 05 00 00 80 96 98 00 00 00 40(@) 42(B) 0f 00
+  7.117718 -->1 22:  00 00 a0 86 01 00 00 00 10 27(') 00 00 00 00 e8 03  00 00 00 00 64(d) 00
+  7.117789 -->1 21:  00 00 00 00 0a 00 00 00 00 00 01 00 00 00 00 00  2c(,) 76(v) d8 88 dc
+  7.117864 -->1 25:  67(g) 4f(O) 08 23(#) df c1 df ae 59(Y) e1 b1 b7 96 e5 e3 e4  53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8
+  7.117941 -->1 7:  e6 c2 84 26(&) eb 89 8c
+  7.132067 1<-- 7:  3d(=) 00 00 0d 0a 66(f) 3e(>)
+  7.133848 -->1 1:  50(P)
+  7.133855 -->1 1:  30(0)
+  7.133873 -->1 1:  31(1)
+  7.134931 -->1 1:  00
+  7.134960 -->1 1:  40(@)
+  7.134972 -->1 1:  7a(z)
+  7.134994 -->1 10:  10 f3 5a(Z) 00 a0 72(r) 4e(N) 18 09 00
+  7.135033 -->1 26:  10 a5 d4 e8 00 00 e8 76(v) 48(H) 17 00 00 e4 0b 54(T) 02  00 00 ca 9a 3b(;) 00 00 00 e1 f5
+  7.135086 -->1 37:  05 00 00 80 96 98 00 00 00 40(@) 42(B) 0f 00 00 00 a0  86 01 00 00 00 10 27(') 00 00 00 00 e8 03 00 00 00  00 64(d) 00 00 00
+  7.135170 -->1 51:  00 00 0a 00 00 00 00 00 01 00 00 00 00 00 2c(,) 76(v)  d8 88 dc 67(g) 4f(O) 08 23(#) df c1 df ae 59(Y) e1 b1 b7 96  e5 e3 e4 53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&)  eb 89 8c
+  7.155368 1<-- 7:  3d(=) 00 64(d) 0d 0a 66(f) 3e(>)
+  7.157929 -->1 1:  50(P)
+  7.157939 -->1 1:  30(0)
+  7.157953 -->1 1:  31(1)
+  7.159010 -->1 1:  00
+  7.159018 -->1 1:  40(@)
+  7.159033 -->1 12:  7a(z) 10 f3 5a(Z) 00 a0 72(r) 4e(N) 18 09 00 10
+  7.159079 -->1 48:  a5 d4 e8 00 00 e8 76(v) 48(H) 17 00 00 e4 0b 54(T) 02 00  00 ca 9a 3b(;) 00 00 00 e1 f5 05 00 00 80 96 98 00  00 00 40(@) 42(B) 0f 00 00 00 a0 86 01 00 00 00 10 27(')
+  7.159141 -->1 62:  00 00 00 00 e8 03 00 00 00 00 64(d) 00 00 00 00 00  0a 00 00 00 00 00 01 00 00 00 00 00 2c(,) 76(v) d8 88  dc 67(g) 4f(O) 08 23(#) df c1 df ae 59(Y) e1 b1 b7 96 e5 e3  e4 53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&)
+  7.159288 -->1 3:  eb 89 8c
+  7.178629 1<-- 7:  3d(=) 64(d) 00 0d 0a 66(f) 3e(>)
+  7.182071 -->1 1:  50(P)
+  7.182120 -->1 1:  30(0)
+  7.182133 -->1 1:  31(1)
+  7.183221 -->1 1:  00
+  7.183227 -->1 1:  40(@)
+  7.183247 -->1 23:  7a(z) 10 f3 5a(Z) 00 a0 72(r) 4e(N) 18 09 00 10 a5 d4 e8 00  00 e8 76(v) 48(H) 17 00 00
+  7.183290 -->1 40:  e4 0b 54(T) 02 00 00 ca 9a 3b(;) 00 00 00 e1 f5 05 00  00 80 96 98 00 00 00 40(@) 42(B) 0f 00 00 00 a0 86 01  00 00 00 10 27(') 00 00 00
+  7.183374 -->1 62:  00 e8 03 00 00 00 00 64(d) 00 00 00 00 00 0a 00 00  00 00 00 01 00 00 00 00 00 2c(,) 76(v) d8 88 dc 67(g) 4f(O)  08 23(#) df c1 df ae 59(Y) e1 b1 b7 96 e5 e3 e4 53(S) c6  3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&) eb 89 8c
+  7.201923 1<-- 7:  3d(=) 00 00 0d 0a 66(f) 3e(>)
+  7.205091 -->1 1:  46(F)
+  7.205130 -->1 1:  46(F)
+  7.205146 -->1 1:  46(F)
+  9.831366 1<-- 
+  9.831405 1<-- 
+^A
+
diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..a82abdc
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="easyprogrammer" default="default" basedir=".">
+    <description>Builds, tests, and runs the project easyprogrammer.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar:                  JAR building
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="easyprogrammer-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+    
+<target name="-post-jar">
+  <jar jarfile="dist/easyprogrammer-withJSSC.jar">
+    <zipfileset src="${dist.jar}" excludes="META-INF/*" />
+    <zipfileset src="dist/lib/jssc-2.8.0.jar" excludes="META-INF/*" />
+    <!--<fileset dir="libs/windows">
+      <include name="EasyProgrammer-*.dll" />
+    </fileset> -->
+    <manifest>
+        <attribute name="Main-Class" value="at.htlkaindorf.sx.EasyProgrammer.gui.EasyProgrammer"/>
+    </manifest>
+  </jar>
+  <move file="dist/easyprogrammer-withJSSC.jar" tofile="dist/easyprogrammer.jar" />
+</target>    
+    
+</project>
diff --git a/good b/good
new file mode 100644 (file)
index 0000000..c627206
--- /dev/null
+++ b/good
@@ -0,0 +1,178 @@
+  0.000000 1<-- 
+  0.000037 1<-- 
+  4.933322 1<-- 72:  0d 0a 42(B) 6f(o) 6f(o) 74(t) 6c(l) 6f(o) 61(a) 64(d) 65(e) 72(r) 20( ) 56(V) 65(e) 72(r)  73(s) 69(i) 6f(o) 6e(n) 20( ) 32(2) 2e(.) 30(0) 35(5) 20( ) 5b([) 41(A) 74(t) 6d(m) 65(e) 67(g)  61(a) 31(1) 36(6) 2c(,) 32(2) 30(0) 31(1) 31(1) 2d(-) 30(0) 38(8) 2d(-) 32(2) 37(7) 2c(,) 53(S)  58(X) 5d(]) 20( ) 20( ) 20( ) 0d 0a 20( ) 2e(.) 2e(.) 2e(.) 20( ) 70(p) 72(r) 65(e) 73(s)  73(s) 20( ) 27(') 40(@) 27(') 0d 0a 2e(.)
+  4.983453 1<-- 1:  2e(.)
+  5.033634 1<-- 1:  2e(.)
+  5.083828 1<-- 1:  2e(.)
+  5.133950 1<-- 1:  2e(.)
+  5.184144 1<-- 1:  2e(.)
+  5.232408 -->1 1:  40(@)
+  5.234632 1<-- 3:  0d 0a 40(@)
+  5.244625 -->1 1:  6d(m)
+  5.245416 1<-- 1:  6d(m)
+  5.245800 -->1 1:  30(0)
+  5.246553 1<-- 1:  30(0)
+  5.246968 -->1 1:  32(2)
+  5.247706 1<-- 1:  32(2)
+  5.248286 -->1 1:  40(@)
+  5.249038 1<-- 1:  40(@)
+  5.249404 -->1 1:  66(f)
+  5.250140 1<-- 1:  66(f)
+  5.250562 -->1 1:  31(1)
+  5.251308 1<-- 1:  31(1)
+  5.254641 -->1 1:  32(2)
+  5.255418 1<-- 1:  32(2)
+  5.255888 -->1 1:  38(8)
+  5.256633 1<-- 1:  38(8)
+  5.257159 -->1 1:  0a
+  5.358839 1<-- 4:  0d 0a 66(f) 3e(>)
+  
+  5.360713 -->1 131:  50(P) 30(0) 30(0) 0c 94 bd 00 0c 94 da 00 0c 94 da 00 0c  94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c  94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c  94 00 03 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c  94 da 00 0c 94 da 00 0c 94 da 00 0c 94 da 00 0c  94 38(8) 03 0c 94 da 00 55(U) 04 7f 04 8a 04 96 04 a6  04 b4 04 c3 04 d2 04 e3 04 ef 04 fd 04 0b 05 1a  05 26(&) 05 3f(?) 05 4b(K) 05 2b(+) 04 49(I) 04 6e(n) 61(a) 6e(n) 00 69(i)  6e(n) 66(f) 00
+  5.384545 1<-- 3:  3d(=) 30(0) 30(0)
+  5.395798 1<-- 13:  20( ) 33(3) 31(1) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  
+
+
+  5.396393 -->1 131:  50(P) 30(0) 31(1) 00 40(@) 7a(z) 10 f3 5a(Z) 00 a0 72(r) 4e(N) 18 09 00  10 a5 d4 e8 00 00 e8 76(v) 48(H) 17 00 00 e4 0b 54(T) 02  00 00 ca 9a 3b(;) 00 00 00 e1 f5 05 00 00 80 96 98  00 00 00 40(@) 42(B) 0f 00 00 00 a0 86 01 00 00 00 10  27(') 00 00 00 00 e8 03 00 00 00 00 64(d) 00 00 00 00  00 0a 00 00 00 00 00 01 00 00 00 00 00 2c(,) 76(v) d8  88 dc 67(g) 4f(O) 08 23(#) df c1 df ae 59(Y) e1 b1 b7 96 e5  e3 e4 53(S) c6 3a(:) e6 51(Q) 99 76(v) 96 e8 e6 c2 84 26(&) eb  89 8c 9b
+  5.420156 1<-- 3:  3d(=) 30(0) 31(1)
+  5.431492 1<-- 13:  20( ) 35(5) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.432459 -->1 131:  50(P) 30(0) 32(2) 62(b) ed 40(@) 7c(|) 6f(o) fc ef bc 9c 9f 40(@) f2 ba  a5 6f(o) a5 f4 90 05 5a(Z) 2a(*) f7 5c(\) 93 6b(k) 6c(l) f9 67(g) 6d(m)  c1 1b fc e0 e4 0d 47(G) fe f5 20( ) e6 b5 00 d0 ed 90  2e(.) 03 00 94 35(5) 77(w) 05 00 80 84 1e 08 00 00 20( ) 4e(N)  0a 00 00 00 c8 0c 33(3) 33(3) 33(3) 33(3) 0f 98 6e(n) 12 83 11  41(A) ef 8d 21(!) 14 89 3b(;) e6 55(U) 16 cf fe e6 db 18 d1  84 4b(K) 38(8) 1b f7 7c(|) 1d 90 1d a4 bb e4 24($) 20( ) 32(2) 84  72(r) 5e(^) 22(") 81 00 c9 f1 24($) ec a1 e5 3d(=) 27(') 11 24($) 1f  be cf e5
+  5.456243 1<-- 3:  3d(=) 30(0) 32(2)
+  5.467552 1<-- 13:  20( ) 46(F) 44(D) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.467953 -->1 131:  50(P) 30(0) 33(3) d4 e0 de bf cd bf 10 e0 a0 e6 b0 e0 e4  ed f6 e1 02 c0 05 90 0d 92 a0 3d(=) b1 07 d9 f7 11  e0 a0 ed b0 e0 01 c0 1d 92 ae 31(1) b1 07 e1 f7 0e  94 97 05 0c 94 68(h) 0b 0c 94 00 00 10 92 f1 00 10  92 f0 00 10 92 e0 00 08 95 cf 92 df 92 ef 92 ff  92 0f 93 1f 93 cf 93 df 93 00 d0 1f 92 cd b7 de  b7 81 e0 0e 94 b2 02 88 23(#) 09 f4 55(U) c0 80 91 e0  00 86 30(0) 08 f4 50(P) c0 01 e0 10 e0 d1 2c(,) cc 24($) c3  94 81 ea
+  5.491779 1<-- 3:  3d(=) 30(0) 33(3)
+  5.503039 1<-- 13:  20( ) 35(5) 35(5) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.503766 -->1 131:  50(P) 30(0) 34(4) e8 2e(.) 80 e0 f8 2e(.) f8 01 ef 51(Q) ff 4f(O) 80  81 d8 0e 1f 92 df 92 1f 92 8f 93 ff 92 ef 92 0e  94 99 0a c3 94 0c 2d(-) 10 e0 80 91 e0 00 90 e0 04  97 0f 90 0f 90 0f 90 0f 90 0f 90 0f 90 08 17 19  07 1c f3 d1 94 1f 92 df 92 8f ea 90 e0 9f 93 8f  93 1f 92 83 e0 8f 93 ae 01 4f(O) 5f(_) 5f(_) 4f(O) 7a(z) 01 ff  92 4f(O) 93 0e 94 da 0a c7 01 0e 94 ad 0a f8 01 ef  51(Q) ff 4f(O) 20( ) 81 30(0) e0 89 81 99 27(') 87 fd 90 95 0f  b6 f8 94
+  5.527593 1<-- 3:  3d(=) 30(0) 34(4)
+  5.538906 1<-- 13:  20( ) 37(7) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.539438 -->1 131:  50(P) 30(0) 35(5) de bf 0f be cd bf 28(() 17 39(9) 07 81 f0 8b  eb 90 e0 0e 94 ad 0a 0f 90 0f 90 0f 90 df 91 cf  91 1f 91 0f 91 ff 90 ef 90 df 90 cf 90 08 95 21(!)  81 30(0) e0 8a 81 99 27(') 87 fd 90 95 28(() 17 39(9) 07 39(9)  f7 84 eb 90 e0 0e 94 ad 0a e6 cf 0c 94 07 04 08  95 08 95 08 95 08 95 08 95 08 95 8b b3 91 e0 89  27(') 8b bb 08 95 8a 33(3) e9 f0 e0 91 e0 00 ef 30(0) 60(`)  f0 10 92 e0 00 80 91 f1 00 8f 3f(?) 91 f0 80 91 f1  00 8f 5f(_)
+  5.563221 1<-- 3:  3d(=) 30(0) 35(5)
+  5.574500 1<-- 13:  20( ) 31(1) 31(1) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.575421 -->1 131:  50(P) 30(0) 36(6) 80 93 f1 00 08 95 ee 23(#) 51(Q) f0 91 e0 9e  0f 90 93 e0 00 f0 e0 ef 51(Q) ff 4f(O) 80 83 8a 30(0) 39(9)  f0 08 95 91 e0 90 93 e0 00 80 93 e1 00 08 95 83  e0 0e 94 f3 02 81 e0 0c 94 98 02 90 91 f6 00 80  91 f5 00 98 17 91 f0 e0 91 f5 00 81 e0 8e 0f 80  93 f5 00 f0 e0 ee 50(P) ff 4f(O) 86 81 90 91 f5 00 90  31(1) 10 f0 10 92 f5 00 90 e0 08 95 8e ef 9f ef 08  95 5d(]) 9b fe cf 8c b9 99 27(') 87 fd 90 95 08 95 86  e1 e2 ef
+  5.599228 1<-- 3:  3d(=) 30(0) 36(6)
+  5.610517 1<-- 13:  20( ) 31(1) 36(6) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.611936 -->1 131:  50(P) 30(0) 37(7) f0 e0 df 01 1d 92 8a 95 e9 f7 bf e3 2e(.)  e7 85 e0 b1 50(P) 20( ) 40(@) 80 40(@) e1 f7 00 c0 00 00 85  e9 8c bf 8a e0 83 bf 82 e0 89 bf 88 bf 8c e0 89  b9 10 bc 1b b8 86 e8 80 bd 88 e9 8a b9 8f e0 8b  bb 18 ba 9f ef 9a bb 84 b3 8f 73(s) 84 bb 97 bb 8e  e6 90 e0 90 93 1b 01 80 93 1a 01 80 e6 90 e0 90  93 19 01 80 93 18 01 08 95 08 95 8f 3f(?) 11 f0 8f  5f(_) 08 95 8f ef 08 95 8f 3f(?) 2f(/) ef 92 07 11 f0 01  96 08 95
+  5.635748 1<-- 3:  3d(=) 30(0) 37(7)
+  5.647015 1<-- 13:  20( ) 36(6) 32(2) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.647829 -->1 131:  50(P) 30(0) 38(8) 8f ef 9f ef 08 95 fc 01 86 2f(/) 90 81 9f  3f(?) 19 f0 9f 5f(_) 90 83 08 95 9f ef 90 83 08 95 fc  01 86 2f(/) 20( ) 81 31(1) 81 2f(/) 3f(?) 9f ef 39(9) 07 29()) f0 2f(/)  5f(_) 3f(?) 4f(O) 31(1) 83 20( ) 83 08 95 2f(/) ef 3f(?) ef 31(1) 83 20( )  83 08 95 80 91 f2 00 87 ff 08 95 78(x) 94 08 95 e2  ef f0 e0 90 81 8f b7 80 78(x) 89 2b(+) 80 83 f8 94 08  95 8d ec 90 e0 9f 93 8f 93 0e 94 99 0a 0f 90 0f  90 08 95 90 91 f6 00 80 91 f5 00 98 17 38(8) f4 80  91 f6 00
+  5.671620 1<-- 3:  3d(=) 30(0) 38(8)
+  5.682916 1<-- 13:  20( ) 45(E) 34(4) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.683818 -->1 131:  50(P) 30(0) 39(9) 90 91 f5 00 80 5f(_) 89 1b 08 95 80 91 f6  00 90 91 f5 00 89 1b 08 95 20( ) 91 f2 00 9f b7 90  78(x) 92 2b(+) 90 93 f2 00 f8 94 20( ) 91 f6 00 90 91 f5  00 29()) 17 b0 f0 90 91 f6 00 20( ) 91 f5 00 92 1b 89  17 d0 f4 e0 91 f5 00 e8 0f e0 31(1) 88 f4 f0 e0 ee  50(P) ff 4f(O) 86 81 90 e0 20( ) 91 f2 00 27(') fd 0a c0 08  95 90 91 f6 00 20( ) 91 f5 00 90 5f(_) 92 1b e8 cf e0  51(Q) ed cf 78(x) 94 08 95 8f ef 9f ef ed cf 90 91 f2  00 8f b7
+  5.707632 1<-- 3:  3d(=) 30(0) 39(9)
+  5.718882 1<-- 13:  20( ) 31(1) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.719451 -->1 131:  50(P) 30(0) 41(A) 80 78(x) 89 2b(+) 80 93 f2 00 f8 94 5f(_) 9b 05  c0 8c b1 80 93 f7 00 5f(_) 99 fb cf 10 92 f5 00 10  92 f6 00 10 92 f7 00 80 91 f2 00 87 ff 08 95 78(x)  94 08 95 20( ) 91 f2 00 9f b7 90 78(x) 92 2b(+) 90 93 f2  00 f8 94 90 91 f4 00 98 23(#) 21(!) e0 09 f4 20( ) e0 90  91 f4 00 98 2b(+) 90 93 f4 00 80 91 f2 00 87 ff 01  c0 78(x) 94 82 2f(/) 08 95 20( ) 91 f2 00 9f b7 90 78(x) 92  2b(+) 90 93 f2 00 f8 94 20( ) 91 f4 00 28(() 23(#) 31(1) e0 09  f4 30(0) e0
+  5.743235 1<-- 3:  3d(=) 30(0) 41(A)
+  5.754527 1<-- 13:  20( ) 43(C) 39(9) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.755015 -->1 131:  50(P) 30(0) 42(B) 20( ) 91 f4 00 98 2f(/) 90 95 92 23(#) 90 93 f4  00 80 91 f2 00 87 ff 01 c0 78(x) 94 83 2f(/) 08 95 90  91 f4 00 98 23(#) 81 e0 09 f4 80 e0 08 95 81 11 04  c0 8f e0 8b bb 18 ba 08 95 80 ef 8b bb 8f ef 88  bb 08 95 84 30(0) 60(`) f4 9b b3 21(!) e0 30(0) e0 08 2e(.) 01  c0 22(") 0f 0a 94 ea f7 61(a) 11 03 c0 92 2b(+) 9b bb 08  95 20( ) 95 29()) 23(#) 2b(+) bb 08 95 84 30(0) 50(P) f4 9b b3 21(!)  e0 30(0) e0 08 2e(.) 01 c0 22(") 0f 0a 94 ea f7 92 27(') 9b  bb 08 95
+  5.778818 1<-- 3:  3d(=) 30(0) 42(B)
+  5.790092 1<-- 13:  20( ) 44(D) 42(B) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.791478 -->1 131:  50(P) 30(0) 43(C) 1f 92 0f 92 0f b6 0f 92 11 24($) 2f(/) 93 3f(?)  93 4f(O) 93 5f(_) 93 6f(o) 93 7f 93 8f 93 9f 93 af 93 bf  93 ef 93 ff 93 8c b1 82 35(5) 21(!) f4 90 91 d3 00 90  34(4) a9 f0 80 93 d3 00 0e 94 71(q) 01 ff 91 ef 91 bf  91 af 91 9f 91 8f 91 7f 91 6f(o) 91 5f(_) 91 4f(O) 91 3f(?)  91 2f(/) 91 0f 90 0f be 0f 90 1f 90 18 95 28(() e0 88  e1 90 e0 0f b6 f8 94 a8 95 81 bd 0f be 21(!) bd a8  95 ff cf 1f 92 0f 92 0f b6 0f 92 11 24($) 2f(/) 93 3f(?)  93 4f(O) 93
+  5.815284 1<-- 3:  3d(=) 30(0) 43(C)
+  5.826542 1<-- 13:  20( ) 34(4) 36(6) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.827825 -->1 131:  50(P) 30(0) 44(D) 5f(_) 93 6f(o) 93 7f 93 8f 93 9f 93 af 93 bf  93 ef 93 ff 93 80 91 d2 00 8f 5f(_) 85 30(0) e0 f1 10  92 d2 00 80 91 d1 00 8f 5f(_) 80 93 d1 00 80 91 d0  00 88 23(#) c1 f0 80 91 f3 00 8f 3f(?) c1 f1 8f 5f(_) 80  93 f3 00 ff 91 ef 91 bf 91 af 91 9f 91 8f 91 7f  91 6f(o) 91 5f(_) 91 4f(O) 91 3f(?) 91 2f(/) 91 0f 90 0f be 0f  90 1f 90 18 95 81 e0 80 93 d0 00 78(x) 94 80 91 d1  00 80 fd 19 c0 81 fd 12 c0 82 fd 1d c0 83 fd 1e  c0 84 fd
+  5.851633 1<-- 3:  3d(=) 30(0) 44(D)
+  5.862906 1<-- 13:  20( ) 31(1) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.863836 -->1 131:  50(P) 30(0) 45(E) 1f c0 85 fd 14 c0 86 fd 1e c0 87 ff 08  c0 0e 94 6c(l) 01 05 c0 80 93 d2 00 d3 cf 0e 94 66(f)  01 10 92 d0 00 ce cf 0e 94 64(d) 01 fa cf 8f ef c7  cf 0e 94 6a(j) 01 f5 cf 0e 94 67(g) 01 f2 cf 0e 94 68(h)  01 ef cf 0e 94 69(i) 01 ec cf 0e 94 6b(k) 01 e9 cf 80  e1 e8 e0 f1 e0 df 01 1d 92 8a 95 e9 f7 16 be 82  e1 80 b9 81 e0 81 b9 84 e0 86 bf 08 95 08 95 f8  94 80 91 0c 01 90 91 0d 01 8f 3b(;) 9f 47(G) 54(T) f4 80  91 0c 01
+  5.887642 1<-- 3:  3d(=) 30(0) 45(E)
+  5.898930 1<-- 13:  20( ) 39(9) 32(2) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.899815 -->1 131:  50(P) 30(0) 46(F) 90 91 0d 01 80 5c(\) 9f 4f(O) 90 93 0d 01 80  93 0c 01 78(x) 94 08 95 f8 94 80 91 0c 01 90 91 0d  01 81 34(4) 90 48(H) 54(T) f0 80 91 0c 01 90 91 0d 01 80  54(T) 91 09 90 93 0d 01 80 93 0c 01 78(x) 94 08 95 f8  94 90 93 0d 01 80 93 0c 01 78(x) 94 08 95 f8 94 80  91 0c 01 90 91 0d 01 78(x) 94 08 95 f8 94 20( ) 91 10  01 30(0) 91 11 01 80 91 0c 01 90 91 0d 01 aa 27(') 97  fd a0 95 ba 2f(/) 82 0f 93 1f a1 1d b1 1d 81 15 20( )  e8 92 07
+  5.923582 1<-- 3:  3d(=) 30(0) 46(F)
+  5.934886 1<-- 13:  20( ) 35(5) 31(1) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.936182 -->1 131:  50(P) 31(1) 30(0) a1 05 b1 05 14 f0 8f ef 9f e7 78(x) 94 08  95 21(!) b1 28(() 7f 80 91 0a 01 90 91 0b 01 89 2b(+) 49(I)  f0 80 91 0a 01 90 91 0b 01 01 97 90 93 0b 01 80  93 0a 01 80 91 08 01 90 91 09 01 82 31(1) 91 05 38(8)  f0 81 e0 90 e0 90 93 09 01 80 93 08 01 08 95 fc  01 e6 5d(]) ff 4f(O) 0c 94 73(s) 09 80 91 d5 00 81 60(`) 80  93 d5 00 0e 94 26(&) 02 8a e0 e5 ed f0 e0 ae e0 b1  e0 01 90 0d 92 8a 95 e1 f7 0e 94 20( ) 02 84 e9 86  bf 81 e1
+  5.959957 1<-- 3:  3d(=) 31(1) 30(0)
+  5.971249 1<-- 13:  20( ) 41(A) 34(4) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  5.972064 -->1 131:  50(P) 31(1) 31(1) 90 e0 90 93 09 01 80 93 08 01 84 e6 80  93 d4 00 08 95 80 91 d4 00 81 50(P) 80 93 d4 00 81  11 d5 cf 10 92 09 01 10 92 08 01 08 95 82 e0 90  e0 90 93 09 01 80 93 08 01 10 92 df 00 20( ) 91 d5  00 2e(.) 7f 20( ) 93 d5 00 30(0) 91 0e 01 36(6) 95 40(@) 91 0f  01 47(G) 95 44(D) 27(') 47(G) 95 84 2f(/) 83 2b(+) 30(0) 91 0f 01 93  2f(/) 96 95 01 96 38(8) 2f(/) 33(3) 0f 21(!) 70(p) 23(#) 2b(+) 20( ) 93 d5  00 99 0f 88 1f 88 27(') 88 1f 89 2b(+) 80 93 d6 00 08  95 8a ef
+  5.995871 1<-- 3:  3d(=) 31(1) 31(1)
+  6.007135 1<-- 13:  20( ) 38(8) 32(2) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.008641 -->1 131:  50(P) 31(1) 32(2) 90 e0 90 93 0b 01 80 93 0a 01 10 92 09  01 10 92 08 01 08 95 84 ea 86 bf 83 e0 90 e0 90  93 09 01 80 93 08 01 8a e0 80 93 d4 00 08 95 80  91 d4 00 81 50(P) 80 93 d4 00 28(() 30(0) 11 f0 20( ) 31(1) 01  f5 84 e0 90 e0 90 93 09 01 80 93 08 01 08 95 80  e9 83 b9 84 e8 86 bf 85 e0 90 e0 90 93 09 01 80  93 08 01 8a e0 80 93 d4 00 08 95 80 91 d4 00 81  50(P) 80 93 d4 00 28(() 31(1) 09 f4 cd c0 20( ) 32(2) 09 f4 60(`)  cf 88 23(#)
+  6.032429 1<-- 3:  3d(=) 31(1) 32(2)
+  6.043722 1<-- 13:  20( ) 37(7) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.044085 -->1 131:  50(P) 31(1) 33(3) 09 f4 5d(]) cf 08 95 80 91 df 00 83 b9 84  e8 86 bf 8a e0 80 93 d4 00 87 e0 90 e0 90 93 09  01 80 93 08 01 08 95 80 91 d4 00 81 50(P) 80 93 d4  00 28(() 32(2) 09 f4 a8 c0 20( ) 32(2) 19 f7 87 e0 90 e0 90  93 09 01 80 93 08 01 08 95 84 ea 86 bf 89 e0 90  e0 90 93 09 01 80 93 08 01 8a e0 80 93 d4 00 08  95 80 91 d4 00 81 50(P) 80 93 d4 00 20( ) 31(1) 49(I) f6 8a  e0 90 e0 90 93 09 01 80 93 08 01 08 95 81 e9 83  b9 84 e8
+  6.067882 1<-- 3:  3d(=) 31(1) 33(3)
+  6.079153 1<-- 13:  20( ) 45(E) 45(E) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.079542 -->1 131:  50(P) 31(1) 34(4) 86 bf 8b e0 90 e0 90 93 09 01 80 93 08  01 8a e0 80 93 d4 00 08 95 80 91 d4 00 81 50(P) 80  93 d4 00 20( ) 34(4) 09 f4 5b([) c0 28(() 33(3) 09 f4 09 cf 28(()  34(4) 09 f0 a6 cf 05 cf 84 ec 86 bf 8d e0 90 e0 90  93 09 01 80 93 08 01 8a e0 80 93 d4 00 08 95 80  91 d4 00 81 50(P) 80 93 d4 00 20( ) 35(5) 09 f0 91 cf 83  b1 e0 91 df 00 f0 e0 ee 0f ff 1f e9 52(R) ff 4f(O) 10  82 81 83 8e e0 90 e0 90 93 09 01 80 93 08 01 08  95 84 e8
+  6.103322 1<-- 3:  3d(=) 31(1) 34(4)
+  6.114599 1<-- 13:  20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.115339 -->1 131:  50(P) 31(1) 35(5) 86 bf 8f e0 90 e0 90 93 09 01 80 93 08  01 8a e0 80 93 d4 00 08 95 80 91 d4 00 81 50(P) 80  93 d4 00 28(() 35(5) 09 f0 6c(l) cf 20( ) 91 df 00 e2 2f(/) f0  e0 33(3) b1 ee 0f ff 1f e9 52(R) ff 4f(O) 80 81 91 81 83  2b(+) 91 83 80 83 81 e0 82 0f 80 93 df 00 84 30(0) 48(H)  f5 82 e0 90 e0 90 93 09 01 80 93 08 01 08 95 80  91 df 00 e8 2f(/) f0 e0 ee 0f ff 1f e9 52(R) ff 4f(O) 11  82 10 82 81 30(0) 09 f4 bd cf 8c e0 90 e0 90 93 09  01 80 93
+  6.139197 1<-- 3:  3d(=) 31(1) 35(5)
+  6.150484 1<-- 13:  20( ) 44(D) 44(D) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.151537 -->1 131:  50(P) 31(1) 36(6) 08 01 08 95 88 e0 90 e0 90 93 09 01 80  93 08 01 08 95 86 e0 90 e0 90 93 09 01 80 93 08  01 08 95 80 e1 90 e0 90 93 09 01 80 93 08 01 08  95 0e 94 be 01 0e 94 a6 03 0e 94 dc 00 8c e7 90  e0 9f 93 8f 93 85 e8 90 e0 9f 93 8f 93 81 e9 90  e0 9f 93 8f 93 85 ec 90 e0 9f 93 8f 93 0e 94 99  0a 0e 94 2f(/) 02 78(x) 94 8d b7 9e b7 08 96 0f b6 f8  94 9e bf 0f be 8d bf 0e 94 f3 01 0e 94 b5 03 0e  94 e3 00
+  6.175354 1<-- 3:  3d(=) 31(1) 36(6)
+  6.186634 1<-- 13:  20( ) 36(6) 33(3) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.187466 -->1 131:  50(P) 31(1) 37(7) f9 cf a3 e1 b0 e0 e7 ec f5 e0 0c 94 3c(<)  09 7c(|) 01 1b 01 6a(j) 01 fc 01 17 82 16 82 83 81 81  ff 66(f) c3 be 01 6f(o) 5f(_) 7f 4f(O) 4b(K) 01 f7 01 93 81 f1  01 93 fd 85 91 93 ff 81 91 1f 01 88 23(#) 09 f4 53(S)  c3 85 32(2) 39(9) f4 93 fd 85 91 93 ff 81 91 1f 01 85  32(2) 39(9) f4 b7 01 90 e0 0e 94 67(g) 0a 56(V) 01 65(e) 01 e5  cf 10 e0 51(Q) 2c(,) 20( ) e0 20( ) 32(2) a0 f4 8b 32(2) 69(i) f0 30(0)  f4 80 32(2) 59(Y) f0 83 32(2) 69(i) f4 20( ) 61(a) 2c(,) c0 8d 32(2) 39(9)  f0 80 33(3)
+  6.211279 1<-- 3:  3d(=) 31(1) 37(7)
+  6.222544 1<-- 13:  20( ) 39(9) 35(5) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.223978 -->1 131:  50(P) 31(1) 38(8) 39(9) f4 21(!) 60(`) 26(&) c0 22(") 60(`) 24($) 60(`) 23(#) c0 28(()  60(`) 21(!) c0 27(') fd 27(') c0 30(0) ed 38(8) 0f 3a(:) 30(0) 78(x) f4 26(&)  ff 06 c0 fa e0 1f 9f 30(0) 0d 11 24($) 13 2f(/) 13 c0 6a(j)  e0 56(V) 9e 30(0) 0d 11 24($) 53(S) 2e(.) 20( ) 62(b) 0c c0 8e 32(2) 21(!)  f4 26(&) fd 11 c3 20( ) 64(d) 06 c0 8c 36(6) 11 f4 20( ) 68(h) 02  c0 88 36(6) 41(A) f4 f1 01 93 fd 85 91 93 ff 81 91 1f  01 81 11 c1 cf 9b eb 98 0f 93 30(0) 18 f4 20( ) 61(a) 80  5e(^) 06 c0 9b e9 98 0f 93 30(0) 08 f0 aa c1 2f(/) 7e(~) 26(&)  ff 16 e0
+  6.247765 1<-- 3:  3d(=) 31(1) 38(8)
+  6.259098 1<-- 13:  20( ) 38(8) 36(6) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.259952 -->1 131:  50(P) 31(1) 39(9) 2f(/) 73(s) 72(r) 2e(.) 85 36(6) 21(!) f4 f2 2f(/) f0 64(d) 7f  2e(.) 08 c0 86 36(6) 21(!) f4 62(b) 2f(/) 60(`) 68(h) 76(v) 2e(.) 02 c0 11  11 11 50(P) 77(w) fe 07 c0 1c 33(3) 48(H) f4 44(D) 24($) 43(C) 94 41(A)  0e 27(') e0 0b c0 18 30(0) 30(0) f4 21(!) 2f(/) 06 c0 27(') e0 4c(L)  e3 44(D) 2e(.) 03 c0 27(') e0 17 e0 41(A) 2c(,) 56(V) 01 74(t) e0 a7  0e b1 1c f6 01 60(`) 81 71(q) 81 82 81 93 81 04 2d(-) a4  01 0e 94 79(y) 09 6c(l) 01 09 81 00 ff 02 c0 03 ff 06  c0 71(q) fc 07 c0 72(r) fc 08 c0 61(a) 2c(,) 08 c0 3d(=) e2 63(c)  2e(.) 05 c0
+  6.283748 1<-- 3:  3d(=) 31(1) 39(9)
+  6.295040 1<-- 13:  20( ) 34(4) 41(A) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.296018 -->1 131:  50(P) 31(1) 41(A) 2b(+) e2 62(b) 2e(.) 02 c0 90 e2 69(i) 2e(.) 80 2f(/) 8c  70(p) 99 f1 66(f) 20( ) 11 f0 84 e0 01 c0 83 e0 85 15 10  f0 51(Q) 2c(,) 0b c0 58(X) 1a 73(s) fc 08 c0 b7 01 80 e2 90  e0 0e 94 67(g) 0a 5a(Z) 94 c9 f7 f3 cf 66(f) 20( ) 29()) f0 b7  01 86 2d(-) 90 e0 0e 94 67(g) 0a 03 fd 03 c0 0c e7 10  e0 02 c0 08 e7 10 e0 f7 2d(-) f0 71(q) 7f 2e(.) f8 01 84  91 88 23(#) 09 f4 76(v) c2 71(q) 10 80 52(R) b7 01 90 e0 0e  94 67(g) 0a 0f 5f(_) 1f 4f(O) f2 cf 77(w) fe 0f c0 4c(L) 0c 04  ff 04 c0
+  6.319825 1<-- 3:  3d(=) 31(1) 41(A)
+  6.331064 1<-- 13:  20( ) 43(C) 36(6) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.331530 -->1 131:  50(P) 31(1) 42(B) 8a 81 81 33(3) 09 f4 4a(J) 94 14 14 74(t) f5 f8  e0 f4 15 78(x) f5 88 e0 48(H) 2e(.) 2c(,) c0 76(v) fc 2a(*) c0 81  2f(/) 90 e0 8c 15 9d 05 9c f0 6c(l) ef c6 16 6f(o) ef d6  06 74(t) f0 77(w) 2d(-) 70(p) 68(h) 77(w) 2e(.) 0a c0 e2 e0 f0 e0 ec  0f fd 1f e1 0f f1 1d 80 81 80 33(3) 19 f4 11 50(P) 11  11 f4 cf 77(w) fe 0e c0 44(D) 24($) 43(C) 94 41(A) 0e 81 2f(/) 90  e0 c8 16 d9 06 2c(,) f4 1c 19 04 c0 44(D) 24($) 43(C) 94 01  c0 10 e0 77(w) fe 07 c0 1c 14 1d 04 3c(<) f4 96 01 2f(/)  5f(_) 3f(?) 4f(O)
+  6.355311 1<-- 3:  3d(=) 31(1) 42(B)
+  6.366603 1<-- 13:  20( ) 32(2) 33(3) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.367325 -->1 131:  50(P) 31(1) 43(C) 05 c0 25(%) e0 30(0) e0 02 c0 21(!) e0 30(0) e0 66(f)  20( ) 11 f0 2f(/) 5f(_) 3f(?) 4f(O) 11 23(#) 31(1) f0 41(A) 2f(/) 50(P) e0 4f(O)  5f(_) 5f(_) 4f(O) 24($) 0f 35(5) 1f 45(E) 2d(-) 50(P) e0 24($) 17 35(5) 07 14  f4 52(R) 1a 01 c0 51(Q) 2c(,) 87 2d(-) 89 70(p) 49(I) f4 55(U) 20( ) 39(9)  f0 b7 01 80 e2 90 e0 0e 94 67(g) 0a 5a(Z) 94 f7 cf 66(f)  20( ) 29()) f0 b7 01 86 2d(-) 90 e0 0e 94 67(g) 0a 73(s) fc 09  c0 55(U) 20( ) 39(9) f0 b7 01 80 e3 90 e0 0e 94 67(g) 0a 5a(Z)  94 f7 cf 77(w) fe 5f(_) c0 9c 2d(-) 8d 2d(-) d7 fe 02 c0 90  e0 80 e0
+  6.391199 1<-- 3:  3d(=) 31(1) 43(C)
+  6.402468 1<-- 13:  20( ) 46(F) 46(F) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.403375 -->1 131:  50(P) 31(1) 44(D) 69(i) 2e(.) 78(x) 2e(.) 40(@) e0 50(P) e0 c6 01 84 19 91  09 9d 87 8c 87 96 01 26(&) 19 37(7) 09 28(() 0d 39(9) 1d 81  2f(/) 90 e0 ee 27(') ff 27(') e8 1b f9 0b ff 87 ee 87 ff  ef 6f(o) 16 7f 06 69(i) f4 b7 01 8e e2 90 e0 2b(+) 8b 3a(:)  8b 48(H) 8b 59(Y) 8b 0e 94 67(g) 0a 59(Y) 89 48(H) 89 3a(:) 89 2b(+)  89 c6 14 d7 04 54(T) f0 6c(l) 85 7d(}) 85 66(f) 15 77(w) 05 2c(,)  f4 f9 01 e4 0f f5 1f 81 81 01 c0 80 e3 71(q) e0 67(g)  1a 71(q) 08 4f(O) 5f(_) 5f(_) 4f(O) ee 85 ff 85 6e(n) 16 7f 06 6c(l)  f0 b7 01
+  6.427193 1<-- 3:  3d(=) 31(1) 44(D)
+  6.438514 1<-- 13:  20( ) 30(0) 31(1) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.439110 -->1 131:  50(P) 31(1) 45(E) 90 e0 2b(+) 8b 3a(:) 8b 48(H) 8b 59(Y) 8b 0e 94 67(g)  0a 2b(+) 89 3a(:) 89 48(H) 89 59(Y) 89 ca cf 6c(l) 14 7d(}) 04 39(9)  f4 9a 81 96 33(3) 18 f4 95 33(3) 11 f4 04 ff 81 e3 b7  01 90 e0 4b(K) c0 8a 81 81 33(3) 09 f0 0f 7e(~) b7 01 90  e0 0e 94 67(g) 0a 11 11 05 c0 74(t) fe 18 c0 85 e4 90  e0 17 c0 b7 01 8e e2 90 e0 0e 94 67(g) 0a 82 e0 66(f)  24($) 63(c) 94 68(h) 0e f4 01 e8 0f f1 1d 80 81 b7 01 90  e0 0e 94 67(g) 0a 11 50(P) 41(A) f3 86 2d(-) f1 cf 85 e6 90  e0 b7 01
+  6.462928 1<-- 3:  3d(=) 31(1) 45(E)
+  6.474205 1<-- 13:  20( ) 33(3) 33(3) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.474761 -->1 131:  50(P) 31(1) 46(F) 0e 94 67(g) 0a d7 fc 05 c0 c1 14 d1 04 39(9)  f4 04 ff 05 c0 d1 94 c1 94 d1 08 8d e2 01 c0 8b  e2 b7 01 90 e0 0e 94 67(g) 0a 80 e3 6a(j) e0 c6 16 d1  04 2c(,) f0 8f 5f(_) fa e0 cf 1a d1 08 f7 cf b7 01 90  e0 0e 94 67(g) 0a b7 01 c6 01 c0 96 0e 94 67(g) 0a 41(A)  c1 83 36(6) 31(1) f0 83 37(7) 79(y) f0 83 35(5) 09 f0 58(X) c0 21(!)  c0 56(V) 01 72(r) e0 a7 0e b1 1c f6 01 80 81 89 83 01  e0 10 e0 64(d) 01 14 c0 56(V) 01 f2 e0 af 0e b1 1c f6  01 c0 80
+  6.498561 1<-- 3:  3d(=) 31(1) 46(F)
+  6.509854 1<-- 13:  20( ) 36(6) 45(E) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.510369 -->1 131:  50(P) 32(2) 30(0) d1 80 26(&) ff 03 c0 61(a) 2f(/) 70(p) e0 02 c0 6f(o)  ef 7f ef c6 01 2b(+) 8b 0e 94 5c(\) 0a 8c 01 2b(+) 89 2f(/)  77(w) 15 c0 56(V) 01 f2 e0 af 0e b1 1c f6 01 c0 80 d1  80 26(&) ff 03 c0 61(a) 2f(/) 70(p) e0 02 c0 6f(o) ef 7f ef c6  01 2b(+) 8b 0e 94 51(Q) 0a 8c 01 2b(+) 89 20( ) 68(h) 72(r) 2e(.) 23(#)  fd 1a c0 85 2d(-) 90 e0 08 17 19 07 a8 f4 b7 01 80  e2 90 e0 0e 94 67(g) 0a 5a(Z) 94 f4 cf f6 01 77(w) fc 85  91 77(w) fe 81 91 6f(o) 01 b7 01 90 e0 0e 94 67(g) 0a 51(Q)  10 5a(Z) 94
+  6.534187 1<-- 3:  3d(=) 32(2) 30(0)
+  6.545496 1<-- 13:  20( ) 41(A) 32(2) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.546344 -->1 131:  50(P) 32(2) 31(1) 01 50(P) 11 09 01 15 11 05 79(y) f7 e2 c0 84  36(6) 11 f0 89 36(6) 51(Q) f5 56(V) 01 27(') ff 09 c0 f4 e0 af  0e b1 1c f6 01 60(`) 81 71(q) 81 82 81 93 81 0a c0 f2  e0 af 0e b1 1c f6 01 60(`) 81 71(q) 81 88 27(') 77(w) fd 80  95 98 2f(/) 02 2f(/) 0f 76(v) 97 ff 08 c0 90 95 80 95 70(p)  95 61(a) 95 7f 4f(O) 8f 4f(O) 9f 4f(O) 00 68(h) 2a(*) e0 30(0) e0 a4  01 0e 94 0a 0b c8 2e(.) c8 18 3e(>) c0 02 2f(/) 85 37(7) 21(!)  f4 0f 7e(~) 2a(*) e0 30(0) e0 1d c0 09 7f 8f 36(6) 91 f0 18  f4 88 35(5)
+  6.570194 1<-- 3:  3d(=) 32(2) 31(1)
+  6.581492 1<-- 13:  20( ) 38(8) 46(F) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.582275 -->1 131:  50(P) 32(2) 32(2) 59(Y) f0 b0 c0 80 37(7) 19 f0 88 37(7) 11 f0 ab  c0 00 61(a) 04 ff 09 c0 04 60(`) 07 c0 24($) ff 08 c0 06  60(`) 06 c0 28(() e0 30(0) e0 05 c0 20( ) e1 30(0) e0 02 c0 20( )  e1 32(2) e0 56(V) 01 07 ff 09 c0 f4 e0 af 0e b1 1c f6  01 60(`) 81 71(q) 81 82 81 93 81 08 c0 f2 e0 af 0e b1  1c f6 01 60(`) 81 71(q) 81 80 e0 90 e0 a4 01 0e 94 0a  0b c8 2e(.) c8 18 0f 77(w) 06 ff 0b c0 20( ) 2f(/) 2e(.) 7f c1  16 50(P) f4 04 ff 0a c0 02 fd 08 c0 20( ) 2f(/) 2e(.) 7e(~) 05  c0 dc 2c(,)
+  6.606080 1<-- 3:  3d(=) 32(2) 32(2)
+  6.617361 1<-- 13:  20( ) 46(F) 34(4) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.618049 -->1 131:  50(P) 32(2) 33(3) 20( ) 2f(/) 03 c0 dc 2c(,) 01 c0 d1 2e(.) 24($) ff 0d  c0 fe 01 ec 0d f1 1d 80 81 80 33(3) 11 f4 29()) 7e(~) 09  c0 22(") ff 06 c0 d3 94 d3 94 04 c0 82 2f(/) 86 78(x) 09  f0 d3 94 23(#) fd 13 c0 20( ) ff 06 c0 1c 2d(-) d5 14 18  f4 15 0d 1d 19 d5 2c(,) d5 14 68(h) f4 b7 01 80 e2 90  e0 2b(+) 8b 0e 94 67(g) 0a d3 94 2b(+) 89 f5 cf d5 14 10  f4 5d(]) 18 01 c0 51(Q) 2c(,) 24($) ff 12 c0 b7 01 80 e3 90  e0 2b(+) 8b 0e 94 67(g) 0a 2b(+) 89 22(") ff 17 c0 21(!) ff 03  c0 88 e5
+  6.641870 1<-- 3:  3d(=) 32(2) 33(3)
+  6.653120 1<-- 13:  20( ) 34(4) 43(C) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.653953 -->1 131:  50(P) 32(2) 34(4) 90 e0 02 c0 88 e7 90 e0 b7 01 0c c0 82  2f(/) 86 78(x) 59(Y) f0 21(!) fd 02 c0 80 e2 01 c0 8b e2 27(')  fd 8d e2 b7 01 90 e0 0e 94 67(g) 0a c1 16 38(8) f4 b7  01 80 e3 90 e0 0e 94 67(g) 0a 11 50(P) f7 cf ca 94 f4  01 ec 0d f1 1d 80 81 b7 01 90 e0 0e 94 67(g) 0a c1  10 f5 cf 55(U) 20( ) 09 f4 c2 cc b7 01 80 e2 90 e0 0e  94 67(g) 0a 5a(Z) 94 f6 cf f7 01 86 81 97 81 02 c0 8f  ef 9f ef 63(c) 96 e2 e1 0c 94 58(X) 09 2f(/) 92 3f(?) 92 4f(O)  92 5f(_) 92
+  6.677750 1<-- 3:  3d(=) 32(2) 34(4)
+  6.689043 1<-- 13:  20( ) 31(1) 34(4) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.689453 -->1 131:  50(P) 32(2) 35(5) 6f(o) 92 7f 92 8f 92 9f 92 af 92 bf 92 cf  92 df 92 ef 92 ff 92 0f 93 1f 93 cf 93 df 93 cd  b7 de b7 ca 1b db 0b 0f b6 f8 94 de bf 0f be cd  bf 09 94 2a(*) 88 39(9) 88 48(H) 88 5f(_) 84 6e(n) 84 7d(}) 84 8c  84 9b 84 aa 84 b9 84 c8 84 df 80 ee 80 fd 80 0c  81 1b 81 aa 81 b9 81 ce 0f d1 1d 0f b6 f8 94 de  bf 0f be cd bf ed 01 08 95 ee 0f ff 1f 05 90 f4  91 e0 2d(-) 09 94 28(() 30(0) 08 f0 27(') e0 33(3) 27(') da 01 99  0f 31(1) 1d
+  6.713262 1<-- 3:  3d(=) 32(2) 35(5)
+  6.724558 1<-- 13:  20( ) 39(9) 46(F) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.725378 -->1 131:  50(P) 32(2) 36(6) 87 fd 91 60(`) 00 96 61(a) 05 71(q) 05 39(9) f4 32(2)  60(`) 2e(.) 5f(_) 3d(=) 93 30(0) e3 2a(*) 95 e1 f7 08 95 9f 3f(?) 30(0)  f0 80 38(8) 71(q) 05 61(a) 05 09 f0 3c(<) 5f(_) 3c(<) 5f(_) 3d(=) 93 91  30(0) 08 f0 80 68(h) 91 1d df 93 cf 93 1f 93 0f 93 ff  92 ef 92 19 2f(/) 98 7f 96 95 e9 2f(/) 96 95 96 95 e9  0f ff 27(') e6 52(R) ff 4f(O) 99 27(') 33(3) 27(') ee 24($) ff 24($) a7  01 e7 01 05 90 08 94 07 94 28(() f4 36(6) 0f e7 1e f8  1e 49(I) 1f 51(Q) 1d 66(f) 0f 77(w) 1f 88 1f 99 1f 06 94 a1  f7 05 90
+  6.749208 1<-- 3:  3d(=) 32(2) 36(6)
+  6.760478 1<-- 13:  20( ) 32(2) 45(E) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.761002 -->1 131:  50(P) 32(2) 37(7) 07 94 28(() f4 e7 0e f8 1e 49(I) 1f 56(V) 1f c1  1d 77(w) 0f 88 1f 99 1f 66(f) 1f 06 94 a1 f7 05 90 07  94 28(() f4 f8 0e 49(I) 1f 56(V) 1f c7 1f d1 1d 88 0f 99  1f 66(f) 1f 77(w) 1f 06 94 a1 f7 05 90 07 94 20( ) f4 49(I)  0f 56(V) 1f c7 1f d8 1f 99 0f 66(f) 1f 77(w) 1f 88 1f 06  94 a9 f7 84 91 10 95 17 70(p) 41(A) f0 d6 95 c7 95 57(W)  95 47(G) 95 f7 94 e7 94 1a 95 c1 f7 e0 e8 f0 e0 68(h)  94 15 90 15 91 35(5) 91 65(e) 91 95 91 05 90 7f e2 73(s)  95 e1 18
+  6.784776 1<-- 3:  3d(=) 32(2) 37(7)
+  6.796079 1<-- 13:  20( ) 37(7) 30(0) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.796677 -->1 131:  50(P) 32(2) 38(8) f1 0a 43(C) 0b 56(V) 0b c9 0b d0 09 c0 f7 e1  0c f1 1e 43(C) 1f 56(V) 1f c9 1f d0 1d 7e(~) f4 70(p) 33(3) 11  f4 8a 95 e6 cf e8 94 01 50(P) 30(0) f0 08 0f 0a f4 00  27(') 02 17 08 f4 20( ) 2f(/) 23(#) 95 02 2f(/) 7a(z) 33(3) 28(() f0 79(y)  e3 7d(}) 93 2a(*) 95 e9 f7 10 c0 7d(}) 93 2a(*) 95 89 f6 06  94 97 95 67(g) 95 37(7) 95 17 95 17 94 e1 18 f1 0a 43(C)  0b 56(V) 0b c9 0b d0 09 98 f0 23(#) 95 7e(~) 91 73(s) 95 7a(z)  33(3) 08 f0 70(p) e3 7c(|) 93 20( ) 13 b8 f7 7e(~) 91 70(p) 61(a) 7d(})  93 30(0) f0
+  6.820485 1<-- 3:  3d(=) 32(2) 38(8)
+  6.831781 1<-- 13:  20( ) 38(8) 44(D) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.832806 -->1 131:  50(P) 32(2) 39(9) 83 95 71(q) e3 7d(}) 93 70(p) e3 2a(*) 95 e1 f7 11  24($) ef 90 ff 90 0f 91 1f 91 cf 91 df 91 99 27(') 87  fd 90 95 08 95 fc 01 05 90 61(a) 50(P) 70(p) 40(@) 01 10 d8  f7 80 95 90 95 8e 0f 9f 1f 08 95 fc 01 61(a) 50(P) 70(p)  40(@) 01 90 01 10 d8 f7 80 95 90 95 8e 0f 9f 1f 08  95 0f 93 1f 93 cf 93 df 93 18 2f(/) 09 2f(/) eb 01 8b  81 81 fd 03 c0 8f ef 9f ef 20( ) c0 82 ff 10 c0 4e(N)  81 5f(_) 81 2c(,) 81 3d(=) 81 42(B) 17 53(S) 07 7c(|) f4 e8 81 f9  81 9f 01
+  6.856619 1<-- 3:  3d(=) 32(2) 39(9)
+  6.867899 1<-- 13:  20( ) 42(B) 32(2) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.868354 -->1 131:  50(P) 32(2) 41(A) 2f(/) 5f(_) 3f(?) 4f(O) 39(9) 83 28(() 83 10 83 06 c0 e8  85 f9 85 81 2f(/) 09 95 89 2b(+) 29()) f7 2e(.) 81 3f(?) 81 2f(/)  5f(_) 3f(?) 4f(O) 3f(?) 83 2e(.) 83 81 2f(/) 90 2f(/) df 91 cf 91 1f  91 0f 91 08 95 a0 e0 b0 e0 ef e9 fa e0 0c 94 4c(L)  09 fe 01 35(5) 96 61(a) 91 71(q) 91 af 01 80 91 1a 01 90  91 1b 01 0e 94 c1 05 e2 e0 0c 94 68(h) 09 0f 93 1f  93 cf 93 df 93 e0 91 1a 01 f0 91 1b 01 23(#) 81 21(!)  ff 1b c0 ec 01 00 e0 10 e0 89 91 60(`) 91 1a 01 70(p)  91 1b 01
+  6.892239 1<-- 3:  3d(=) 32(2) 41(A)
+  6.903458 1<-- 13:  20( ) 43(C) 43(C) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.903869 -->1 131:  50(P) 32(2) 42(B) db 01 18 96 ed 91 fc 91 19 97 88 23(#) 31(1)  f0 09 95 89 2b(+) 89 f3 0f ef 1f ef ee cf 8a e0 09  95 89 2b(+) 11 f4 c8 01 02 c0 8f ef 9f ef df 91 cf  91 1f 91 0f 91 08 95 ae e0 b0 e0 e0 ee fa e0 0c  94 4a(J) 09 0d 89 1e 89 8f 89 98 8d 26(&) e0 2c(,) 83 1a  83 09 83 97 ff 02 c0 80 e0 90 e8 01 97 9e 83 8d  83 ae 01 45(E) 5e(^) 5f(_) 4f(O) 69(i) 8d 7a(z) 8d ce 01 01 96 0e  94 c1 05 4d(M) 81 5e(^) 81 57(W) fd 0a c0 2f(/) 81 38(8) 85 42(B)  17 53(S) 07
+  6.927669 1<-- 3:  3d(=) 32(2) 42(B)
+  6.938937 1<-- 13:  20( ) 37(7) 44(D) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.939784 -->1 131:  50(P) 32(2) 43(C) 0c f4 9a 01 f8 01 e2 0f f3 1f 10 82 2e(.)  96 e4 e0 0c 94 66(f) 09 fa 01 aa 27(') 28(() 30(0) 51(Q) f1 20( )  31(1) 81 f1 e8 94 6f(o) 93 6e(n) 7f 6e(n) 5f(_) 7f 4f(O) 8f 4f(O) 9f  4f(O) af 4f(O) b1 e0 3e(>) d0 b4 e0 3c(<) d0 67(g) 0f 78(x) 1f 89  1f 9a 1f a1 1d 68(h) 0f 79(y) 1f 8a 1f 91 1d a1 1d 6a(j)  0f 71(q) 1d 81 1d 91 1d a1 1d 20( ) d0 09 f4 68(h) 94 3f(?)  91 2a(*) e0 26(&) 9f 11 24($) 30(0) 19 30(0) 5d(]) 31(1) 93 de f6 cf  01 08 95 46(F) 2f(/) 47(G) 70(p) 40(@) 5d(]) 41(A) 93 b3 e0 0f d0 c9  f7 f6 cf
+  6.963608 1<-- 3:  3d(=) 32(2) 43(C)
+  6.974900 1<-- 13:  20( ) 38(8) 35(5) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.975742 -->1 131:  50(P) 32(2) 44(D) 46(F) 2f(/) 4f(O) 70(p) 40(@) 5d(]) 4a(J) 33(3) 18 f0 49(I) 5d(]) 31(1)  fd 40(@) 52(R) 41(A) 93 02 d0 a9 f7 ea cf b4 e0 a6 95 97  95 87 95 77(w) 95 67(g) 95 ba 95 c9 f7 00 97 61(a) 05 71(q)  05 08 95 9b 01 ac 01 0a 2e(.) 06 94 57(W) 95 47(G) 95 37(7)  95 27(') 95 ba 95 c9 f7 62(b) 0f 73(s) 1f 84 1f 95 1f a0  1d 08 95 f8 94 ff cf 00 00 00 01 00 00 00 00 00  00 9c 01 00 00 00 00 00 02 00 00 00 00 b7 01 00  00 00 00 31(1) 31(1) 3a(:) 33(3) 32(2) 3a(:) 31(1) 31(1) 00 46(F) 65(e) 62(b) 20( )  32(2) 33(3) 20( )
+  6.999542 1<-- 3:  3d(=) 32(2) 44(D)
+  7.010818 1<-- 13:  20( ) 32(2) 38(8) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  7.011360 -->1 131:  50(P) 32(2) 45(E) 32(2) 30(0) 31(1) 36(6) 00 0a 0d 49(I) 32(2) 43(C) 2d(-) 54(T) 65(e)  6d(m) 70(p) 20( ) 4d(M) 65(e) 61(a) 73(s) 00 25(%) 30(0) 32(2) 78(x) 20( ) 2d(-) 3e(>) 20( )  25(%) 30(0) 32(2) 58(X) 0a 00 25(%) 30(0) 32(2) 58(X) 00 4c(L) 52(R) 43(C) 20( ) 4f(O)  4b(K) 00 4c(L) 52(R) 43(C) 20( ) 45(E) 72(r) 72(r) 6f(o) 72(r) 00 25(%) 73(s) 20( ) 25(%)  73(s) 20( ) 25(%) 73(s) 0a 0d 00 00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  00 00 00
+  7.035202 1<-- 3:  3d(=) 32(2) 45(E)
+  7.046457 1<-- 13:  20( ) 33(3) 45(E) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  7.055935 -->1 1:  46(F)
+  7.055945 -->1 1:  46(F)
+  7.055960 -->1 1:  46(F)
+  7.057064 1<-- 1:  58(X)
+  7.314492 1<-- 40:  0a 0d 49(I) 32(2) 43(C) 2d(-) 54(T) 65(e) 6d(m) 70(p) 20( ) 4d(M) 65(e) 61(a) 73(s) 20( )  46(F) 65(e) 62(b) 20( ) 32(2) 33(3) 20( ) 32(2) 30(0) 31(1) 36(6) 20( ) 31(1) 31(1) 3a(:) 33(3)  32(2) 3a(:) 31(1) 31(1) 0a 0d 0a 0d
diff --git a/jssc-2.8.0.jar b/jssc-2.8.0.jar
new file mode 100644 (file)
index 0000000..d2b5c07
Binary files /dev/null and b/jssc-2.8.0.jar differ
diff --git a/manifest.mf b/manifest.mf
new file mode 100644 (file)
index 0000000..328e8e5
--- /dev/null
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/measurements/2016-03-04-download-problem/logs b/measurements/2016-03-04-download-problem/logs
new file mode 100644 (file)
index 0000000..5c119aa
--- /dev/null
@@ -0,0 +1,44 @@
+INFO   *13:24:27.539: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.539: response '=13 26 00 00<0d><0a>f>' received for flash page 13 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:243)]
+FINER   13:24:27.541: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.541: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.565: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+INFO   *13:24:27.566: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.576: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.576: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.577: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.607: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.607: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.608: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.642: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.642: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.642: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.674: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.674: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.674: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.708: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+FINER   13:24:27.708: writing flash page 14 [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.writeAndCheckPage(DownloadProtocol.java:220)]
+INFO   *13:24:27.708: waiting for pattern 'f>' [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:271)]
+INFO   *13:24:27.741: bytes received, '' in buffer, continue checking pattern [at at.htlkaindorf.sx.EasyProgrammer.serial.Protocol.readResponseString(Protocol.java:282)]
+WARNING 13:24:27.742:  [at at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol.download(DownloadProtocol.java:135)]
+--------------------------------------------------------------------------------
+java.lang.Exception: Bootloader Error (unexpected response)
+
+
+
+  6.847062 1<-- 3:  3d(=) 31(1) 32(2)
+  6.859050 1<-- 13:  20( ) 45(E) 42(B) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  6.865310 -->1 1:  50(P)
+  6.865333 -->1 1:  31(1)
+  6.866546 -->1 129:  33(3) 2f(/) 93 3f(?) 93 4f(O) 93 5f(_) 93 6f(o) 93 7f 93 8f 93 9f  93 af 93 bf 93 ef 93 ff 93 80 91 df 00 8f 5f(_) 85  30(0) e0 f1 10 92 df 00 80 91 de 00 8f 5f(_) 80 93 de  00 80 91 dd 00 88 23(#) c1 f0 80 91 04 01 8f 3f(?) c1  f1 8f 5f(_) 80 93 04 01 ff 91 ef 91 bf 91 af 91 9f  91 8f 91 7f 91 6f(o) 91 5f(_) 91 4f(O) 91 3f(?) 91 2f(/) 91 0f  90 0f be 0f 90 1f 90 18 95 81 e0 80 93 dd 00 78(x)  94 80 91 de 00 80 fd 19 c0 81 fd 12 c0 82 fd 1d  c0
+  7.467351 -->1 1:  57(W)
+  7.469293 -->1 130:  31(1) 33(3) 2f(/) 93 3f(?) 93 4f(O) 93 5f(_) 93 6f(o) 93 7f 93 8f 93  9f 93 af 93 bf 93 ef 93 ff 93 80 91 df 00 8f 5f(_)  85 30(0) e0 f1 10 92 df 00 80 91 de 00 8f 5f(_) 80 93  de 00 80 91 dd 00 88 23(#) c1 f0 80 91 04 01 8f 3f(?)  c1 f1 8f 5f(_) 80 93 04 01 ff 91 ef 91 bf 91 af 91  9f 91 8f 91 7f 91 6f(o) 91 5f(_) 91 4f(O) 91 3f(?) 91 2f(/) 91  0f 90 0f be 0f 90 1f 90 18 95 81 e0 80 93 dd 00  78(x) 94 80 91 de 00 80 fd 19 c0 81 fd 12 c0 82 fd  1d c0
+  7.492102 1<-- 3:  3d(=) 31(1) 33(3)
+  7.503854 1<-- 13:  20( ) 32(2) 36(6) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  7.508264 -->1 1:  50(P)
+  7.508300 -->1 1:  31(1)
+  7.511312 -->1 129:  34(4) 83 fd 1e c0 84 fd 1f c0 85 fd 14 c0 86 fd 1e  c0 87 ff 08 c0 0e 94 a1 02 05 c0 80 93 df 00 d3  cf 0e 94 9b 02 10 92 dd 00 ce cf 0e 94 99 02 fa  cf 8f ef c7 cf 0e 94 9f 02 f5 cf 0e 94 9c 02 f2  cf 0e 94 9d 02 ef cf 0e 94 9e 02 ec cf 0e 94 a0  02 e9 cf 80 e1 e9 e1 f1 e0 df 01 1d 92 8a 95 e9  f7 16 be 82 e1 80 b9 81 e0 81 b9 84 e0 86 bf 08  95 08 95 f8 94 80 91 1d 01 90 91 1e 01 8f 3b(;) 9f  47(G)
+  7.526238 1<-- 3:  3d(=) 31(1) 8f
+  7.537936 1<-- 13:  20( ) 35(5) 45(E) 20( ) 30(0) 30(0) 20( ) 30(0) 30(0) 0d 0a 66(f) 3e(>)
+  7.543880 -->1 1:  57(W)
+  7.543952 -->1 1:  31(1)
diff --git a/measurements/2016-03-04-download-problem/p10i.png b/measurements/2016-03-04-download-problem/p10i.png
new file mode 100644 (file)
index 0000000..1d6ac5e
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p10i.png differ
diff --git a/measurements/2016-03-04-download-problem/p11i.png b/measurements/2016-03-04-download-problem/p11i.png
new file mode 100644 (file)
index 0000000..bf40884
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p11i.png differ
diff --git a/measurements/2016-03-04-download-problem/p12.png b/measurements/2016-03-04-download-problem/p12.png
new file mode 100644 (file)
index 0000000..354b2d4
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p12.png differ
diff --git a/measurements/2016-03-04-download-problem/p13.png b/measurements/2016-03-04-download-problem/p13.png
new file mode 100644 (file)
index 0000000..758c54d
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p13.png differ
diff --git a/measurements/2016-03-04-download-problem/p14i.png b/measurements/2016-03-04-download-problem/p14i.png
new file mode 100644 (file)
index 0000000..35568f8
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p14i.png differ
diff --git a/measurements/2016-03-04-download-problem/p1i.png b/measurements/2016-03-04-download-problem/p1i.png
new file mode 100644 (file)
index 0000000..0ab7d27
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p1i.png differ
diff --git a/measurements/2016-03-04-download-problem/p2i.png b/measurements/2016-03-04-download-problem/p2i.png
new file mode 100644 (file)
index 0000000..bff103f
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p2i.png differ
diff --git a/measurements/2016-03-04-download-problem/p3i.png b/measurements/2016-03-04-download-problem/p3i.png
new file mode 100644 (file)
index 0000000..c2e5e9b
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p3i.png differ
diff --git a/measurements/2016-03-04-download-problem/p4i.png b/measurements/2016-03-04-download-problem/p4i.png
new file mode 100644 (file)
index 0000000..3e7d4f8
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p4i.png differ
diff --git a/measurements/2016-03-04-download-problem/p5i.png b/measurements/2016-03-04-download-problem/p5i.png
new file mode 100644 (file)
index 0000000..aee0f38
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p5i.png differ
diff --git a/measurements/2016-03-04-download-problem/p6i.png b/measurements/2016-03-04-download-problem/p6i.png
new file mode 100644 (file)
index 0000000..abb9276
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p6i.png differ
diff --git a/measurements/2016-03-04-download-problem/p7i.png b/measurements/2016-03-04-download-problem/p7i.png
new file mode 100644 (file)
index 0000000..7bcbe39
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p7i.png differ
diff --git a/measurements/2016-03-04-download-problem/p8i.png b/measurements/2016-03-04-download-problem/p8i.png
new file mode 100644 (file)
index 0000000..1ab995b
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p8i.png differ
diff --git a/measurements/2016-03-04-download-problem/p9i.png b/measurements/2016-03-04-download-problem/p9i.png
new file mode 100644 (file)
index 0000000..0756a43
Binary files /dev/null and b/measurements/2016-03-04-download-problem/p9i.png differ
diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml
new file mode 100644 (file)
index 0000000..2fa8535
--- /dev/null
@@ -0,0 +1,1419 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - test compilation
+  - test execution
+  - test debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="easyprogrammer-impl">
+    <fail message="Please build using Ant 1.8.0 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.8.0"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <property name="platform.java" value="${java.home}/bin/java"/>
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="profile.available">
+            <and>
+                <isset property="javac.profile"/>
+                <length length="0" string="${javac.profile}" when="greater"/>
+                <matches pattern="1\.[89](\..*)?" string="${javac.source}"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <or>
+                <not>
+                    <istrue value="${jar.archive.disabled}"/>
+                </not>
+                <istrue value="${not.archive.disabled}"/>
+            </or>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+profile.available">
+            <and>
+                <isset property="profile.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <and>
+                <isset property="endorsed.classpath"/>
+                <not>
+                    <equals arg1="${endorsed.classpath}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="" property="javac.profile.cmd.line.arg" value="-profile ${javac.profile}">
+            <isset property="profile.available"/>
+        </condition>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="javac.fork">
+            <or>
+                <istrue value="${jdkBug6558476}"/>
+                <istrue value="${javac.external.vm}"/>
+            </or>
+        </condition>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <property name="copylibs.rebase" value="true"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+        <condition property="junit.available">
+            <or>
+                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+            </or>
+        </condition>
+        <condition property="testng.available">
+            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+        </condition>
+        <condition property="junit+testng.available">
+            <and>
+                <istrue value="${junit.available}"/>
+                <istrue value="${testng.available}"/>
+            </and>
+        </condition>
+        <condition else="testng" property="testng.mode" value="mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <condition else="" property="testng.debug.mode" value="-mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <property name="java.failonerror" value="true"/>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.profile.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.profile.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-init">
+        <condition else="false" property="nb.junit.batch" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <not>
+                    <isset property="test.method"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="nb.junit.single" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <isset property="test.method"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-init-test-properties">
+        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+        <property name="test.binarytestincludes" value=""/>
+        <property name="test.binaryexcludes" value=""/>
+    </target>
+    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+    <target if="${testng.available}" name="-init-macrodef-testng">
+        <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+                    <isset property="test.method"/>
+                </condition>
+                <union id="test.set">
+                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+                        <filename name="@{testincludes}"/>
+                    </fileset>
+                </union>
+                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="easyprogrammer" testname="TestNG tests" workingDir="${work.dir}">
+                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+                    <propertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </propertyset>
+                    <customize/>
+                </testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-test-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <echo>No tests executed.</echo>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+        <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <sequential>
+                <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${testng.available}" name="-init-macrodef-testng-debug">
+        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element name="customize2" optional="true"/>
+            <sequential>
+                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+                    <isset property="test.method"/>
+                </condition>
+                <condition else="-suitename easyprogrammer -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                    <matches pattern=".*\.xml" string="@{testClass}"/>
+                </condition>
+                <delete dir="${build.test.results.dir}" quiet="true"/>
+                <mkdir dir="${build.test.results.dir}"/>
+                <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+                    <customize>
+                        <customize2/>
+                        <jvmarg value="-ea"/>
+                        <arg line="${testng.debug.mode}"/>
+                        <arg line="-d ${build.test.results.dir}"/>
+                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
+                        <arg line="${testng.cmd.args}"/>
+                    </customize>
+                </j2seproject3:debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element implicit="true" name="customize2" optional="true"/>
+            <sequential>
+                <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2/>
+                </j2seproject3:testng-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2>
+                        <syspropertyset>
+                            <propertyref prefix="test-sys-prop."/>
+                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                        </syspropertyset>
+                    </customize2>
+                </j2seproject3:testng-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+    <!--
+                pre NB7.2 profiling section; consider it deprecated
+            -->
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" failonerror="${java.failonerror}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <!--
+                end of pre NB7.2 profiling section
+            -->
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version &quot;${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <attribute default="jvm" name="jvm"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" failonerror="${java.failonerror}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <filtermapper>
+                            <replacestring from=" " to="%20"/>
+                        </filtermapper>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" excludeFromCopy="${copylibs.excludes}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}" excludes="${dist.archive.excludes}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: easyprogrammer was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+main.class.available" name="-do-jar-set-mainclass">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+profile.available" name="-do-jar-set-profile">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Profile" value="${javac.profile}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-create-manifest,-do-jar-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.mkdist" name="-do-jar-copylibs">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen" if="do.archive" name="-do-jar-jar" unless="do.mkdist">
+        <j2seproject1:jar manifest="${tmp.manifest.file}"/>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <condition else="" property="jar.usage.message" value="To run this application from the command line without Ant, try:${line.separator}${platform.java} -cp ${run.classpath.with.dist.jar} ${main.class}">
+            <isset property="main.class.available"/>
+        </condition>
+        <condition else="debug" property="jar.usage.level" value="info">
+            <isset property="main.class.available"/>
+        </condition>
+        <echo level="${jar.usage.level}" message="${jar.usage.message}"/>
+    </target>
+    <target depends="-do-jar-copylibs" if="do.archive" name="-do-jar-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-jar,-do-jar-delete-manifest" name="-do-jar-without-libraries"/>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-create-manifest,-do-jar-copy-manifest,-do-jar-set-mainclass,-do-jar-set-profile,-do-jar-set-splashscreen,-do-jar-copylibs,-do-jar-delete-manifest" name="-do-jar-with-libraries"/>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-without-libraries,-do-jar-with-libraries,-post-jar" name="-do-jar"/>
+    <target depends="init,compile,-pre-jar,-do-jar,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <!--
+                pre NB7.2 profiler integration
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                end of pre NB72 profiling section
+            -->
+    <target if="netbeans.home" name="-profile-check">
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+        <startprofiler/>
+        <antcall target="run"/>
+    </target>
+    <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcall target="run-single"/>
+    </target>
+    <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+    <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <startprofiler/>
+        <antcall target="test-single"/>
+    </target>
+    <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcal target="run-test-with-main"/>
+    </target>
+    <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <startprofiler/>
+        <antcall target="run-applet"/>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+            <and>
+                <isset property="endorsed.classpath.cmd.line.arg"/>
+                <not>
+                    <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <condition else="" property="bug5101868workaround" value="*.java">
+            <matches pattern="1\.[56](\..*)?" string="${java.version}"/>
+        </condition>
+        <javadoc additionalparam="-J-Dfile.encoding=${file.encoding} ${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="${bug5101868workaround},${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+            <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                TEST COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                TEST EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:test includes="${includes}" testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+    <!--
+                =======================
+                TEST DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: easyprogrammer was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <and>
+                <not>
+                    <isset property="already.built.${call.subproject}"/>
+                </not>
+                <available file="${call.script}"/>
+            </and>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/nbproject/configs/crumb_2.properties b/nbproject/configs/crumb_2.properties
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nbproject/configs/empty.properties b/nbproject/configs/empty.properties
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nbproject/configs/nano.properties b/nbproject/configs/nano.properties
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nbproject/configs/sure.properties b/nbproject/configs/sure.properties
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties
new file mode 100644 (file)
index 0000000..4eef77a
--- /dev/null
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=e013f057
+build.xml.script.CRC32=50389c62
+build.xml.stylesheet.CRC32=8064a381@1.75.2.48
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=e013f057
+nbproject/build-impl.xml.script.CRC32=034e3503
+nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48
diff --git a/nbproject/project.properties b/nbproject/project.properties
new file mode 100644 (file)
index 0000000..2625832
--- /dev/null
@@ -0,0 +1,76 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=easyprogrammer
+application.vendor=steiner
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/easyprogrammer.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.jssc-2.8.0.jar=jssc-2.8.0.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${file.reference.jssc-2.8.0.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.external.vm=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+javac.test.processorpath=\
+    ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=at.htlkaindorf.sx.EasyProgrammer.gui.EasyProgrammer
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/nbproject/project.xml b/nbproject/project.xml
new file mode 100644 (file)
index 0000000..0be439a
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>easyprogrammer</name>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+    </configuration>
+</project>
diff --git a/released/easyprogrammer.jar b/released/easyprogrammer.jar
new file mode 100644 (file)
index 0000000..1998e82
Binary files /dev/null and b/released/easyprogrammer.jar differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/ByteFifo.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/ByteFifo.java
new file mode 100644 (file)
index 0000000..88e3926
--- /dev/null
@@ -0,0 +1,113 @@
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+/**
+ *
+ * @author steiner
+ */
+public class ByteFifo
+{
+  private final Object lock = new Object();
+  private byte [] buffer;
+  private int wIndex;
+  private int rIndex;
+  private int available;
+
+
+  public ByteFifo (int size)
+  {
+    buffer = new byte [size];
+  }
+  
+  public void push (byte b)
+  {
+    synchronized (lock)
+    {
+      if (available == buffer.length)
+      {
+        byte [] oldBuffer = buffer;
+        buffer = new byte[buffer.length*2];
+        for (int i=0; i<available; i++)
+        {
+          int ri = (rIndex + i)%oldBuffer.length;
+          buffer[i] = oldBuffer[ri];
+        }
+        rIndex = 0;
+        wIndex = available;
+        buffer[available++] = b;
+      }
+      else
+      {
+        buffer[wIndex] = b;
+        available++;
+        if (wIndex>=buffer.length)
+          wIndex = 0;
+      }
+    }
+  }
+  
+  public void push (byte [] ba)
+  {
+    synchronized (lock)
+    {
+      if ((available+ba.length) >= buffer.length)
+      {
+        byte [] oldBuffer = buffer;
+        buffer = new byte[buffer.length*2];
+        for (int i=0; i<available; i++)
+        {
+          int ri = (rIndex + i)%oldBuffer.length;
+          buffer[i] = oldBuffer[ri];
+        }
+        rIndex = 0;
+        wIndex = available;
+        for (byte b : ba)
+          buffer[available++] = b;
+      }
+      else
+      {
+        for (byte b : ba)
+        {
+          buffer[wIndex++] = b;
+          if (wIndex>=buffer.length)
+            wIndex = 0;
+          available++;
+        }
+      }
+    }
+  }
+  
+  
+  public int pop ()
+  {
+    synchronized (lock)
+    {
+      if (available<=0)
+        return -1;
+      byte rv = buffer[rIndex++];
+      available--;
+      if (rIndex>=buffer.length)
+        rIndex = 0;
+      return rv<0 ? (int)rv+256 : (int)rv;
+    }
+  }
+  
+  
+  public int available ()
+  {
+    synchronized (lock)
+    {
+      return available;
+    }
+  }
+  
+  public void flush ()
+  {
+    synchronized (lock)
+    {
+      available = 0;
+      rIndex = 0;
+      wIndex = 0;
+    }
+  }
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/CpuTyp.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/CpuTyp.java
new file mode 100644 (file)
index 0000000..ecbddec
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+/**
+ *
+ * @author steiner
+ */
+public class CpuTyp
+{
+  public enum Typ {Unknown, UserSpecified, Atmega324P, Atmega328P,
+                   Atmega328, Atmega16, Atmega8L,
+                   AT90CAN128, Atmega1284P };
+
+  private Typ typ;
+  private int bootloaderSize;
+  private int flashSize;
+  private int pageSize;
+  private String resetCommand;
+
+  public CpuTyp(Typ typ)
+  {
+    this.typ = typ;
+  }
+
+
+  public CpuTyp(Typ typ, int bootloaderSize, String resetCommand)
+  {
+    this.typ = typ;
+    this.bootloaderSize = bootloaderSize;
+    this.resetCommand = resetCommand;
+  }
+
+
+  public int getFlashSize ()
+  {
+    switch (typ)
+    {
+      case Atmega8L:    return   8*1024;
+      case Atmega16:    return  16*1024;
+      case Atmega324P:  return  32*1024;
+      case Atmega328 :  return  32*1024;
+      case Atmega328P:  return  32*1024;
+      case AT90CAN128:  return  0x20000;
+      case Atmega1284P: return 128*1024;
+      case UserSpecified: if (this.flashSize>0) return this.flashSize; break;
+    }
+    throw new RuntimeException("CPU-Typ not known");
+  }
+
+
+  public int getPageSize ()
+  {
+    switch (typ)
+    {
+      case Atmega8L:    return  64;
+      case Atmega16:    return 128;
+      case Atmega324P:  return 128;
+      case Atmega328 :  return 128;
+      case Atmega328P:  return 128;
+      case AT90CAN128:  return 256;
+      case Atmega1284P: return 256;
+      case UserSpecified: if (this.pageSize>0) return this.pageSize; break;
+    }
+    throw new RuntimeException("CPU-Typ not known");
+  }
+
+  public int getPages () throws Exception
+  {
+    return this.getFlashSize()/this.getPageSize();
+  }
+
+  public String getName ()
+  {
+    if (this.typ != Typ.Unknown)
+      return this.typ.toString();
+    throw new RuntimeException("CPU-Typ not known");
+  }
+  
+  public String getDescription ()
+  {
+    return String.format("%s (%dKiB, %d Bytes per Page)", typ.name(), getFlashSize()/1024, getPageSize());
+  }
+
+  public String[] getAvailableNames ()
+  {
+    String [] s = new String[Typ.values().length-1];
+    
+    int i=0;
+    for (Typ t : Typ.values())
+    {
+      if (t != Typ.Unknown && t != Typ.UserSpecified)
+        s[i++] = t.toString();
+    }
+
+    return s;
+  }
+
+
+  public void setTyp(Typ typ)
+  {
+    this.typ = typ;
+  }
+
+  public void setTyp(String typName) throws Exception
+  {
+    for (Typ t : Typ.values())
+    {
+      if (t != Typ.Unknown && typName.equals(t.toString()))
+      {
+        this.typ = t;
+        return;
+      }
+    }
+    throw new Exception("CPU-Typ not known");
+  }
+
+  
+  public String getResetCommand ()
+  {
+    return resetCommand;
+  }
+
+  
+  public void setResetCommand (String resetCommand)
+  {
+    this.resetCommand = resetCommand;
+  }
+  
+  public void setBootloaderSize(int bootloaderSize)
+  {
+    this.bootloaderSize = bootloaderSize;
+  }
+
+  public int getBootloaderSize ()
+  {
+    return bootloaderSize;
+  }  
+
+  public int getBootloaderSizeIndex () throws Exception
+  {
+    switch (typ)
+    {
+      case Atmega8L:
+      case Atmega16:
+      case Atmega324P:
+      case Atmega328:
+      case Atmega328P:
+      case AT90CAN128:
+        switch (bootloaderSize)
+        {
+          case    0: return 0;
+          case  512: return 1;
+          case 1024: return 2;
+          case 2048: return 3;
+          default: throw new Exception("Unvalid Bootloader size");
+        }
+    }
+    throw new RuntimeException("CPU-Typ not known");
+  }  
+  
+  
+  public int getBootloaderBytes (int index) throws Exception
+  {
+    switch (typ)
+    {
+      case Atmega1284P:
+        switch (index)
+        {
+          case 0: return 1024;
+          case 1: return 2048;
+          case 2: return 4096;
+          case 3: return 8192;
+          default: throw new Exception ("index out of range");
+        }
+        
+      case Atmega328P: case Atmega16: case Atmega8L:
+        switch (index)
+        {
+          case 0: return 0;
+          case 1: return 512;
+          case 2: return 1024;
+          case 3: return 2048;
+          default: throw new Exception ("index out of range");
+        }
+        
+      case UserSpecified: 
+        switch (index)
+        {
+          case 0: return 0;
+          case 1: return bootloaderSize;
+          default: throw new Exception ("index out of range");
+        }
+
+    }
+    throw new RuntimeException("CPU-Typ not known");
+  }
+  
+  
+  public String[] getAvailableBootloaderSizes ()
+  {
+    return getBootloaderSizeTypes().split(",");
+  }
+
+  
+  public String getBootloaderSizeTypes() 
+  {
+    switch (typ)
+    {
+      case Atmega328P: return "No Bootloader,512 Bytes,1024 Bytes,2048 Bytes";
+      case Atmega16:   return "No Bootloader,512 Bytes,1024 Bytes,2048 Bytes";
+      case Atmega8L:   return "No Bootloader,512 Bytes,1024 Bytes,2048 Bytes";
+      case Atmega1284P: return ("1024 Bytes,2048 Bytes,4096 Bytes,8192 Bytes");
+      case UserSpecified: return String.format("No Bootloader,%d Bytes", bootloaderSize);
+    }
+    throw new RuntimeException("CPU-Typ not known");
+  }
+
+  
+  public void setFlashSize(int flashSize)
+  {
+    this.flashSize = flashSize;
+  }
+
+
+  public void setPageSize(int pageSize)
+  {
+    this.pageSize = pageSize;
+  }
+
+
+  public Typ getTyp()
+  {
+    return typ;
+  }
+
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/LineTerminal.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/LineTerminal.java
new file mode 100644 (file)
index 0000000..775fcb2
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+import java.awt.Point;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+
+/**
+ * Simple Line-Terminal with special ctrl codes '\n','\r','\b'.</BR>
+ * @author Manfred Steiner
+ */
+public class LineTerminal extends Terminal
+{
+  private static final int DEFAULT_STRING_SIZE = 128;
+  public static final int MODE_NL_IS_CR = 0;
+
+  private Point cursorPos;
+
+  private int mode;
+  private int numberOfLines;     // number of lines available in text[]
+  private int firstLine;         // first line number in text[]
+  private int lastLine;          // last line number in text[]
+  private int start;             // index of 'firstLine'
+  private int maxColumnsIndex;   // index of line with largest number of columns
+  private int columns;           // needed number of columns
+  private StringBuilder [] data; // byte representation of terminal content (for debugging purposes)
+  private StringBuilder [] text; // text representation of terminal content (for text output)
+
+
+  public LineTerminal (int numberOfLines)
+  {
+    super();
+    this.numberOfLines = numberOfLines;
+    this.cursorPos = new Point(0,0);
+    this.data = new StringBuilder [this.numberOfLines];
+    this.text = new StringBuilder [this.numberOfLines];
+    for (int i=0; i<this.numberOfLines; i++)
+    {
+      this.data[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+      this.text[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+    }
+  }
+
+  public boolean isTextAvailable (int line, int pos)
+  {
+    int i = getIndex(line);
+    if (i<0 || pos>=this.text[i].length())
+      return false;
+    return true;
+  }
+
+
+  public boolean isLineAvailable (int line, int pos)
+  {
+    int i = getIndex(line);
+    if (i<0)
+      return false;
+    return true;
+  }
+
+
+  public char getText (int line, int pos) throws IndexOutOfBoundsException
+  {
+    int i = getIndex(line);
+    if (i<0 || pos<0 || pos>=text[i].length())
+      throw new IndexOutOfBoundsException();
+
+    return text[i].charAt(pos);
+  }
+
+
+  public String getText (int line) throws IndexOutOfBoundsException
+  {
+    int i = getIndex(line);
+    if (i<0)
+      throw new IndexOutOfBoundsException();
+
+    return text[i].toString();
+  }
+
+
+  public void append (char c)
+  {
+    switch (c)
+    {
+      case '\n': ctrl_nl(); return;
+      case '\r': ctrl_cr(); return;
+      case '\b': ctrl_bs(); return;
+    }
+
+    int i = getIndex(this.cursorPos.y);
+    if (this.cursorPos.x >= this.text[i].length())
+    {
+      this.text[i].append(c);
+      this.data[i].append(c);
+    }
+    else
+    {
+      this.text[i].setCharAt(this.cursorPos.x, c);
+      this.data[i].append(c);
+    }
+    if (this.text[i].length()>this.columns)
+    {
+      this.columns = this.text[i].length();
+      this.maxColumnsIndex = i;
+    }
+    this.cursorPos.x++;
+  }
+
+
+  public void append (String s)
+  {
+    for (int i=0; i<s.length(); i++)
+      this.append(s.charAt(i));
+  }
+
+
+  public void append (byte b)
+  {
+    this.append((char) b);
+  }
+
+  public void append (byte [] b, int numberOfbytes)
+  {
+    for (int i=0; i<b.length && i<numberOfbytes; i++)
+      this.append(b[i]);
+  }
+
+  public void append (byte [] b)
+  {
+    for (int i=0; i<b.length; i++)
+      this.append(b[i]);
+  }
+
+
+  @Override
+  public int getLines()
+  {
+    return this.lastLine-this.firstLine + 1;
+  }
+
+  public int getFirstLine ()
+  {
+    return this.firstLine;
+  }
+
+
+  public int getLastLine ()
+  {
+    return this.lastLine;
+  }
+
+  public int getCursorLine ()
+  {
+    return this.cursorPos.y;
+  }
+
+
+  public void copyToClipboard (Clipboard clip)
+  {
+    //Clipboard clip = getToolkit().getSystemClipboard();
+    StringSelection cont;
+    StringBuilder str = new StringBuilder(128);
+
+    for (int z=0; z<this.getLines(); z++)
+    {
+      str.append(this.getText(z)).append("\n");
+    }
+
+    cont = new StringSelection(str.toString());
+    clip.setContents(cont, null);
+  }
+
+
+  public void deleteContent ()
+  {
+    this.cursorPos = new Point(0,0);
+    this.data = new StringBuilder [this.numberOfLines];
+    this.text = new StringBuilder [this.numberOfLines];
+    for (int i=0; i<this.numberOfLines; i++)
+    {
+      this.data[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+      this.text[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+    }
+    this.firstLine = 0;
+    this.lastLine = 0;
+    this.start = 0;
+    this.maxColumnsIndex = 0;
+    this.columns = 0;
+  }
+
+
+  @Override
+  public int getColumns()
+  {
+    return this.columns;
+  }
+
+
+  @Override
+  public int length (int line)
+  {
+    int i = getIndex(line);
+    if (i>=0)
+      return text[i].length();
+    return 0;
+  }
+
+
+  @Override
+  public String toString()
+  {
+    return this.getClass().getCanonicalName() + "["
+           + "length=" + this.text.length
+           + ",lines=" + this.getLines()
+           + ",columns=" + this.getColumns()
+           + ",first=" + this.firstLine
+           + ",last=" + this.lastLine
+           + ",start=" + this.start
+           + ",maxColumnsIndex=" + this.maxColumnsIndex
+           + "]";
+  }
+
+
+
+
+ /* *********************************************************************
+  * private methods
+  ********************************************************************** */
+  
+  private int getIndex (int line)
+  {
+    if (line<this.firstLine || line>this.lastLine)
+      return -1;
+    int index = line - this.firstLine + this.start;
+    if (index>=this.numberOfLines)
+      index -= this.numberOfLines;
+    return index;
+  }
+
+
+  private void ctrl_nl ()
+  {
+    if (mode != LineTerminal.MODE_NL_IS_CR)
+      throw new RuntimeException("not supported yet");
+
+    int i = getIndex(this.cursorPos.y);
+    this.data[i].append('\n');
+
+    this.cursorPos.y++;
+    this.cursorPos.x = 0;
+
+    if (this.getIndex(this.cursorPos.y)<0)
+    {
+      this.lastLine++;
+      if (getIndex(lastLine) == getIndex(firstLine))
+      {
+        this.start++;
+        if (this.start >= this.numberOfLines)
+          this.start = 0;
+        this.firstLine++;
+      }
+      i = this.getIndex(this.cursorPos.y);
+      if (text[i].length()>0)
+      {
+        if (text[i].length()>DEFAULT_STRING_SIZE*8)
+          text[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+        else
+          text[i].delete(0, text[i].length());
+
+        if (data[i].length()>DEFAULT_STRING_SIZE*8)
+          data[i] = new StringBuilder(DEFAULT_STRING_SIZE);
+        else
+          data[i].delete(0, data[i].length());
+      }
+
+      if (this.maxColumnsIndex == i)
+      {
+        this.columns = 0;
+        for (i=0; i<text.length; i++)
+        {
+          if (text[i].length() > columns)
+          {
+            columns = text[i].length();
+            maxColumnsIndex = i;
+          }
+        }
+      }
+
+    }
+  }
+
+
+  private void ctrl_cr ()
+  {
+    if (mode != LineTerminal.MODE_NL_IS_CR)
+      throw new RuntimeException("not supported yet");
+
+    int i = getIndex(this.cursorPos.y);
+    this.data[i].append('\r');
+    this.cursorPos.x = 0;
+  }
+
+  private void ctrl_bs ()
+  {
+    if (mode != LineTerminal.MODE_NL_IS_CR)
+      throw new RuntimeException("not supported yet");
+
+    int i = getIndex(this.cursorPos.y);
+    this.data[i].append('\b');
+
+    if (this.cursorPos.x>0)
+      this.cursorPos.x--;
+  }
+
+
+
+
+  public static void main(String[] args)
+  {
+    LineTerminal t = new LineTerminal(4);
+    t.append("Line 0\n");
+    t.append("Line 1\n");
+    t.append("Line 2\n");
+    t.append("Line 3\n");
+    t.append("Line 4\n");
+    t.append("Line 5\n");
+    t.append("Line 6\n");
+    t.append("Line 7");
+    System.out.println(" Lines=" + t.getLines());
+    System.out.println(t.getText(4));
+    System.out.println(t.getText(5));
+    System.out.println(t.getText(6));
+    System.out.println(t.getText(7));
+    System.out.println(t);
+
+  }
+
+
+
+
+
+
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/MemoryContent.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/MemoryContent.java
new file mode 100644 (file)
index 0000000..9ed1b76
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+import java.util.Iterator;
+
+/**
+ * Content and paramters of the µC memory.</BR>
+ * @author steiner
+ */
+public final class MemoryContent implements Iterable
+{
+  private int [][] mem;
+  private int size;
+  private int pages;
+  private int pageSize;
+  private boolean complete;
+  private int validBytes;
+  private int validPages;
+  private MemoryContent oldMemoryContent;
+  private boolean modeString;
+  final private String headerFormat;
+  
+  /**
+   * Constructor with flash memory size and page-size (in bytes).<br>
+   * Default value for the ATmega328P is: size=32768, pageSize=128
+   * @param size Flash memory size in number of bytes.
+   * @param pageSize Size of one page (programable unit) in flash memory.
+   * @throws RuntimeException in case of size or pageSize is less than or equal to zero..
+   */
+  public MemoryContent(int size, int pageSize, String headerFormat) throws RuntimeException
+  {
+    this.size = size;
+    this.pages = size / pageSize;
+    this.pageSize = pageSize;
+    this.mem = null;
+    this.modeString = true;
+    this.headerFormat = headerFormat;
+    clearMemory();
+  }
+
+
+  public void setModeString(boolean modeString)
+  {
+    this.modeString = modeString;
+  }
+
+
+  public void clearMemory () throws RuntimeException
+  {
+    if (this.pages<=0 || this.pageSize<=0)
+      throw new RuntimeException("pages and/or pageSize must be greater than 0");
+
+    if (this.mem == null)
+    {
+      this.mem = new int [pages] [];
+      for (int i=0; i<pages; i++)
+        this.mem[i] = null;
+    }
+
+    for (int i=0; i<pages; i++)
+    {
+      if (mem[i]==null)
+        mem[i] = new int [pageSize];
+       for (int j=0; j<pageSize; j++)
+        mem[i][j] = -1;
+    }
+
+    this.validBytes = 0;
+  }
+
+  
+
+  public int getValidBytes ()
+  {
+    return validBytes;
+  }
+
+  public int getValidPages ()
+  {
+    return validPages;
+  }
+
+
+  public int getPageSize()
+  {
+    return pageSize;
+  }
+
+
+  public int getPages()
+  {
+    return pages;
+  }
+
+
+  public int getSize()
+  {
+    return size;
+  }
+
+
+  public void setMemoryByte (int address, int value) throws Exception
+  {
+    if (address<0 || address>=this.size)
+      throw new Exception("address out of range");
+
+    if (isComplete())
+      throw new Exception("memory is set completly");
+
+    int page = address / this.pageSize;
+    int pos = address % this.pageSize;
+    this.mem[page][pos] = value;
+  }
+
+  
+  public int byteAt (int address) throws Exception
+  {
+    if (address<0 || address>=this.size)
+      throw new Exception("address out of range");
+
+    int page = address / this.pageSize;
+    int offset = address % this.pageSize;
+    return this.mem[page][offset];
+  }
+
+
+  public int byteAt (int page, int offset) throws Exception
+  {
+    if (page<0 || page>=this.pages || offset<0 || offset>=this.pageSize)
+      throw new Exception("address via page/offset is out of range");
+
+    return this.mem[page][offset];
+  }
+
+
+  public boolean isByteDownloadNeeded (int page, int offset)
+  {
+    if (page<0 || page>=this.pages || offset<0 || offset>=this.pageSize)
+      return false;
+
+    if (this.oldMemoryContent != null)
+    {
+      try
+      {
+        int old = this.oldMemoryContent.byteAt(page,offset);
+        int act = this.byteAt(page, offset);
+        if (act<0 || act>255 || act == old)
+          return false;
+      }
+      catch (Exception ex) { }
+    }
+    {
+      if (page<0 || page>=this.pages || offset<0 || offset>=this.pageSize)
+      return false;
+
+    }
+
+    if (this.mem[page][offset]<0 || this.mem[page][offset]>255)
+      return false;
+
+    return true;
+  }
+
+
+  public boolean isComplete()
+  {
+    return complete;
+  }
+
+
+  public void setComplete(boolean complete)
+  {
+    if (complete == false)
+      throw new RuntimeException("not allowed");
+
+    if (this.complete == false && complete==true)
+    {
+      this.complete = true;
+      this.validBytes = 0;
+      this.validPages = 0;
+      for (int i=0; i<this.pages; i++)
+      {
+        boolean valid = false;
+        for (int j=0; j<this.pageSize; j++)
+        {
+          if (mem[i][j]>=0 && mem[i][j]<=255)
+          {
+            this.validBytes++;
+            valid = true;
+          }
+        }
+        if (valid)
+          this.validPages++;
+      }
+    }
+  }
+
+
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder(128);
+    sb.append(this.getClass().getCanonicalName());
+    sb.append("[");
+    sb.append("size="); sb.append(size);
+    sb.append(", pages="); sb.append(pages);
+    sb.append(", pageSize="); sb.append(pageSize);
+    sb.append(", validBytes="); sb.append(validBytes);
+    sb.append("]\n");
+
+    sb.append("mem["); sb.append(mem.length); sb.append("][");
+    sb.append(mem[0].length); sb.append("]=");
+    for (int i=0; i<this.pages; i++)
+    {
+      sb.append(String.format("\n%04x: ", i*this.pageSize));
+      for (int j=0; j<this.pageSize; j++)
+      {
+        if (mem[i][j]>=0 && mem[i][j]<=255)
+          sb.append(String.format(" %02x", mem[i][j]));
+        else
+          sb.append("   ");
+      }
+    }
+
+    return sb.toString();
+  }
+
+
+  public void setOldMemoryContent (MemoryContent oldMemoryContent)
+  {
+    this.oldMemoryContent = oldMemoryContent;
+  }
+
+
+  public Iterator<String> iterator()
+  {
+    if (this.modeString)
+      return new StringIterator(this);
+    return new ByteIterator(this);
+  }
+
+
+  private class StringIterator implements Iterator
+  {
+    MemoryContent mem;
+    int page;
+    int pos;
+    StringBuilder sb;
+
+    public StringIterator(MemoryContent mem)
+    {
+      this.mem = mem;
+      sb = new StringBuilder(256);
+    }
+
+    public String next ()
+    {
+      sb.delete(0, sb.length());
+
+      while (mem.mem[page] != null)
+      {
+        int j;
+        for (j=0; j<mem.pageSize; j++)
+        {
+          if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+            break;
+        }
+        if (j<mem.pageSize)
+        {
+          sb.append(String.format(headerFormat, page));
+          for (j=0; j<mem.pageSize; j++)
+          {
+            if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+              sb.append(String.format("%02X", mem.mem[page][j]));
+            else
+              sb.append("00");
+          }
+          page++;
+          break;
+        }
+        page++;
+      }
+
+      if (sb.length()==0)
+        return null;
+
+      return sb.toString();
+    }
+
+
+    public boolean hasNext()
+    {
+      while (page<mem.getPageSize() && mem.mem[page] != null)
+      {
+        int j;
+        for (j=0; j<mem.pageSize; j++)
+        {
+          if (mem.isByteDownloadNeeded(page,j))
+            break;
+          // if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+          // break;
+        }
+        if (j<mem.pageSize)
+          return true;
+
+        page++;
+      }
+      return false;
+    }
+
+    public void remove()
+    {
+      page++;
+    }
+
+  }
+
+  private class ByteIterator implements Iterator
+  {
+    MemoryContent mem;
+    int page;
+    int pos;
+    byte [] b;
+
+    public ByteIterator(MemoryContent mem)
+    {
+      this.mem = mem;
+      String s = String.format(headerFormat, 0);
+      b = new byte[mem.getPageSize()+s.length()];
+    }
+
+    public byte [] next ()
+    {
+      for (int i=0; i<b.length; i++)
+        b[i] = 0;
+
+      while (mem.mem[page] != null)
+      {
+        int j;
+        for (j=0; j<mem.pageSize; j++)
+        {
+          if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+            break;
+        }
+        if (j<mem.pageSize)
+        {
+          String s = String.format(headerFormat, page);
+          int k;
+          for (k=0; k<s.length(); k++)
+            b[k] = (byte)s.charAt(k);
+
+          for (j=0; j<mem.pageSize; j++)
+          {
+            if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+              b[j+k] = (byte)mem.mem[page][j];
+          }
+          page++;
+          break;
+        }
+        page++;
+      }
+
+      return b;
+    }
+
+
+    public boolean hasNext()
+    {
+      while (page<mem.pages && mem.mem[page] != null)
+      {
+        int j;
+        for (j=0; j<mem.pageSize; j++)
+        {
+          if (mem.isByteDownloadNeeded(page,j))
+            break;
+          // if (mem.mem[page][j]>=0 && mem.mem[page][j]<=255)
+          // break;
+        }
+        if (j<mem.pageSize)
+          return true;
+
+        page++;
+      }
+      return false;
+    }
+
+    public void remove()
+    {
+      page++;
+    }
+
+  }
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/ProgramFile.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/ProgramFile.java
new file mode 100644 (file)
index 0000000..ebcae2b
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+
+import at.htlkaindorf.sx.EasyProgrammer.gui.DialogSelectProgramFile;
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.TimeZone;
+
+/**
+ *
+ * @author steiner
+ */
+public class ProgramFile implements Iterable
+{
+  private byte [] hexData;
+  private byte [] rsnData;
+  private CpuTyp cpu;
+  private MemoryContent memoryContent;
+  private MemoryContent oldMemoryContent;
+  private ArrayList<String> errorList;
+  private long lastModified;
+  private int  bootloaderMode;
+
+  DialogSelectProgramFile dialogSelectProgramFile;
+
+  public ProgramFile(DialogSelectProgramFile dialogSelectProgramFile, CpuTyp target)
+  {
+    this.dialogSelectProgramFile = dialogSelectProgramFile;
+    cpu = target;
+    //cpu = ProgramFile.CpuTyp.ATMEGA328P;
+    //cpu = ProgramFile.CpuTyp.ATMEGA8L;
+  }
+
+
+  public void setCpu(CpuTyp cpu) throws Exception
+  {
+    this.cpu = cpu;
+    loadFile();
+  }
+
+  public CpuTyp getCpu()
+  {
+    return cpu;
+  }
+
+  public int getHexLength()
+  {
+    if (hexData == null)
+      return 0;
+    return hexData.length;
+  }
+
+  public int getRsnLength()
+  {
+    if (rsnData == null)
+      return 0;
+    return rsnData.length;
+  }
+
+  public int getMemoryLength ()
+  {
+    if (this.memoryContent==null)
+      return 0;
+    return this.memoryContent.getValidBytes();
+  }
+
+
+  public int getMemoryPages ()
+  {
+    if (this.memoryContent==null)
+      return 0;
+    
+    return this.memoryContent.getValidPages();
+  }
+
+
+  public ArrayList<String> getErrorList()
+  {
+    return errorList;
+  }
+
+
+  public int getBootloaderMode()
+  {
+    return bootloaderMode;
+  }
+
+  
+
+  public void setBootloaderMode(int bootloaderMode)
+  {
+    this.bootloaderMode = bootloaderMode;
+
+    if (this.memoryContent != null)
+    switch (bootloaderMode)
+    {
+      case 0: this.memoryContent.setModeString(true); break;
+      case 1: this.memoryContent.setModeString(true); break;
+      case 2: this.memoryContent.setModeString(false); break;
+      case 3: this.memoryContent.setModeString(false); break;
+    }
+
+    if (this.oldMemoryContent != null)
+    switch (bootloaderMode)
+    {
+      case 0: this.oldMemoryContent.setModeString(true); break;
+      case 1: this.oldMemoryContent.setModeString(true); break;
+      case 2: this.oldMemoryContent.setModeString(false); break;
+      case 3: this.oldMemoryContent.setModeString(false); break;
+    }
+
+  }
+
+
+  public String getBootloaderStartCmd ()
+  {
+    if (this.memoryContent == null)
+      return null;
+
+    switch(this.bootloaderMode)
+    {
+      case 0: return "@m00@f" + this.memoryContent.getPageSize();
+      case 1: return "@m01@s0c@f" + this.memoryContent.getPageSize();
+      case 2: return "@m02@f" + this.memoryContent.getPageSize();
+      case 3: return "@m03@s0c@f" + this.memoryContent.getPageSize();
+    }
+    return null;
+  }
+
+  public void completeDownloadDone ()
+  {
+    this.oldMemoryContent = this.memoryContent;
+  }
+
+
+  public void loadFile () throws Exception
+  {
+    if (this.memoryContent != null)
+    {
+      this.oldMemoryContent = this.memoryContent;
+      this.memoryContent = null;
+      this.hexData = null;
+      this.rsnData = null;
+      this.lastModified = 0L;
+      this.errorList = null;
+    }
+
+    if (this.dialogSelectProgramFile==null)
+      throw new RuntimeException("Cannot get path/file infos...");
+
+    String fileName = this.dialogSelectProgramFile.getFolderName() + this.dialogSelectProgramFile.getFileName();
+    
+    FileInputStream is;
+    try
+    {
+      File f = new File(fileName);
+      lastModified = f.lastModified();
+      is = new FileInputStream(fileName);
+    }
+    catch (FileNotFoundException ex)
+    {
+      throw new Exception("Datei '" + fileName + "' kann nicht geöffnet werden (" + ex.getMessage() + ")");
+    }
+    catch (SecurityException ex)
+    {
+      throw new Exception("Datei '" + fileName + "' kann nicht geöffnet werden (" + ex.getMessage() + ")");
+    }
+
+    ByteArrayOutputStream os = new ByteArrayOutputStream();
+    RSNOutputStream ros = new RSNOutputStream(os);
+    ros.setParameter(cpu.getPageSize(), cpu.getFlashSize(), cpu);
+
+    if (is !=null && os != null)
+    {
+      byte [] b = new byte [8192];
+      int len = 0;
+      do
+      {
+        len = is.read(b);
+        if (len>0)
+          ros.write(b, 0, len);
+      }
+      while (len>0);
+      hexData = os.toByteArray();
+      this.memoryContent = ros.getMemoryContent();
+      this.errorList = ros.getErrorList();
+      //System.out.println(this.memoryContent);
+      os.close();
+      ros.close();
+      os = null;
+      //for (int i=0; i<hexData.length; i++)
+        //System.out.print((char)hexData[i]);
+    }
+
+    if (is != null)
+      is.close();
+    is = null;
+  }
+
+  public boolean isAvailable ()
+  {
+     return dialogSelectProgramFile.getFolderName() != null && dialogSelectProgramFile.getFileName() != null;
+  }
+  
+  public boolean isModified ()
+  {
+     if (this.dialogSelectProgramFile.getFolderName() == null || this.dialogSelectProgramFile.getFileName() == null)
+       return false;
+     
+     String fileName = this.dialogSelectProgramFile.getFolderName() + this.dialogSelectProgramFile.getFileName();
+     File f = new File(fileName);
+     if (lastModified == f.lastModified())
+       return false;
+
+     return true;
+  }
+
+  public String getLastModifiedString ()
+  {
+    Date when = new Date(lastModified);
+    //SimpleDateFormat sdf = new SimpleDateFormat( "EEEE yyyy/MM/dd hh:mm:ss aa zz : zzzzzz" );
+    SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd / HH:mm:ss" );
+    sdf.setTimeZone(TimeZone.getDefault()); // local time
+    String str = sdf.format(when);
+    return str;
+  }
+
+
+  public void setDownloadModeFast (boolean modeFast)
+  {
+    if (memoryContent != null)
+    {
+      if (modeFast == true)
+        memoryContent.setOldMemoryContent(this.oldMemoryContent);
+      else
+        memoryContent.setOldMemoryContent(null);
+    }
+  }
+
+  public Iterator iterator()
+  {
+    return this.memoryContent.iterator();
+  }
+
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/RSNOutputStream.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/RSNOutputStream.java
new file mode 100644 (file)
index 0000000..f932873
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+import java.io.*;
+import java.util.ArrayList;
+
+/**
+ *
+ * @author steiner
+ */
+public class RSNOutputStream extends FilterOutputStream
+{
+  private MemoryContent memoryContent;
+  private int address;
+  private int offset;  // always zero if Intel Hex Record Typ 2,3,4 not supported
+  private char [] line;
+  private int linePos;
+  private int lineNumber;
+  private boolean fileComplete;
+  private ArrayList<String> errorList;
+  private CpuTyp cpu;
+  private String headerFormat;
+
+  public RSNOutputStream(OutputStream out)
+  {
+    super(out);
+    //this.out = out;
+  }
+
+
+  public void setParameter (int pageSize, int memorySize, CpuTyp cpu)
+  {
+    if (memorySize % pageSize != 0)
+     throw  new RuntimeException("Pagesize " + pageSize + " doesn't fit to memorysize " + memorySize);
+    
+    this.cpu = cpu;
+    if (cpu.getFlashSize()/cpu.getPageSize() > 256)
+      headerFormat = "P%03X";
+    else
+      headerFormat = "P%02X";
+    memoryContent = new MemoryContent(memorySize, pageSize, headerFormat);
+    this.line = new char [43];
+    this.lineNumber = 1;
+  }
+
+
+  public MemoryContent getMemoryContent()
+  {
+    return memoryContent;
+  }
+
+
+  public ArrayList<String> getErrorList()
+  {
+    return errorList;
+  }
+  
+
+  @Override
+  public void close() throws IOException
+  {
+    super.close();
+  }
+
+
+  @Override
+  public void flush() throws IOException
+  {
+    super.flush();
+    memoryContent = new MemoryContent(32768, 128, headerFormat);
+    address = 0;
+    linePos = 0;
+    this.lineNumber = 1;
+    fileComplete = false;
+  }
+
+
+  @Override
+  public void write(int b) throws IOException
+  {
+    //super.write(b);
+    if (b<0 || b>255)
+      throw new IOException("b out of range");
+
+    if (b == 13) return;
+    if (b == 10)
+    {
+      //if (lineNumber==625)
+      //   System.out.println("Test");
+
+      try { executeIntelHexLine(line, linePos - 1); }
+      catch (Exception ex)
+      {
+        if (errorList==null)
+          errorList = new ArrayList<String>();
+        errorList.add("Fehler in Zeile " + lineNumber + ": " + ex.getMessage());
+      }
+      lineNumber++;
+      linePos = 0;
+      return;
+    }
+
+    if (b == ':')
+    {
+      if (linePos > 0)
+        throw new IOException("':' only allowed on first position of a line");
+    }
+    else if ( !((b>='0' && b<='9') || (b>='A' && b<='F') || (b>='a' && b<='f')) )
+      throw new IOException("'" + (char) b + "' is not a hexadecimal digit");
+
+    if (linePos>=line.length)
+      throw new IOException("Size of line " + lineNumber + " too large");
+
+    line[linePos++] = (char) b;
+  }
+
+
+  @Override
+  public void write(byte[] b) throws IOException
+  {
+    for (int i= 0; i<b.length; i++)
+    {
+      if (b[i]<0) write(b[i]+256);
+      else        write(b[i]);
+    }
+  }
+
+
+  @Override
+  public void write(byte[] b, int off, int len) throws IOException
+  {
+    for (int i=0; i<len; i++)
+    {
+      if (b[i+off]<0) write(b[i+off]+256);
+      else            write(b[i+off]);
+    }
+  }
+
+  
+  void executeIntelHexLine (char [] line, int bytes) throws Exception
+  {
+    String errMsg = null;
+
+    if (line[0] != ':')
+      throw new Exception("Kein Intel-Hex Format, ':' fehlt als erstes Zeichen");
+
+    if (line.length<4)
+      throw new Exception("Kein Intel-Hex Format, Zeile zu kurz");
+
+    StringBuilder sb = new StringBuilder("  ");
+    int chksum = 0;
+    int [] b = new int [21];
+    //System.out.print("Intel-Hex :");
+    for (int i=0; i<(line.length-1)/2; i++)
+    {
+      sb.setCharAt(0, line[i*2+1]);
+      sb.setCharAt(1, line[i*2+2]);
+      b[i] = Integer.parseInt(sb.toString(), 16);
+      if (i==0 && b[i] > (line.length-1)/2-5)
+        throw new Exception("Intel-Hex Format - Länge fehlerhaft");
+      //System.out.print(" " + Integer.toHexString(b[i]));
+      if (i<(line.length-1)/2-1 && i<(b[0]+4))
+        chksum += b[i];
+      else
+      {
+        chksum = (256 - chksum % 256) % 256;
+        //chksum = (256 - chksum % 256);
+        if (b[i] != chksum)
+          throw new Exception("Intel-Hex Format Checksum-Fehler");
+        //System.out.println(" - Checksum ok");
+        switch (b[3])
+        {
+          case 0: // Binaerdaten
+            executeIntelHexTyp00(b);
+            break;
+
+          case 1: // File-Ende
+            executeIntelHexTyp01(b);
+            break;
+            
+          case 2: // Extended Segment Address
+            throw new Exception("Intel-Hex Format - Typ 02 not supported yet");
+
+          case 3: // Start Segment Address Record
+            throw new Exception("Intel-Hex Format - Typ 03 not supported yet");
+
+          case 4: // Extended Linear Address Record
+            throw new Exception("Intel-Hex Format - Typ 04 not supported yet");
+
+          case 5: // Start Linear Address Record
+            throw new Exception("Intel-Hex Format - Typ 05 not supported yet");
+          
+          default:
+            throw new Exception("Intel-Hex Format - Unbekannter Record Typ");
+        }
+
+        return;
+      }
+    }
+
+    throw new RuntimeException("Intel-Hex Format: unerwartetes Ende");
+  }
+
+  private void executeIntelHexTyp00(int [] b) throws Exception
+  {
+    if (b[3] != 0)
+      throw new RuntimeException("Falscher Typ");
+    int add = this.offset + b[1]*256+b[2];
+    int len = b[0];
+    int page;
+    int pos;
+    for (int i=0; i<len; i++)
+    {
+      add = this.offset + b[1]*256+b[2] + i;
+      try { this.memoryContent.setMemoryByte(add, b[i+4]); }
+      catch (Exception ex)
+      {
+        throw new Exception("Intel Hex - " + ex.getMessage());
+      }
+    }
+  }
+
+  private void executeIntelHexTyp01(int [] b) throws Exception
+  {
+    if (b[3] != 1)
+      throw new RuntimeException("Falscher Typ");
+    fileComplete = true;
+    if (this.out != null)
+    {
+      byte [] bout = new byte [this.memoryContent.getPageSize()];
+      boolean isEmpty;
+      try
+      {
+        for (int i=0; i<this.memoryContent.getPages(); i++)
+        {
+          isEmpty = true;
+          for (int j=0; j<this.memoryContent.getPageSize(); j++)
+            if (this.memoryContent.byteAt(i,j)>=0) isEmpty = false;
+          if (!isEmpty)
+          {
+            out.write((byte)'P');
+            String str = String.format("%02X", i);
+            out.write((byte)str.charAt(0));
+            out.write((byte)str.charAt(1));
+            for (int j=0; j<this.memoryContent.getPageSize(); j++)
+            {
+              if (this.memoryContent.byteAt(i,j)<0 ||this.memoryContent.byteAt(i,j)>255)
+                str = "00";
+              else
+                str = String.format("%02X", this.memoryContent.byteAt(i,j));
+              out.write((byte)str.charAt(0));
+              out.write((byte)str.charAt(1));
+            }
+            out.write(10);
+          }
+        }
+        out.write('F');
+        out.write('F');
+        out.write('F');
+      }
+      catch (IOException ex)
+      {
+        throw new Exception("IOException - " + ex.getMessage());
+      }
+    }
+    memoryContent.setComplete(true);
+  }
+
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder(128);
+    sb.append(this.getClass().getCanonicalName());
+    sb.append("[");
+    sb.append("address="); sb.append(address);
+    sb.append(", offset="); sb.append(offset);
+    sb.append(", linePos="); sb.append(linePos);
+    sb.append(", lineNumber="); sb.append(lineNumber);
+    sb.append(", fileComplete="); sb.append(fileComplete);
+    sb.append(", memoryContent="); sb.append(memoryContent);
+    sb.append("]\n");
+    sb.append("line["); sb.append(line.length); sb.append("]='");
+    for (int i=0; i<line.length; i++)
+      sb.append(line[i]);
+    sb.append("'\n");
+
+    if (this.memoryContent != null)
+    {
+      sb.append("memoryContent("); sb.append(memoryContent); sb.append(")=");
+      sb.append(this.memoryContent.toString());
+    }
+
+    return sb.toString();
+  }
+
+
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/data/Terminal.java b/src/at/htlkaindorf/sx/EasyProgrammer/data/Terminal.java
new file mode 100644 (file)
index 0000000..c2e3910
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.data;
+
+
+/**
+ * Abstract Terminal class.
+ * @author Manfred Steiner
+ */
+public abstract class Terminal
+{
+  public abstract void append (byte b);
+  public abstract void append (byte [] b, int numberOfbytes);
+  public abstract void append (byte [] b);
+  public abstract void append (char c);
+  public abstract void append (String s);
+  public abstract void deleteContent ();
+  public abstract char getText (int line, int pos) throws IndexOutOfBoundsException;
+  public abstract String getText (int line) throws IndexOutOfBoundsException;
+  public abstract boolean isTextAvailable (int line, int pos);
+  public abstract int getLines ();
+  public abstract int getColumns ();
+  public abstract int length (int line);
+  public abstract int getFirstLine ();
+  public abstract int getLastLine ();
+  public abstract int getCursorLine ();
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.form b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.form
new file mode 100644 (file)
index 0000000..eb66a80
--- /dev/null
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="&#xdc;ber..."/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[620, 140]"/>
+    </Property>
+    <Property name="name" type="java.lang.String" value="AboutDialog" noResource="true"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <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"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,54,0,0,2,15"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="panCenter">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jpanCenterNorth">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="10" left="10" right="10" top="10"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="North"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="jPanel1">
+              <Properties>
+                <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+                  <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                    <EmptyBorder bottom="10" left="10" right="10" top="10"/>
+                  </Border>
+                </Property>
+              </Properties>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                <Property name="columns" type="int" value="0"/>
+                <Property name="rows" type="int" value="2"/>
+              </Layout>
+              <SubComponents>
+                <Component class="javax.swing.JLabel" name="jlaName">
+                  <Properties>
+                    <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                      <Font name="Arial" size="24" style="1"/>
+                    </Property>
+                    <Property name="horizontalAlignment" type="int" value="0"/>
+                    <Property name="text" type="java.lang.String" value="EasyProgrammer"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JLabel" name="jlaCopyright">
+                  <Properties>
+                    <Property name="horizontalAlignment" type="int" value="0"/>
+                    <Property name="text" type="java.lang.String" value="(C) 2013-2016, Manfred Steiner"/>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Component class="javax.swing.JLabel" name="jlaIcon">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png"/>
+                </Property>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="10" left="10" right="10" top="10"/>
+              </Border>
+            </Property>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="Center"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextPane" name="textPane">
+              <Properties>
+                <Property name="editable" type="boolean" value="false"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="panSouth">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="South"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JButton" name="butSchliessen">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Schliessen"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[5, 5, 5, 5]"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonSchliessen"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogAbout.java
new file mode 100644 (file)
index 0000000..814df2f
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * AboutDialog.java
+ *
+ * Created on 28.07.2010, 08:34:55
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.libs.EasyProgrammerLib;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.File;
+import java.util.*;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+
+
+/**
+ * Dialogfenster 'About'.</BR>
+ * @author Manfred Steiner
+ */
+public final class DialogAbout extends javax.swing.JDialog
+{
+  public final static String version = "2.26 (25.8.2016)";
+  public final static String source = "https://www.htl-mechatronik.at/svn/easyprogrammer/?p=26";
+    
+  private static final Logger LOG = Logger.getLogger(DialogAbout.class.getName());
+
+  
+  
+  /** Creates new form AboutDialog */
+  public DialogAbout(java.awt.Frame parent, boolean modal)
+  {
+    super(parent, modal);
+    initComponents();
+    insertSystemInfo();
+    pack();
+    setLocationRelativeTo(parent);
+    setResizable(false);
+  }
+
+
+  public void insertSystemInfo()
+  {
+    // UnComment next Statement to see all available Properties in a additional window
+    // showSysPropListGUI();
+
+    Properties pr = System.getProperties();
+    StyledDocument doc = textPane.getStyledDocument();
+
+    Style styleBold = textPane.addStyle("Arial 12 Bold", null);
+    StyleConstants.setBold(styleBold,true);
+    StyleConstants.setFontFamily(styleBold, "Arial");
+    StyleConstants.setFontSize(styleBold, 12);
+
+    Style styleNormal = textPane.addStyle("Arial 12 Normal", null);
+    StyleConstants.setFontFamily(styleNormal, "Arial");
+    StyleConstants.setFontSize(styleNormal, 12);
+
+    try
+    {
+      doc.insertString(doc.getLength(), "Produkt Version: ", styleBold);
+      doc.insertString(doc.getLength(), version + "\n", styleNormal);
+      doc.insertString(doc.getLength(), "Source: ", styleBold);
+      doc.insertString(doc.getLength(), source + "\n", styleNormal);
+      
+      doc.insertString(doc.getLength(), "Java: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("java.runtime.version"), styleNormal);
+      doc.insertString(doc.getLength(), "; " + System.getProperty("java.vm.name"), styleNormal);
+      doc.insertString(doc.getLength(), System.getProperty("java.vm.version")  + "\n", styleNormal);
+
+      doc.insertString(doc.getLength(), "System: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("os.name"), styleNormal);
+      doc.insertString(doc.getLength(), "  Version " + System.getProperty("os.version"), styleNormal);
+      doc.insertString(doc.getLength(), "  running on " + System.getProperty("os.arch"), styleNormal);
+      doc.insertString(doc.getLength(), "; " + System.getProperty("sun.jnu.encoding"), styleNormal);
+      doc.insertString(doc.getLength(), "; " + System.getProperty("user.language"), styleNormal);
+      doc.insertString(doc.getLength(), "_" + System.getProperty("user.country"), styleNormal);
+
+      doc.insertString(doc.getLength(), "\nBenutzer: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("user.name"), styleNormal);
+
+      doc.insertString(doc.getLength(), "\nBenutzerverzeichnis: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("user.home"), styleNormal);
+
+      doc.insertString(doc.getLength(), "\nArbeitsverzeichnis: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("user.dir"), styleNormal);
+
+      doc.insertString(doc.getLength(), "\nExterne Klassen in: ", styleBold);
+      doc.insertString(doc.getLength(), System.getProperty("java.ext.dirs"), styleNormal);
+
+      doc.insertString(doc.getLength(), "\n" + "EasyProgrammerLib: ", styleBold);
+      if (!EasyProgrammerLib.isLibAvailable())
+        doc.insertString(doc.getLength(), "not available", styleNormal);
+      else
+      {
+        File libFile = EasyProgrammerLib.getLibFile();
+        doc.insertString(doc.getLength(), EasyProgrammerLib.getLibraryVersion() + " (" + libFile.getName() + ")", styleNormal);
+      }
+
+      String version = "n/a";
+      try { version = jssc.SerialNativeInterface.getNativeLibraryVersion(); }
+      catch (Exception ex) { LOG.warning(ex); }
+      doc.insertString(doc.getLength(), "\nJSSC Native: ", styleBold);
+      doc.insertString(doc.getLength(), version, styleNormal);
+
+      version = "n/a";
+      try { version = jssc.SerialNativeInterface.getLibraryVersion(); }
+      catch (Exception ex) { LOG.warning(ex); }
+      doc.insertString(doc.getLength(), "\nJSSC: ", styleBold);
+      doc.insertString(doc.getLength(), version, styleNormal);
+    }
+
+    catch (BadLocationException ble)
+    {
+      System.err.println("Couldn't insert initial text into text pane.");
+    }
+  
+  }
+
+
+
+  /** Panel to display the (limited) GUI intereface. */
+  public void showSysPropListGUI()
+  {
+//     JFrame window = new JFrame("System Properties");
+//     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+//     JPanel panel = new JPanel();
+//     JTextArea m_propertiesTA = new JTextArea(20, 40);
+//
+//     //... Add property list data to text area.
+//     Properties pr = System.getProperties();
+//     TreeSet<String> propKeys = new TreeSet(pr.keySet());
+//     for (Iterator it = propKeys.iterator(); it.hasNext(); )
+//     {
+//       String key = (String)it.next();
+//       m_propertiesTA.append("" + key + "=" + pr.get(key) + "\n");
+//     }
+//
+//     panel.setLayout(new BorderLayout());
+//     panel.add(new JScrollPane(m_propertiesTA), BorderLayout.CENTER);
+//
+//     window.setContentPane(panel);
+//     window.pack();
+//     window.setVisible(true);
+  }
+
+  
+
+
+  /** 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")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        panCenter = new javax.swing.JPanel();
+        jpanCenterNorth = new javax.swing.JPanel();
+        jPanel1 = new javax.swing.JPanel();
+        jlaName = new javax.swing.JLabel();
+        jlaCopyright = new javax.swing.JLabel();
+        jlaIcon = new javax.swing.JLabel();
+        jScrollPane = new javax.swing.JScrollPane();
+        textPane = new javax.swing.JTextPane();
+        panSouth = new javax.swing.JPanel();
+        butSchliessen = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Über...");
+        setMinimumSize(new java.awt.Dimension(620, 140));
+        setName("AboutDialog"); // NOI18N
+
+        panCenter.setLayout(new java.awt.BorderLayout());
+
+        jpanCenterNorth.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
+        jPanel1.setLayout(new java.awt.GridLayout(2, 0));
+
+        jlaName.setFont(new java.awt.Font("Arial", 1, 24)); // NOI18N
+        jlaName.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+        jlaName.setText("EasyProgrammer");
+        jPanel1.add(jlaName);
+
+        jlaCopyright.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+        jlaCopyright.setText("(C) 2013-2016, Manfred Steiner");
+        jPanel1.add(jlaCopyright);
+
+        jpanCenterNorth.add(jPanel1);
+
+        jlaIcon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png"))); // NOI18N
+        jpanCenterNorth.add(jlaIcon);
+
+        panCenter.add(jpanCenterNorth, java.awt.BorderLayout.NORTH);
+
+        jScrollPane.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        textPane.setEditable(false);
+        jScrollPane.setViewportView(textPane);
+
+        panCenter.add(jScrollPane, java.awt.BorderLayout.CENTER);
+
+        getContentPane().add(panCenter, java.awt.BorderLayout.CENTER);
+
+        butSchliessen.setText("Schliessen");
+        butSchliessen.setMargin(new java.awt.Insets(5, 5, 5, 5));
+        butSchliessen.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                onButtonSchliessen(evt);
+            }
+        });
+        panSouth.add(butSchliessen);
+
+        getContentPane().add(panSouth, java.awt.BorderLayout.SOUTH);
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void onButtonSchliessen(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonSchliessen
+    {//GEN-HEADEREND:event_onButtonSchliessen
+      // TODO add your handling code here:
+      dispose();
+    }//GEN-LAST:event_onButtonSchliessen
+
+
+  /**
+   * @param args the command line arguments
+   */
+  public static void main(String args[])
+  {
+    java.awt.EventQueue.invokeLater(new Runnable()
+    {
+
+      @Override
+      public void run()
+      {
+        DialogAbout dialog = new DialogAbout(new javax.swing.JFrame(), true);
+        dialog.addWindowListener(new java.awt.event.WindowAdapter()
+        {
+
+          @Override
+          public void windowClosing(java.awt.event.WindowEvent e)
+          {
+            System.exit(0);
+          }
+        });
+        dialog.setVisible(true);
+      }
+    });
+  }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton butSchliessen;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JScrollPane jScrollPane;
+    private javax.swing.JLabel jlaCopyright;
+    private javax.swing.JLabel jlaIcon;
+    private javax.swing.JLabel jlaName;
+    private javax.swing.JPanel jpanCenterNorth;
+    private javax.swing.JPanel panCenter;
+    private javax.swing.JPanel panSouth;
+    private javax.swing.JTextPane textPane;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.form b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.form
new file mode 100644 (file)
index 0000000..742fea8
--- /dev/null
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.8" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Einstellungen"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <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"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,11,0,0,1,37"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jpanCenter">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="First"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="15" right="5" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="West"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="6"/>
+            <Property name="verticalGap" type="int" value="3"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Microprocessor"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Flash-Size"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Pagesize"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel5">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Pages"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel6">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Bootloader-Size"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel11">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Reset String"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel3">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="1" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="Center"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="6"/>
+            <Property name="verticalGap" type="int" value="3"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JComboBox" name="jcbMicroprocessor">
+              <Properties>
+                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                  <StringArray count="3">
+                    <StringItem index="0" value="Atmega328P"/>
+                    <StringItem index="1" value="Atmega8"/>
+                    <StringItem index="2" value="User-Defined"/>
+                  </StringArray>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMicroprocessorChange"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JFormattedTextField" name="jftfFlashSize">
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jftfFlashSizeActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JFormattedTextField" name="jftfPageSize">
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jftfPageSizeActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JTextField" name="jtfPages">
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jtfPagesActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JComboBox" name="jcbBootloaderSize">
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jcbBootloaderSizeonMicroprocessorChange"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JTextField" name="jtfResetString">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="@R"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jtfResetStringActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <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.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="1" right="15" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="East"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="6"/>
+            <Property name="verticalGap" type="int" value="3"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.Box$Filler" name="filler1">
+              <Properties>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[1, 1]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[1, 1]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[1, 1]"/>
+                </Property>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.RigidArea"/>
+              </AuxValues>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel7">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="KiB"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel8">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Bytes"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel5">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="Last"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JCheckBox" name="jcbResetCmd">
+              <Properties>
+                <Property name="selected" type="boolean" value="true"/>
+                <Property name="text" type="java.lang.String" value="Sende nach dem Reset String &quot;\u005cr\u005cn&quot;" containsInvalidXMLChars="true"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="jpanSouth">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="South"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout">
+        <Property name="horizontalGap" type="int" value="10"/>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jpanButtons">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="horizontalGap" type="int" value="10"/>
+            <Property name="rows" type="int" value="1"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="jbutOK">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="OK"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onBtOK"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jbutCancel">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Abbrechen"/>
+                <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                  <Insets value="[5, 5, 5, 5]"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onBtAbbrechen"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogProperties.java
new file mode 100644 (file)
index 0000000..1a34023
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * KoeffSpeichernDialog.java
+ *
+ * Created on 27.07.2010, 13:12:15
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+
+import at.htlkaindorf.sx.EasyProgrammer.data.CpuTyp;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialPortInfo;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+
+
+/**
+ *
+ * @author steiner
+ */
+public class DialogProperties extends javax.swing.JDialog
+{
+   private boolean pressedOK = false;
+   private CpuTyp  cpuTyp;
+
+
+  /** Creates new form KoeffSpeichernDialog */
+  public DialogProperties(java.awt.Frame parent, String title, boolean modal)
+  {
+    super(parent, title, modal);
+    
+    initComponents();
+    
+    javax.swing.text.MaskFormatter mf=null;
+    try
+    {
+      mf = new javax.swing.text.MaskFormatter ("###");
+    }
+    catch (java.text.ParseException e) {}
+    javax.swing.text.DefaultFormatterFactory dff = new javax.swing.text.DefaultFormatterFactory(mf);
+
+    this.jftfFlashSize.setFormatterFactory(dff);
+
+    cpuTyp = new CpuTyp(CpuTyp.Typ.Atmega328P);
+    jcbMicroprocessor.setModel(new javax.swing.DefaultComboBoxModel(cpuTyp.getAvailableNames()));
+    try
+    {
+      this.jcbMicroprocessor.setSelectedItem(cpuTyp.getName());
+      this.UpdateFields();
+    }
+    catch (Exception ex) { ex.printStackTrace(); };
+    
+    String [] availBLSizes = cpuTyp.getAvailableBootloaderSizes();
+    jcbBootloaderSize.setModel(new javax.swing.DefaultComboBoxModel(availBLSizes));
+    try
+    {
+      jcbBootloaderSize.setSelectedIndex(cpuTyp.getBootloaderSizeIndex());
+      UpdateFields();
+    }
+    catch (Exception ex) { ex.printStackTrace(); };
+    
+//    this.addComponentListener(new ComponentAdapter()
+//    {
+//        @Override
+//        public void componentResized (ComponentEvent e)
+//        {
+//        }
+//    });
+    
+  }
+
+  @Override
+  public void setVisible (boolean b)
+  {
+    pack();
+    setMinimumSize(getPreferredSize());
+    setLocationRelativeTo(getParent());
+    super.setVisible(b); //To change body of generated methods, choose Tools | Templates.
+  }
+
+
+  @Override
+  public void setMinimumSize (Dimension minimumSize)
+  {
+    super.setMinimumSize(minimumSize);
+  }
+  
+
+  public boolean isPressedOK ()
+  {
+    return pressedOK;
+  }
+
+  public CpuTyp getCpuTyp()
+  {
+    return cpuTyp;
+  }
+
+
+  public void setCpuTyp(CpuTyp cpuTyp)
+  {
+    this.cpuTyp = cpuTyp;
+
+    if (jcbBootloaderSize.getItemCount()>0)
+    {
+      try
+      {
+        jcbBootloaderSize.setSelectedIndex(cpuTyp.getBootloaderSizeIndex());
+      } 
+      catch (Exception ex)
+      {
+        ex.printStackTrace(System.err);
+      }
+    }
+
+    if (jcbMicroprocessor.getItemCount()>0)
+    {
+      try
+      {
+        this.jcbMicroprocessor.setSelectedItem(cpuTyp.getName());
+      } 
+      catch (Exception ex)
+      {
+        ex.printStackTrace(System.err);
+      }
+    }
+    
+    String resetCmd = cpuTyp.getResetCommand();
+    if (resetCmd.endsWith("\r\n"))
+    {
+      jtfResetString.setText(resetCmd.substring(0, resetCmd.length()-2));
+      jcbResetCmd.setSelected(true);
+    }
+    else
+    {
+      jtfResetString.setText(resetCmd);
+      jcbResetCmd.setSelected(false);
+    }
+    
+    
+  }
+
+  public String getResetString ()
+  {
+    if (jcbResetCmd.isSelected())
+      return jtfResetString.getText() + "\r\n";
+    else
+      return jtfResetString.getText();
+  }
+  
+  
+  public void endDialogWithOK ()
+  {
+    dispose();
+    cpuTyp.setResetCommand(getResetString());
+    this.pressedOK = true;
+  }
+
+  private void changeMicroprocessor ()
+  {
+    String s = (String) this.jcbMicroprocessor.getSelectedItem();
+    try
+    {
+      cpuTyp.setTyp(s);
+      UpdateFields();
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace(System.err);
+    }
+  }
+
+  private void UpdateFields () throws Exception
+  {
+    if (this.cpuTyp.getTyp()==CpuTyp.Typ.UserSpecified)
+    {
+      this.jftfFlashSize.setEnabled(true);
+      this.jftfPageSize.setEnabled(true);
+      return;
+    }
+
+    //System.out.println(cpuTyp.getFlashSize()/1024);
+    this.jftfFlashSize.setText(String.format("%d", cpuTyp.getFlashSize()/1024));
+    this.jftfFlashSize.setEnabled(false);
+    this.jftfPageSize.setText(String.format("%d",cpuTyp.getPageSize()));
+    this.jftfPageSize.setEnabled(false);
+    this.jtfPages.setText(String.format("%d",cpuTyp.getPages()));
+    this.jtfPages.setEnabled(false);
+    
+    //jcbBootloaderSize.setSelectedIndex(cpuTyp.getBootloaderSizeIndex());
+
+    String resetCmd = cpuTyp.getResetCommand();
+    if (resetCmd==null)
+      resetCmd = "@reset\n\r";
+    if (resetCmd.endsWith("\r\n"))
+    {
+      jtfResetString.setText(resetCmd.substring(0, resetCmd.length()-2));
+      jcbResetCmd.setSelected(true);
+    }
+    else
+    {
+      jtfResetString.setText(resetCmd);
+      jcbResetCmd.setSelected(false);
+    }
+    jtfResetString.setEnabled(true);
+    jcbResetCmd.setEnabled(true);
+  }
+
+
+  /** 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")
+  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+  private void initComponents()
+  {
+
+    jpanCenter = new javax.swing.JPanel();
+    jPanel2 = new javax.swing.JPanel();
+    jLabel2 = new javax.swing.JLabel();
+    jLabel3 = new javax.swing.JLabel();
+    jLabel4 = new javax.swing.JLabel();
+    jLabel5 = new javax.swing.JLabel();
+    jLabel6 = new javax.swing.JLabel();
+    jLabel11 = new javax.swing.JLabel();
+    jPanel3 = new javax.swing.JPanel();
+    jcbMicroprocessor = new javax.swing.JComboBox();
+    jftfFlashSize = new javax.swing.JFormattedTextField();
+    jftfPageSize = new javax.swing.JFormattedTextField();
+    jtfPages = new javax.swing.JTextField();
+    jcbBootloaderSize = new javax.swing.JComboBox();
+    jtfResetString = new javax.swing.JTextField();
+    jPanel4 = new javax.swing.JPanel();
+    filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(1, 1), new java.awt.Dimension(1, 1), new java.awt.Dimension(1, 1));
+    jLabel7 = new javax.swing.JLabel();
+    jLabel8 = new javax.swing.JLabel();
+    jPanel5 = new javax.swing.JPanel();
+    jcbResetCmd = new javax.swing.JCheckBox();
+    jpanSouth = new javax.swing.JPanel();
+    jpanButtons = new javax.swing.JPanel();
+    jbutOK = new javax.swing.JButton();
+    jbutCancel = new javax.swing.JButton();
+
+    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+    setTitle("Einstellungen");
+
+    jpanCenter.setLayout(new java.awt.BorderLayout());
+
+    jPanel2.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 15, 5, 5));
+    jPanel2.setLayout(new java.awt.GridLayout(6, 0, 0, 3));
+
+    jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel2.setText("Microprocessor");
+    jPanel2.add(jLabel2);
+
+    jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel3.setText("Flash-Size");
+    jPanel2.add(jLabel3);
+
+    jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel4.setText("Pagesize");
+    jPanel2.add(jLabel4);
+
+    jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel5.setText("Pages");
+    jPanel2.add(jLabel5);
+
+    jLabel6.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel6.setText("Bootloader-Size");
+    jPanel2.add(jLabel6);
+
+    jLabel11.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel11.setText("Reset String");
+    jPanel2.add(jLabel11);
+
+    jpanCenter.add(jPanel2, java.awt.BorderLayout.WEST);
+
+    jPanel3.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 1));
+    jPanel3.setLayout(new java.awt.GridLayout(6, 0, 0, 3));
+
+    jcbMicroprocessor.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Atmega328P", "Atmega8", "User-Defined" }));
+    jcbMicroprocessor.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMicroprocessorChange(evt);
+      }
+    });
+    jPanel3.add(jcbMicroprocessor);
+
+    jftfFlashSize.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jftfFlashSizeActionPerformed(evt);
+      }
+    });
+    jPanel3.add(jftfFlashSize);
+
+    jftfPageSize.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jftfPageSizeActionPerformed(evt);
+      }
+    });
+    jPanel3.add(jftfPageSize);
+
+    jtfPages.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jtfPagesActionPerformed(evt);
+      }
+    });
+    jPanel3.add(jtfPages);
+
+    jcbBootloaderSize.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jcbBootloaderSizeonMicroprocessorChange(evt);
+      }
+    });
+    jPanel3.add(jcbBootloaderSize);
+
+    jtfResetString.setText("@R");
+    jtfResetString.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jtfResetStringActionPerformed(evt);
+      }
+    });
+    jPanel3.add(jtfResetString);
+
+    jpanCenter.add(jPanel3, java.awt.BorderLayout.CENTER);
+
+    jPanel4.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 1, 5, 15));
+    jPanel4.setLayout(new java.awt.GridLayout(6, 0, 0, 3));
+    jPanel4.add(filler1);
+
+    jLabel7.setText("KiB");
+    jPanel4.add(jLabel7);
+
+    jLabel8.setText("Bytes");
+    jPanel4.add(jLabel8);
+
+    jpanCenter.add(jPanel4, java.awt.BorderLayout.EAST);
+
+    jcbResetCmd.setSelected(true);
+    jcbResetCmd.setText("Sende nach dem Reset String \"\\r\\n\"");
+    jPanel5.add(jcbResetCmd);
+
+    jpanCenter.add(jPanel5, java.awt.BorderLayout.PAGE_END);
+
+    getContentPane().add(jpanCenter, java.awt.BorderLayout.PAGE_START);
+
+    jpanSouth.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 10, 5));
+
+    jpanButtons.setLayout(new java.awt.GridLayout(1, 0, 10, 0));
+
+    jbutOK.setText("OK");
+    jbutOK.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onBtOK(evt);
+      }
+    });
+    jpanButtons.add(jbutOK);
+
+    jbutCancel.setText("Abbrechen");
+    jbutCancel.setMargin(new java.awt.Insets(5, 5, 5, 5));
+    jbutCancel.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onBtAbbrechen(evt);
+      }
+    });
+    jpanButtons.add(jbutCancel);
+
+    jpanSouth.add(jpanButtons);
+
+    getContentPane().add(jpanSouth, java.awt.BorderLayout.SOUTH);
+
+    pack();
+  }// </editor-fold>//GEN-END:initComponents
+
+    private void onBtAbbrechen(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onBtAbbrechen
+    {//GEN-HEADEREND:event_onBtAbbrechen
+      // TODO add your handling code here:
+      dispose();
+    }//GEN-LAST:event_onBtAbbrechen
+
+    private void onBtOK(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onBtOK
+    {//GEN-HEADEREND:event_onBtOK
+      // TODO add your handling code here:
+      endDialogWithOK();
+    }//GEN-LAST:event_onBtOK
+
+    private void onMicroprocessorChange(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMicroprocessorChange
+    {//GEN-HEADEREND:event_onMicroprocessorChange
+      changeMicroprocessor();
+    }//GEN-LAST:event_onMicroprocessorChange
+
+    private void jftfFlashSizeActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jftfFlashSizeActionPerformed
+    {//GEN-HEADEREND:event_jftfFlashSizeActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_jftfFlashSizeActionPerformed
+
+    private void jftfPageSizeActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jftfPageSizeActionPerformed
+    {//GEN-HEADEREND:event_jftfPageSizeActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_jftfPageSizeActionPerformed
+
+    private void jtfPagesActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jtfPagesActionPerformed
+    {//GEN-HEADEREND:event_jtfPagesActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_jtfPagesActionPerformed
+
+    private void jtfResetStringActionPerformed (java.awt.event.ActionEvent evt)//GEN-FIRST:event_jtfResetStringActionPerformed
+    {//GEN-HEADEREND:event_jtfResetStringActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_jtfResetStringActionPerformed
+
+    private void jcbBootloaderSizeonMicroprocessorChange (java.awt.event.ActionEvent evt)//GEN-FIRST:event_jcbBootloaderSizeonMicroprocessorChange
+    {//GEN-HEADEREND:event_jcbBootloaderSizeonMicroprocessorChange
+      // TODO add your handling code here:
+    }//GEN-LAST:event_jcbBootloaderSizeonMicroprocessorChange
+
+
+  /**
+   * @param args the command line arguments
+   */
+  public static void main(String args[])
+  {
+    java.awt.EventQueue.invokeLater(new Runnable()
+    {
+
+      public void run()
+      {
+        DialogProperties dialog = new DialogProperties(new javax.swing.JFrame(), "Einstellungen", true);
+        dialog.addWindowListener(new java.awt.event.WindowAdapter()
+        {
+
+          public void windowClosing(java.awt.event.WindowEvent e)
+          {
+            System.exit(0);
+          }
+        });
+        dialog.setVisible(true);
+      }
+    });
+  }
+  // Variables declaration - do not modify//GEN-BEGIN:variables
+  private javax.swing.Box.Filler filler1;
+  private javax.swing.JLabel jLabel11;
+  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 jPanel2;
+  private javax.swing.JPanel jPanel3;
+  private javax.swing.JPanel jPanel4;
+  private javax.swing.JPanel jPanel5;
+  private javax.swing.JButton jbutCancel;
+  private javax.swing.JButton jbutOK;
+  private javax.swing.JComboBox jcbBootloaderSize;
+  private javax.swing.JComboBox jcbMicroprocessor;
+  private javax.swing.JCheckBox jcbResetCmd;
+  private javax.swing.JFormattedTextField jftfFlashSize;
+  private javax.swing.JFormattedTextField jftfPageSize;
+  private javax.swing.JPanel jpanButtons;
+  private javax.swing.JPanel jpanCenter;
+  private javax.swing.JPanel jpanSouth;
+  private javax.swing.JTextField jtfPages;
+  private javax.swing.JTextField jtfResetString;
+  // End of variables declaration//GEN-END:variables
+
+    
+   
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSelectProgramFile.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSelectProgramFile.java
new file mode 100644 (file)
index 0000000..f608006
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.libs.EasyProgrammerLib;
+import java.io.File;
+import java.util.ArrayList;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+/**
+ *
+ * @author steiner
+ */
+public class DialogSelectProgramFile
+{
+  private boolean pressedOK;
+  private String  fileName;
+  private String  folderName;
+  private JFrame  parentFrame;
+  private JFileChooser fileChooser;
+
+
+
+  public DialogSelectProgramFile (JFrame parentFrame)
+  {
+    this.parentFrame = parentFrame;
+  }
+
+
+  public void setFileName(String fileName)
+  {
+    this.fileName = fileName;
+  }
+
+
+  public void setFolderName(String folderName)
+  {
+    this.folderName = folderName;
+  }
+
+
+  public String getFileName()
+  {
+    return fileName;
+  }
+
+
+  public String getFolderName()
+  {
+    return folderName;
+  }
+
+
+  public boolean isPressedOK()
+  {
+    return pressedOK;
+  }
+
+
+  public void setVisible(boolean visible)
+  {
+    String[] filterPattern = { "hex", "*"};
+    String[] filterName = { "Hex-Datei", "Alle Dateien" };
+    String fname = null;
+    String folder = null;
+
+    if (visible == false) return;
+
+    if (EasyProgrammerLib.isLibAvailable() == true)
+    {
+      EasyProgrammerLib.showOpenHexFileDialog(folderName, fileName);
+      File file = EasyProgrammerLib.getSelectedFile();
+      if (file != null)
+      {
+        fname = file.getName();
+        folder = file.getAbsolutePath();
+        char [] dir = folder.toCharArray();
+        if (folder.lastIndexOf("\\") >= 0)
+          folder = String.valueOf(dir, 0, folder.lastIndexOf("\\")+1);
+        else if (folder.lastIndexOf("/") >= 0)
+          folder = String.valueOf(dir, 0, folder.lastIndexOf("/")+1);
+        else
+          folder = "";
+      }
+    }
+    else
+    {
+      if (fileChooser == null)
+      {
+        fileChooser = new JFileChooser();
+        fileChooser.setDialogTitle("Programmdatei (Hex-File) für ATmega328P auswählen...");
+        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+        fileChooser.setMultiSelectionEnabled(false);
+        FileNameExtensionFilter fileFilter = new FileNameExtensionFilter ("Hex-Datei (*.hex)", "hex");
+        fileChooser.addChoosableFileFilter(fileFilter);
+        //fileChooser.addChoosableFileFilter(new FileNameExtensionFilter ("Alle Dateien", "*"));
+        fileChooser.setFileFilter(fileFilter);
+        if (fileName != null)
+          fileChooser.setSelectedFile(new File(fileName));
+        if (this.folderName == null)
+        {
+          String dir = System.getProperty("user.dir");
+          if (dir != null) fileChooser.setCurrentDirectory(new File(dir));
+        }
+        else
+          fileChooser.setCurrentDirectory(new File(folderName));
+      }
+      if (folderName != null)
+        fileChooser.setCurrentDirectory(new File(folderName));
+      fileChooser.showOpenDialog(parentFrame);
+      File file = fileChooser.getSelectedFile();
+      if (file != null)
+      {
+        fname = file.getName();
+        folder = fileChooser.getCurrentDirectory().getAbsolutePath();
+      }
+    }
+
+    fileName = null;
+    folderName = null;
+    pressedOK = false;
+    if (fname!=null && folder!=null)
+    {
+      if (System.getProperty("os.name").toLowerCase().contains("win"))
+      {
+        if (folder.endsWith("\\")==false)
+          folder = folder + '\\';
+      }
+      else if (folder.endsWith("/")==false)
+        folder = folder + '/'; // for Linux
+
+      pressedOK = true;
+      fileName = fname;
+      folderName = folder;
+    }
+  }
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.form b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.form
new file mode 100644 (file)
index 0000000..69ee48f
--- /dev/null
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Einstellungen"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[300, 280]"/>
+    </Property>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <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"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-23,0,0,1,36"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="panCenter">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+            <EmptyBorder bottom="10" left="10" right="10" top="10"/>
+          </Border>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="North"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+        <Property name="columns" type="int" value="2"/>
+        <Property name="horizontalGap" type="int" value="5"/>
+        <Property name="rows" type="int" value="1"/>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="5"/>
+            <Property name="verticalGap" type="int" value="3"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Schnittstelle"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 16]"/>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Baudrate"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 16]"/>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Datenbits"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 16]"/>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Parity-Bit"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 16]"/>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel5">
+              <Properties>
+                <Property name="horizontalAlignment" type="int" value="4"/>
+                <Property name="text" type="java.lang.String" value="Stopbits"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 16]"/>
+                </Property>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="5"/>
+            <Property name="verticalGap" type="int" value="3"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JTextField" name="textDesiredInterface">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="COM1"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JComboBox" name="comboBaudrate">
+              <Properties>
+                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                  <StringArray count="5">
+                    <StringItem index="0" value="9600"/>
+                    <StringItem index="1" value="19200"/>
+                    <StringItem index="2" value="38400"/>
+                    <StringItem index="3" value="57600"/>
+                    <StringItem index="4" value="115200"/>
+                  </StringArray>
+                </Property>
+                <Property name="selectedIndex" type="int" value="3"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JComboBox" name="comboDatabits">
+              <Properties>
+                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                  <StringArray count="4">
+                    <StringItem index="0" value="5"/>
+                    <StringItem index="1" value="6"/>
+                    <StringItem index="2" value="7"/>
+                    <StringItem index="3" value="8"/>
+                  </StringArray>
+                </Property>
+                <Property name="selectedIndex" type="int" value="3"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JComboBox" name="comboParity">
+              <Properties>
+                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                  <StringArray count="3">
+                    <StringItem index="0" value="kein"/>
+                    <StringItem index="1" value="gerade"/>
+                    <StringItem index="2" value="ungerade"/>
+                  </StringArray>
+                </Property>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JComboBox" name="comboStopbits">
+              <Properties>
+                <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                  <StringArray count="2">
+                    <StringItem index="0" value="1"/>
+                    <StringItem index="1" value="2"/>
+                  </StringArray>
+                </Property>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="panSouth">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+            <EmptyBorder bottom="2" left="5" right="5" top="1"/>
+          </Border>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="South"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jpanButtons">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="2"/>
+            <Property name="horizontalGap" type="int" value="10"/>
+            <Property name="rows" type="int" value="1"/>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="butOK">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="OK"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onBtOK"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="butCancel">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Abbrechen"/>
+                <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                  <Insets value="[5, 5, 5, 5]"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onBtAbbrechen"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/DialogSerialConfig.java
new file mode 100644 (file)
index 0000000..b3abb0d
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * KoeffSpeichernDialog.java
+ *
+ * Created on 27.07.2010, 13:12:15
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialPortInfoFactory;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialPortInfo;
+import java.awt.Dimension;
+import java.awt.Point;
+import javafx.scene.control.ComboBox;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+
+/**
+ *
+ * @author steiner
+ */
+public final class DialogSerialConfig extends javax.swing.JDialog
+{
+  private boolean pressedOK;
+  private SerialPortInfo serialPortInfo;
+
+  /** Creates new form KoeffSpeichernDialog */
+  public DialogSerialConfig(java.awt.Frame parent, String title, boolean modal)
+  {
+    super(parent, title, modal);
+    initComponents();
+  }
+
+
+  @Override
+  public void setVisible (boolean visible)
+  {
+    if (visible)
+    {
+      pressedOK = false;
+      pack();
+      setMinimumSize(getPreferredSize());
+      setResizable(false);
+      setLocationRelativeTo(getParent());
+      init();
+    }
+    super.setVisible(visible);
+  }
+
+  private void init ()
+  {
+    textDesiredInterface.setText(serialPortInfo.getName());
+    updateModel(comboBaudrate, serialPortInfo.getSupportedBaudrates(), serialPortInfo.getBaudrateIndex());
+    updateModel(comboDatabits, serialPortInfo.getSupportedDatabits(), serialPortInfo.getDatabitIndex());
+    updateModel(comboParity, serialPortInfo.getSupportedParityModes(), serialPortInfo.getParityModeIndex());
+    updateModel(comboStopbits, serialPortInfo.getSupportedStopBits(), serialPortInfo.getStopBitIndex());
+  }
+
+  
+  private void updateModel (JComboBox cb, String [] values, int selectedIndex)
+  {
+    ComboBoxModel m = cb.getModel();
+    for (int i=0; i<m.getSize(); i++)
+    {
+      if (!m.getElementAt(i).equals(values[i]))
+      {
+        cb.setModel(new DefaultComboBoxModel<>(values));
+        cb.getModel().setSelectedItem(values[selectedIndex]);
+        return;
+      }
+    }
+    m.setSelectedItem(values[selectedIndex]);
+  }
+  
+  public void setSerialPortInfo (SerialPortInfo serialPortInfo)
+  {
+    this.serialPortInfo = serialPortInfo;
+  }
+
+
+  public boolean isPressedOK()
+  {
+    return pressedOK;
+  }
+
+  public void endDialogWithOK()
+  {
+    String n = textDesiredInterface.getText();
+    String b = (String)comboBaudrate.getSelectedItem();
+    String d = (String)comboDatabits.getSelectedItem();
+    String p = (String)comboParity.getSelectedItem();
+    String s = (String)comboStopbits.getSelectedItem();
+    serialPortInfo = SerialPortInfoFactory.getSerialPortInfo(n, b, d, p, s);
+    pressedOK = true;
+    dispose();    
+  }
+
+
+  public SerialPortInfo getSerialPortInfo ()
+  {
+    return serialPortInfo;
+  }
+
+  /** 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")
+  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+  private void initComponents()
+  {
+
+    panCenter = new javax.swing.JPanel();
+    jPanel1 = new javax.swing.JPanel();
+    jLabel1 = new javax.swing.JLabel();
+    jLabel2 = new javax.swing.JLabel();
+    jLabel3 = new javax.swing.JLabel();
+    jLabel4 = new javax.swing.JLabel();
+    jLabel5 = new javax.swing.JLabel();
+    jPanel2 = new javax.swing.JPanel();
+    textDesiredInterface = new javax.swing.JTextField();
+    comboBaudrate = new javax.swing.JComboBox();
+    comboDatabits = new javax.swing.JComboBox();
+    comboParity = new javax.swing.JComboBox();
+    comboStopbits = new javax.swing.JComboBox();
+    panSouth = new javax.swing.JPanel();
+    jpanButtons = new javax.swing.JPanel();
+    butOK = new javax.swing.JButton();
+    butCancel = new javax.swing.JButton();
+
+    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+    setTitle("Einstellungen");
+    setMinimumSize(new java.awt.Dimension(300, 280));
+    setResizable(false);
+
+    panCenter.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
+    panCenter.setLayout(new java.awt.GridLayout(1, 2, 5, 0));
+
+    jPanel1.setLayout(new java.awt.GridLayout(5, 0, 0, 3));
+
+    jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel1.setText("Schnittstelle");
+    jLabel1.setPreferredSize(new java.awt.Dimension(80, 16));
+    jPanel1.add(jLabel1);
+
+    jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel2.setText("Baudrate");
+    jLabel2.setPreferredSize(new java.awt.Dimension(80, 16));
+    jPanel1.add(jLabel2);
+
+    jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel3.setText("Datenbits");
+    jLabel3.setPreferredSize(new java.awt.Dimension(80, 16));
+    jPanel1.add(jLabel3);
+
+    jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel4.setText("Parity-Bit");
+    jLabel4.setPreferredSize(new java.awt.Dimension(80, 16));
+    jPanel1.add(jLabel4);
+
+    jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+    jLabel5.setText("Stopbits");
+    jLabel5.setPreferredSize(new java.awt.Dimension(80, 16));
+    jPanel1.add(jLabel5);
+
+    panCenter.add(jPanel1);
+
+    jPanel2.setLayout(new java.awt.GridLayout(5, 0, 0, 3));
+
+    textDesiredInterface.setText("COM1");
+    jPanel2.add(textDesiredInterface);
+
+    comboBaudrate.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "9600", "19200", "38400", "57600", "115200" }));
+    comboBaudrate.setSelectedIndex(3);
+    jPanel2.add(comboBaudrate);
+
+    comboDatabits.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "5", "6", "7", "8" }));
+    comboDatabits.setSelectedIndex(3);
+    jPanel2.add(comboDatabits);
+
+    comboParity.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "kein", "gerade", "ungerade" }));
+    jPanel2.add(comboParity);
+
+    comboStopbits.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1", "2" }));
+    jPanel2.add(comboStopbits);
+
+    panCenter.add(jPanel2);
+
+    getContentPane().add(panCenter, java.awt.BorderLayout.NORTH);
+
+    panSouth.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 5, 2, 5));
+
+    jpanButtons.setLayout(new java.awt.GridLayout(1, 2, 10, 0));
+
+    butOK.setText("OK");
+    butOK.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onBtOK(evt);
+      }
+    });
+    jpanButtons.add(butOK);
+
+    butCancel.setText("Abbrechen");
+    butCancel.setMargin(new java.awt.Insets(5, 5, 5, 5));
+    butCancel.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onBtAbbrechen(evt);
+      }
+    });
+    jpanButtons.add(butCancel);
+
+    panSouth.add(jpanButtons);
+
+    getContentPane().add(panSouth, java.awt.BorderLayout.SOUTH);
+
+    pack();
+  }// </editor-fold>//GEN-END:initComponents
+
+    private void onBtAbbrechen(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onBtAbbrechen
+    {//GEN-HEADEREND:event_onBtAbbrechen
+      // TODO add your handling code here:
+      dispose();
+    }//GEN-LAST:event_onBtAbbrechen
+
+    private void onBtOK(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onBtOK
+    {//GEN-HEADEREND:event_onBtOK
+      // TODO add your handling code here:
+      endDialogWithOK();
+    }//GEN-LAST:event_onBtOK
+
+
+  /**
+   * @param args the command line arguments
+   */
+  public static void main(String args[])
+  {
+    java.awt.EventQueue.invokeLater(new Runnable()
+    {
+
+      public void run()
+      {
+        DialogSerialConfig dialog = new DialogSerialConfig(new javax.swing.JFrame(), "Einstellungen", true);
+        dialog.addWindowListener(new java.awt.event.WindowAdapter()
+        {
+
+          public void windowClosing(java.awt.event.WindowEvent e)
+          {
+            System.exit(0);
+          }
+        });
+        dialog.setVisible(true);
+      }
+    });
+  }
+  // Variables declaration - do not modify//GEN-BEGIN:variables
+  private javax.swing.JButton butCancel;
+  private javax.swing.JButton butOK;
+  private javax.swing.JComboBox comboBaudrate;
+  private javax.swing.JComboBox comboDatabits;
+  private javax.swing.JComboBox comboParity;
+  private javax.swing.JComboBox comboStopbits;
+  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.JPanel jPanel1;
+  private javax.swing.JPanel jPanel2;
+  private javax.swing.JPanel jpanButtons;
+  private javax.swing.JPanel panCenter;
+  private javax.swing.JPanel panSouth;
+  private javax.swing.JTextField textDesiredInterface;
+  // End of variables declaration//GEN-END:variables
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.form b/src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.form
new file mode 100644 (file)
index 0000000..00973a8
--- /dev/null
@@ -0,0 +1,1147 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.2" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Menu class="javax.swing.JMenuBar" name="menuBar">
+      <SubComponents>
+        <Menu class="javax.swing.JMenu" name="menuFile">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Datei"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="menuFileOpen">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="&#xd6;ffnen"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuFileOpen"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator1">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuExit">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Beenden"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuExit"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="menuEdit">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Bearbeiten"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="menuEditProperties">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Einstellungen &#xb5;C"/>
+                <Property name="enabled" type="boolean" value="false"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuEditProperties"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuSerialProperties">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Serielle Schnittstelle"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuEditSerialProperties"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator2">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuCopy">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Kopieren"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuCopy"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuPaste">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Einf&#xfc;gen"/>
+                <Property name="enabled" type="boolean" value="false"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator3">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuDeleteTerminalContent">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Terminalinhalt l&#xf6;schen"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuDeleteTerminalContent"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="menuHelp">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Hilfe"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jmiHelp">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="&#xdc;ber EasyProgrammer..."/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onMenuAbout"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jmiMonitor">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Monitor"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jmiMonitoronMenuAbout"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+      </SubComponents>
+    </Menu>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" value="EasyProgrammer (JSSC)"/>
+    <Property name="iconImage" type="java.awt.Image" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+      <Connection code="appIcon" type="code"/>
+    </Property>
+    <Property name="name" type="java.lang.String" value="EasyProgrammer" noResource="true"/>
+    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[700, 383]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="menuBar" type="java.lang.String" value="menuBar"/>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <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"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,0,0,0,2,37"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JToolBar" name="toolBar">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
+            <LineBorder>
+              <Color PropertyName="color" blue="cc" green="cc" red="cc" type="rgb"/>
+            </LineBorder>
+          </Border>
+        </Property>
+        <Property name="rollover" type="boolean" value="true"/>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="First"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JButton" name="iconFileOpen">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Datei &#xf6;ffnen"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 5, 1, 5]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconFileOpen"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel7">
+          <Properties>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconRefresh">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Aktualisieren"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconRefresh"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconConnect">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Mit &#xb5;C-System verbinden"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconConnect"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconDisconnect">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Von &#xb5;C-System trennen"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconDisconnect"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel5">
+          <Properties>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconCopy">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Terminal-Inhalt in die Zwischenablage kopieren"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconCopy"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconPaste">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Inhalt der Zwischenablage als Terminal-Eingabe verwenden"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="enabled" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconPaste"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconProperties">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Terminal Einstellungen ver&#xe4;ndern"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="enabled" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconProperties"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconCleanTerminal">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Terminalinhalt l&#xf6;schen"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="enabled" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconCleanTerminal"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel6">
+          <Properties>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconDownload">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Download Hex-File"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="enabled" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconDownload"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconStop">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Stop"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="enabled" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconStop"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel8">
+          <Properties>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[10, 10]"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="iconAbout">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="&#xdc;ber EasyProgrammer (Version...)"/>
+            <Property name="borderPainted" type="boolean" value="false"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[1, 10, 1, 10]"/>
+            </Property>
+            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[30, 24]"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onIconAbout"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="panCenter">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+            <EmptyBorder bottom="2" left="2" right="2" top="2"/>
+          </Border>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="panCenterNorth">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="North"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="panSerialInterface">
+              <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="Serielle Schnittstelle"/>
+                  </Border>
+                </Property>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="First"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+              <SubComponents>
+                <Container class="javax.swing.JPanel" name="panSerialInterface2">
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="Center"/>
+                    </Constraint>
+                  </Constraints>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+                  <SubComponents>
+                    <Component class="javax.swing.JComboBox" name="comboInterface">
+                      <Properties>
+                        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+                          <StringArray count="0"/>
+                        </Property>
+                        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+                          <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                            <EmptyBorder bottom="2" left="1" right="1" top="2"/>
+                          </Border>
+                        </Property>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onComboInterface"/>
+                      </Events>
+                      <Constraints>
+                        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                          <BorderConstraints direction="North"/>
+                        </Constraint>
+                      </Constraints>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Container class="javax.swing.JPanel" name="panSerialInterfaceEast">
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="East"/>
+                    </Constraint>
+                  </Constraints>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout">
+                    <Property name="verticalGap" type="int" value="0"/>
+                  </Layout>
+                  <SubComponents>
+                    <Container class="javax.swing.JPanel" name="panSerialInterrfaceButtons">
+
+                      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                        <Property name="columns" type="int" value="0"/>
+                        <Property name="horizontalGap" type="int" value="5"/>
+                        <Property name="rows" type="int" value="1"/>
+                      </Layout>
+                      <SubComponents>
+                        <Component class="javax.swing.JButton" name="butConnect">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Verbinden"/>
+                            <Property name="enabled" type="boolean" value="false"/>
+                            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                              <Insets value="[3, 10, 3, 10]"/>
+                            </Property>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonConnect"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JButton" name="butDisconnect">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Trennen"/>
+                            <Property name="enabled" type="boolean" value="false"/>
+                            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                              <Insets value="[3, 3, 3, 3]"/>
+                            </Property>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonDisconnect"/>
+                          </Events>
+                        </Component>
+                      </SubComponents>
+                    </Container>
+                    <Container class="javax.swing.JPanel" name="jpanSerailConfig">
+
+                      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
+                      <SubComponents>
+                        <Component class="javax.swing.Box$Filler" name="filler4">
+                          <Properties>
+                            <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                              <Dimension value="[10, 32767]"/>
+                            </Property>
+                            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                              <Dimension value="[10, 0]"/>
+                            </Property>
+                            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                              <Dimension value="[10, 0]"/>
+                            </Property>
+                          </Properties>
+                          <AuxValues>
+                            <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
+                          </AuxValues>
+                        </Component>
+                        <Component class="javax.swing.JTextField" name="textSerialConfig">
+                          <Properties>
+                            <Property name="editable" type="boolean" value="false"/>
+                            <Property name="text" type="java.lang.String" value="115200,none,1.5"/>
+                            <Property name="focusable" type="boolean" value="false"/>
+                            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                              <Insets value="[0, 5, 0, 5]"/>
+                            </Property>
+                            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                              <Dimension value="[120, 27]"/>
+                            </Property>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="textSerialConfigActionPerformed"/>
+                          </Events>
+                        </Component>
+                      </SubComponents>
+                    </Container>
+                    <Component class="javax.swing.JButton" name="butSerialConfig">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Einstellungen"/>
+                        <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                          <Insets value="[3, 3, 3, 3]"/>
+                        </Property>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonSerialConfig"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+              </SubComponents>
+            </Container>
+            <Container class="javax.swing.JPanel" name="panProgramFile">
+              <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="Programmdatei (Hex-File)"/>
+                  </Border>
+                </Property>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="Last"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JButton" name="butSelectProgramFile">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Datei"/>
+                    <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                      <Insets value="[3, 10, 3, 10]"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onSelectProgramFile"/>
+                  </Events>
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="West"/>
+                    </Constraint>
+                  </Constraints>
+                </Component>
+                <Container class="javax.swing.JPanel" name="jPanel3">
+                  <Properties>
+                    <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+                      <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                        <EmptyBorder bottom="3" left="1" right="1" top="3"/>
+                      </Border>
+                    </Property>
+                  </Properties>
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="Center"/>
+                    </Constraint>
+                  </Constraints>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                    <Property name="columns" type="int" value="0"/>
+                    <Property name="rows" type="int" value="1"/>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JTextField" name="tfProgramFileName">
+                      <Properties>
+                        <Property name="editable" type="boolean" value="false"/>
+                        <Property name="toolTipText" type="java.lang.String" value=""/>
+                        <Property name="focusable" type="boolean" value="false"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="tfProgramFileNameActionPerformed"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <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.EmptyBorderInfo">
+                        <EmptyBorder bottom="3" left="1" right="1" top="3"/>
+                      </Border>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[40, 33]"/>
+                    </Property>
+                  </Properties>
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="East"/>
+                    </Constraint>
+                  </Constraints>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                    <Property name="columns" type="int" value="0"/>
+                    <Property name="rows" type="int" value="1"/>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JTextField" name="textHexSize">
+                      <Properties>
+                        <Property name="editable" type="boolean" value="false"/>
+                        <Property name="focusable" type="boolean" value="false"/>
+                      </Properties>
+                    </Component>
+                  </SubComponents>
+                </Container>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="panCenterCenter">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="10"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="Center"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+            <Property name="columns" type="int" value="0"/>
+            <Property name="rows" type="int" value="1"/>
+          </Layout>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="textTerminal">
+              <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="Terminal"/>
+                  </Border>
+                </Property>
+              </Properties>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                <Property name="columns" type="int" value="0"/>
+                <Property name="rows" type="int" value="1"/>
+              </Layout>
+            </Container>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="panCenterSouth">
+          <Properties>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="5" right="5" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="Last"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="panDownload">
+              <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="Zielsystem / Download"/>
+                  </Border>
+                </Property>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="Center"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout">
+                <Property name="alignment" type="int" value="0"/>
+              </Layout>
+              <SubComponents>
+                <Component class="javax.swing.JButton" name="butReset">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Reset"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                    <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                      <Insets value="[5, 5, 5, 5]"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonReset"/>
+                  </Events>
+                </Component>
+                <Component class="javax.swing.Box$Filler" name="filler1">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 32767]"/>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 0]"/>
+                    </Property>
+                    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 0]"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
+                  </AuxValues>
+                </Component>
+                <Component class="javax.swing.JCheckBox" name="chkResetBeforeDownload">
+                  <Properties>
+                    <Property name="selected" type="boolean" value="true"/>
+                    <Property name="text" type="java.lang.String" value="Reset"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JButton" name="butDownloadStart">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Start"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                    <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                      <Insets value="[5, 10, 5, 10]"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onDownload"/>
+                  </Events>
+                </Component>
+                <Component class="javax.swing.Box$Filler" name="filler3">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[10, 32767]"/>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[10, 0]"/>
+                    </Property>
+                    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[10, 0]"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
+                  </AuxValues>
+                </Component>
+                <Component class="javax.swing.JButton" name="butDownloadStop">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Stop"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                    <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                      <Insets value="[5, 10, 5, 10]"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonStop"/>
+                  </Events>
+                </Component>
+                <Component class="javax.swing.Box$Filler" name="filler2">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 32767]"/>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 0]"/>
+                    </Property>
+                    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[20, 0]"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.HorizontalStrut"/>
+                  </AuxValues>
+                </Component>
+                <Component class="javax.swing.JButton" name="butDownloadProperties">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Einstellungen"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                    <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                      <Insets value="[5, 5, 5, 5]"/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="butDownloadPropertiesonButtonStop"/>
+                  </Events>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Container class="javax.swing.JPanel" name="panGlobal">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="East"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.Box$Filler" name="filler5">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[32767, 10]"/>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[0, 12]"/>
+                    </Property>
+                    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[0, 12]"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
+                  </AuxValues>
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="First"/>
+                    </Constraint>
+                  </Constraints>
+                </Component>
+                <Container class="javax.swing.JPanel" name="jpanGlobalButtons">
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="Center"/>
+                    </Constraint>
+                  </Constraints>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                    <Property name="columns" type="int" value="1"/>
+                    <Property name="rows" type="int" value="2"/>
+                    <Property name="verticalGap" type="int" value="5"/>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JButton" name="butProperties">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Einstellungen &#xb5;C"/>
+                        <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                          <Insets value="[2, 2, 2, 2]"/>
+                        </Property>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="onFilePropertiesGainLost"/>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onButtonProperties"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="butRefresh">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Aktualisieren"/>
+                        <Property name="actionCommand" type="java.lang.String" value="Refresh"/>
+                        <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+                          <Insets value="[2, 2, 2, 2]"/>
+                        </Property>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="onRefresh"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Component class="javax.swing.Box$Filler" name="filler6">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[32767, 10]"/>
+                    </Property>
+                    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[0, 4]"/>
+                    </Property>
+                    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[0, 4]"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalStrut"/>
+                  </AuxValues>
+                  <Constraints>
+                    <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                      <BorderConstraints direction="Last"/>
+                    </Constraint>
+                  </Constraints>
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="panSouth">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="South"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="panSouthSouth">
+          <Properties>
+            <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+              <Color blue="cc" green="cc" red="cc" type="rgb"/>
+            </Property>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
+                <EmptyBorder bottom="5" left="6" right="5" top="5"/>
+              </Border>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+              <BorderConstraints direction="South"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JProgressBar" name="progressBar">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="West"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+            <Component class="javax.swing.JTextField" name="testUserMessage">
+              <Properties>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="text" type="java.lang.String" value="User Message"/>
+                <Property name="focusable" type="boolean" value="false"/>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="Center"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+            <Component class="javax.swing.JTextField" name="textStatus">
+              <Properties>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="horizontalAlignment" type="int" value="0"/>
+                <Property name="text" type="java.lang.String" value="Status"/>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+                  <BorderConstraints direction="East"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/EasyProgrammer.java
new file mode 100644 (file)
index 0000000..6a08978
--- /dev/null
@@ -0,0 +1,2444 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * EasyProgrammer.java
+ *
+ * Created on 20.10.2010, 12:18:57
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.data.CpuTyp;
+import at.htlkaindorf.sx.EasyProgrammer.data.ProgramFile;
+import at.htlkaindorf.sx.EasyProgrammer.libs.EasyProgrammerLib;
+import at.htlkaindorf.sx.EasyProgrammer.logging.LogWriterHandler;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import at.htlkaindorf.sx.EasyProgrammer.serial.DownloadFile;
+import at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol;
+import at.htlkaindorf.sx.EasyProgrammer.serial.ResetProtocol;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialInterface;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialPortInfo;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialPortInfoFactory;
+import at.htlkaindorf.sx.EasyProgrammer.serial.TerminalProtocol;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.util.*;
+import java.util.logging.Level;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+/**
+ *
+ * @author steiner
+ */
+public final class EasyProgrammer extends javax.swing.JFrame
+{
+  private static final Logger LOG = Logger.getLogger(EasyProgrammer.class.getName());  
+  public final String SERIAL_DEFAULT_CONFIG = "57600/8N1";
+  
+  public enum SwingWorkerTyp { REFRESH, CONNECT, LOADPROGRAMFILE, DOWNLOAD, RESET };
+  public enum MessageTyp { DEFAULT, USER, STATUS, USERANDSTATUS };
+
+  private ArrayList<String> arglist;
+  private int exitCode;
+  private CpuTyp target;
+  private boolean resetBeforeDownload;
+  private String fileName;
+  private int waitTimeMillis;
+          
+  private GUISwingWorker swingWorker;
+  private javax.swing.JScrollPane textarea;
+  private JScrollPane scrollpane;
+  protected TerminalArea terminalArea;
+  protected TerminalProtocol terminalProtocol;
+  protected DownloadProtocol downloadProtocol;
+  protected ResetProtocol resetProtocol;
+  private DialogProperties dlgProperties;
+
+  private DialogSerialConfig dialogSerialConfig;
+  private final List<SerialPortInfo> argSerialConfigs = new LinkedList<>();
+  private DialogSelectProgramFile dialogSelectProgramFile;
+  protected ProgramFile programFile;
+  protected SerialInterface serialInterface;
+  private SerialPortInfo serialPortInfo;
+  private SerialPortInfo[] availableSerialPorts;
+  private String [] processArgs;
+  //private CpuTyp target;
+  private int serverPort;
+  private java.awt.Image appIcon;
+
+
+  /** Creates new form EasyProgrammer
+   * @param arglist */
+  public EasyProgrammer(ArrayList<String> arglist)
+  {
+    this.arglist = arglist;
+    
+    try 
+    {
+      if (arglist.contains("--batch"))
+        initInBatchMode();
+      else
+        initInGUIMode();
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace(System.err);
+      return;
+    }
+    
+    String errMessage = null;
+    
+  }
+
+  
+  
+  private void initInGUIMode () throws Exception
+  {
+    String errMessage = null;
+
+    java.awt.Toolkit toolkit = this.getToolkit();
+    URL url = this.getClass().getResource ("/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png");
+    this.appIcon = Toolkit.getDefaultToolkit().createImage(url);
+
+    try
+    {
+      String version = jssc.SerialNativeInterface.getLibraryVersion();
+      String nativeVersion = jssc.SerialNativeInterface.getNativeLibraryVersion();
+      String msg = String.format("Using JSSC Version %s / Native %s", version, nativeVersion);
+      if (LOG.isInfoLogged())
+        LOG.info(msg);
+      else
+        System.out.println(msg);
+    }
+    catch (Throwable th)
+    {
+      LOG.warning("No serial library (JSSC) available");
+      JOptionPane.showMessageDialog(null, "Kein Zugriff auf Bibkliotheken für die serielle Schnittstelle",
+                                    "Fehler aufgetreten...", JOptionPane.ERROR_MESSAGE);
+      System.exit(1);
+    }
+    
+    try
+    {
+      String version = EasyProgrammerLib.getLibraryVersion();
+      String nativeVersion = EasyProgrammerLib.getNativeLibraryVersion();
+      String msg = String.format("Using EasyprogrammerLib Version %s / Native %s", version, nativeVersion);
+      if (LOG.isInfoLogged())
+        LOG.info(msg);
+      else
+        System.out.println(msg);
+    }
+    catch (Throwable th)
+    {
+      LOG.warning(th);
+    }
+    
+
+    initComponents();
+    textStatus.setPreferredSize(new Dimension(Math.max(textStatus.getPreferredSize().width, 120), textStatus.getPreferredSize().height));
+    setLookAndFeel();
+    panSerialInterface2.setLayout(new SlidingWidthLayout());
+
+
+    try
+    {
+      parseArguments();
+    }
+    catch (Exception ex)
+    {
+      String msg = ex.getMessage();
+      if (msg==null || msg.isEmpty())
+          msg = ex.getClass().getName();
+      JOptionPane.showMessageDialog(this, msg, "Fehler", JOptionPane.ERROR_MESSAGE);
+      exitCode = -150;
+      throw new Exception("Initialization in GUI mode failed", ex);
+    }
+
+    serialInterface.checkInterfaces();
+    updateComboInterface();
+    ComboBoxModel m = comboInterface.getModel();
+    if (!argSerialConfigs.isEmpty())
+    {
+      String desiredName = argSerialConfigs.get(0).getName();
+      String desiredConfig = argSerialConfigs.get(0).getConfigString();
+      nextModelItem: for (int i=0; i<m.getSize(); i++)
+      {
+        Object item = m.getElementAt(i);
+        if (item instanceof SerialPortInfo)
+        {
+          SerialPortInfo pi = (SerialPortInfo) item;
+          for (int j=0; j<argSerialConfigs.size(); j++)
+          {
+            SerialPortInfo argpi = argSerialConfigs.get(j);
+            if (pi.getName().startsWith(argpi.getName()))
+            {
+              pi.setConfiguration(argpi.getConfigString());
+              if (j==0)
+                m.setSelectedItem(item);
+              continue nextModelItem;
+            }
+          }
+          pi.setConfiguration(desiredConfig);
+        }
+      }
+    }
+    if (m.getSelectedItem() != null && m.getSelectedItem() instanceof SerialPortInfo)
+      textSerialConfig.setText( ((SerialPortInfo)m.getSelectedItem()).getConfigString());
+    
+    dialogSerialConfig = new DialogSerialConfig(this, "Serielle Schnittstelle", true);
+    
+    this.chkResetBeforeDownload.setSelected(resetBeforeDownload);
+    if (dialogSelectProgramFile.getFileName() != null)
+    {
+      tfProgramFileName.setText(dialogSelectProgramFile.getFileName());
+      tfProgramFileName.setToolTipText(dialogSelectProgramFile.getFolderName() + dialogSelectProgramFile.getFileName());
+    }
+
+    swingWorker = new GUISwingWorker(this);
+    terminalArea = new TerminalArea();
+    scrollpane =  new JScrollPane(terminalArea, 
+                                  ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
+                                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
+                                 );
+    Dimension size = new Dimension(scrollpane.getPreferredSize());
+    size.height += 60;
+    scrollpane.setPreferredSize(size);
+    terminalArea.setViewport(scrollpane.getViewport());
+    textTerminal.add(scrollpane);
+    terminalArea.requestFocus();
+
+    try 
+    {
+      terminalProtocol = new TerminalProtocol(terminalArea, serialInterface);
+      terminalArea.setTerminalProtocol(terminalProtocol);
+    }
+    catch (Exception ex)
+    {
+      serialInterface = null;
+      JOptionPane.showMessageDialog(this, ex.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE);
+      exitCode = -151;
+      throw new Exception("Initialization in GUI mode failed");
+    }
+
+
+    processArgs = null;
+
+    this.setUserMessage(null);
+    this.setStatus(null);
+    this.buttonRefresh(null);
+    
+    if (tfProgramFileName.getText() != null && tfProgramFileName.getText().length()>0)
+    {
+      try { startSwingWorkerLater(SwingWorkerTyp.LOADPROGRAMFILE); }
+      catch (Exception ex)
+      {
+        System.err.println("Cannot execute 'select program file' (" + ex.getMessage() + ")");
+      }
+    }
+    size = textHexSize.getPreferredSize();
+    size.width = Math.max(size.width, 200);
+    textHexSize.setPreferredSize(size);
+    pack();
+    setMinimumSize(new Dimension(650,500));
+    setSize(new Dimension(750,600));
+
+//    size = getPreferredSize();
+//    size.width = Math.min(size.width, 750);
+//    size.height = Math.min(size.height, 800);
+//    setMinimumSize(size);
+    
+    
+  }
+  
+  
+  private void initInBatchMode () throws Exception
+  {
+    String errMessage = null;
+    
+    try
+    {
+      parseArguments();
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace(System.err);
+      System.out.println("Error: " + ex.getMessage());
+      exitCode = -101;
+      throw new Exception("Initialization in batch mode failed");
+    }
+
+    GUISwingWorker guiSwingWorker = new GUISwingWorker(this);
+    try
+    {
+      guiSwingWorker.loadFile();
+      System.out.println("Hex-File succussfully loaded (" +
+                          this.programFile.getMemoryLength() + " Bytes)");
+    }
+    catch (Exception ex)
+    {
+      if (programFile == null || programFile.getErrorList()==null)
+        System.out.println("Error: Keine Hex-Programmdatei angegeben");
+      else
+      {
+        System.out.println("Error on loading file:");
+        ArrayList<String> errList = programFile.getErrorList();
+        for (String error : errList)
+          System.out.println("  " + error);
+      }
+      exitCode = -102;
+      throw new Exception("Initialization in batch mode failed");
+    }
+    
+    String ifc = String.format("%s (%s)", argSerialConfigs.get(0).getName(), argSerialConfigs.get(0).getConfigString());
+    DownloadFile downloadFile = new DownloadFile(argSerialConfigs.get(0), programFile);
+    try
+    {
+      downloadFile.open();
+      try
+      {
+        downloadFile.start();
+        System.out.println(String.format("serial interface %s connected.", ifc));
+        if (resetBeforeDownload)
+          downloadFile.resetTarget(target.getResetCommand());
+        downloadFile.waitOnBootloader(waitTimeMillis, true);
+        downloadFile.download(arglist.contains("--nocheck"));
+        downloadFile.close();
+        exitCode = 0;
+      }
+      catch (Exception ex)
+      {
+        downloadFile.close();
+        exitCode = -103;
+        throw new Exception("Cannot download file");
+      }
+      finally
+      {
+        System.out.println(String.format("serial interface %s disconnected.", ifc));
+      }    }
+    catch (Exception ex)
+    {
+      System.out.println(String.format("cannot open serial interface %s", ifc));
+
+    }
+  }
+  
+  private void parseArguments () throws Exception
+  {
+    int pos;
+
+    this.serverPort = -1;
+    pos = arglist.indexOf("--port");
+    if (pos>=0)
+    {
+      Scanner scanner = new Scanner(arglist.get(pos+1));
+      this.serverPort = scanner.nextInt();
+      if (this.serverPort <= 1000 || this.serverPort>65535)
+      {
+        String error = "Fehler bei der Option --port\n" + 
+                       "Server-Port '" + arglist.get(pos+1) + "' ungültig\n" +
+                       "Gültig sind Portwerte zwischen 1000 und 65535";
+        this.serverPort = -1;
+        throw new Exception(error);
+      }
+    }
+    
+    pos = arglist.indexOf("--target");
+    if (pos<0)
+      target = new CpuTyp(CpuTyp.Typ.Atmega328P);
+    else
+    {
+      for (CpuTyp.Typ cputyp : CpuTyp.Typ.values())
+      {
+        if (arglist.get(pos+1).equalsIgnoreCase(cputyp.name()))
+        {
+          target = new CpuTyp(cputyp);
+          break;
+        }
+      }
+      if (target == null)
+      {
+        String error = "Fehler bei der Option --target\n" + 
+                       "Target (CPU-Typ) '" + arglist.get(pos+1) + "' ungültig\n" +
+                       "Verfügbar sind: " + target.getAvailableNames();
+        throw new Exception(error);
+      }  
+    }
+
+    pos = arglist.indexOf("--noreset");
+    if (pos>=0)
+      resetBeforeDownload = false;
+    else
+      resetBeforeDownload = true;
+
+
+    pos = arglist.indexOf("--resetcmd");
+    String resetCmd = "@R";
+    if (pos>=0)
+    {
+      if (arglist.size()>(pos+1) && !arglist.get(pos+1).startsWith("-"))
+        resetCmd = arglist.get(pos+1);
+    }
+    //target.setResetCommand(resetCmd + "\r\n");    
+    target.setResetCommand(resetCmd);
+
+    resetCmd = null;
+    pos = arglist.indexOf("--resetseq");
+    if (pos>=0)
+    {
+      if (arglist.size()>(pos+1) && !arglist.get(pos+1).startsWith("-"))
+        resetCmd = arglist.get(pos+1);
+    }
+    if (resetCmd != null) 
+      target.setResetCommand(resetCmd);
+    
+    target.setBootloaderSize(2048);     
+
+    pos = arglist.indexOf("--wait");
+    int waitTime = 10000;
+    if (pos>=0 && arglist.size()>(pos+1) && !arglist.get(pos+1).startsWith("-"))
+    {
+      try
+      {
+        waitTime = Integer.parseInt(arglist.get(pos+1));
+        if (waitTime<100)
+          throw new Exception((String)null);
+      }
+      catch (Exception ex)
+      {
+        String error = "Fehler bei der Option --wait\n" + 
+                       "Hinter '--wait' befindet sich keine gültige Zahl\n" +
+                       "Die Zahl muss >= 100 (ms) sein. Beispiel: --wait 5000";
+        throw new Exception(error);
+      }
+    }
+    this.waitTimeMillis = waitTime;
+    
+    System.out.format("Target = %s\n", target==null ? "unknown" : target.getDescription());
+    
+    try
+    {
+      serialInterface = new SerialInterface();
+      jmiMonitor.setVisible(serialInterface.getMonitor() != null);
+      downloadProtocol = null;
+      resetProtocol = null; //new ResetProtocol(terminalArea, serialInterface);
+    }
+    catch (Exception ex)
+    {
+      String error = "Schwerwiegender Fehler\n" +
+                     "Es fehlen die Programm-Bibliotheken für die serielle Schnittstelle!";
+      throw new Exception(error);
+    }
+
+    dlgProperties = new DialogProperties(this, "Einstellungen", true);
+    //this.chkResetBeforeDownload.setSelected(resetBeforeDownload);
+    this.dlgProperties.setCpuTyp(target);
+    
+    this.dialogSelectProgramFile = new DialogSelectProgramFile(this);
+    this.programFile = new ProgramFile(this.dialogSelectProgramFile,  this.dlgProperties.getCpuTyp());
+
+    pos = arglist.indexOf("--hexfile");
+    if (pos>=0 && arglist.size()>pos+1)
+    {
+      String fname = arglist.get(pos+1);
+      File file = null;
+      if (dialogSelectProgramFile.getFolderName() != null)
+        file = new File(dialogSelectProgramFile.getFolderName() + fname);
+      else
+        file = new File(fname);
+        
+      if (file != null && file.exists() && file.isFile())
+      {
+        String fileName = file.getName();
+        String dirName = file.getPath();
+        dirName = dirName.substring(0, dirName.length()-fileName.length());
+        dialogSelectProgramFile.setFolderName(dirName);
+        dialogSelectProgramFile.setFileName(fileName);
+        //System.out.println("Folder " + dialogSelectProgramFile.getFolderName());
+        //System.out.println("Dir " + dirName);
+        //System.out.println("File " + fileName);
+        System.out.println("File '" + fname + "' will be used");
+      }
+      else
+        System.out.println("File '" + fname + "' not found");
+    }
+
+    pos = arglist.indexOf("--interface-names");
+    if (pos>=0)
+    {
+      try
+      {
+        System.out.println("Interface names = " + arglist.get(pos+1));
+        String [] portNames = arglist.get(pos+1).split(",");
+        for (String n : portNames)
+          argSerialConfigs.add(SerialPortInfoFactory.getSerialPortInfo(n, SERIAL_DEFAULT_CONFIG));
+      }
+      catch (Exception ex)
+      {
+        String error = "Fehler bei der Option --interface-names\n" + 
+                       "'" + arglist.get(pos+1) + "' ist fehlerhaft";
+        throw new IllegalArgumentException(error, ex);
+      }
+    }
+
+    pos = arglist.indexOf("--interface");
+    if (pos>=0)
+    {
+      try
+      {
+        String config = arglist.get(pos+1);
+        String [] interfaces = config.split(";");
+        for (String ifc : interfaces)
+        {
+          String serialConfig;
+          String serialName;
+          String [] f = ifc.split(":");
+          switch (f.length)
+          {
+            case 1: serialName = f[0]; serialConfig = SERIAL_DEFAULT_CONFIG; break;
+            case 2: serialName = f[0]; serialConfig = f[1]; break;
+            default: throw new Exception(String.format("unvalid serial configuration '%s'", config));
+          }
+          argSerialConfigs.add(SerialPortInfoFactory.getSerialPortInfo(serialName, serialConfig));
+        }  
+      }
+      catch (Exception ex)
+      {
+        String error = "Fehler bei der Option --interface\n" + 
+                       "'" + arglist.get(pos+1) + "' ist fehlerhaft";
+        throw new IllegalArgumentException(error, ex);
+      }
+    }
+    
+    if (!argSerialConfigs.isEmpty())
+      System.out.println(String.format("Desired Interface = %s (%s)", argSerialConfigs.get(0).getName(), argSerialConfigs.get(0).getConfigString()));
+
+    pos = arglist.indexOf("--directory");
+    if (pos>=0 && arglist.size()>pos+1)
+    {
+      String dirname = arglist.get(pos+1);
+      File dir = new File(dirname);
+      if (dir != null && dir.exists())
+      {
+         dialogSelectProgramFile.setFolderName(dirname);
+         System.out.println("Directory '" + dirname + "' will be used");
+      }
+      else
+        System.out.println("Directory '" + dirname + "' not found");
+    }
+  }
+  
+  public int executeInBatchMode ()
+  {
+    System.out.println("Done");
+    return exitCode;
+  }
+  
+  
+  private void setLookAndFeel()
+  {
+    if (System.getProperty("os.name").toLowerCase().contains("win"))
+    {
+      try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); }
+      catch (ClassNotFoundException ex) {  }
+      catch (InstantiationException ex) {  }
+      catch (IllegalAccessException ex) {  }
+      catch (UnsupportedLookAndFeelException ex) {  }
+      SwingUtilities.updateComponentTreeUI(this);
+    }
+  }
+
+  protected void setUserMessage (String msg)
+  {
+    this.testUserMessage.setText(msg);
+  }
+
+  
+  public CpuTyp getCpuTyp ()
+  {
+    return dlgProperties.getCpuTyp();
+  }
+
+  public int getServerPort ()
+  {
+    return this.serverPort;
+  }
+
+
+  public int getWaitTimeMillis ()
+  {
+    return waitTimeMillis;
+  }
+
+  
+  
+  public boolean containsArgument (String arg)
+  {
+    if (arglist != null && arglist.contains(arg))
+      return true;
+    else
+      return false;
+  }
+
+
+  private void startProcess (String status, String [] arg)
+  {
+    setStatus(status);
+    this.processArgs = arg;
+    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+  }
+
+  private void startProcess (String status, String arg)
+  {
+    setStatus(status);
+    this.processArgs = new String [1];
+    this.processArgs[0] = arg;
+    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+  }
+
+  protected void startProcess (String status)
+  {
+    setStatus(status);
+    this.processArgs = null;
+    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+  }
+
+  protected void endProcess ()
+  {
+    setStatus(null);
+    this.processArgs = null;
+    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+  }
+
+  protected void setStatus (String status)
+  {
+    this.textStatus.setText(status);
+  }
+
+
+
+  private void runDialogProperties ()
+  {
+    String cpu = dlgProperties.getCpuTyp().getName();
+    dlgProperties.setVisible(true);
+    if ( !dlgProperties.isPressedOK())
+      return;
+    String ncpu = dlgProperties.getCpuTyp().getName();
+    if (!cpu.equals(ncpu) && programFile != null)
+    {
+      try
+      {
+        programFile.setCpu(dlgProperties.getCpuTyp());
+        LOG.info(String.format("Reloading program file with new cpu %s", ncpu));
+      }
+      catch (Exception ex)
+      {
+        LOG.warning(ex);
+      }
+        
+    }
+    
+    
+  }
+
+  private void runDialogSerialProperties ()
+  {
+    dialogSerialConfig.setSerialPortInfo((SerialPortInfo)comboInterface.getSelectedItem());
+    dialogSerialConfig.setVisible(true);
+
+    if (!dialogSerialConfig.isPressedOK())
+      return;
+    
+    serialPortInfo = dialogSerialConfig.getSerialPortInfo();
+    DefaultComboBoxModel model = (DefaultComboBoxModel) comboInterface.getModel();
+    for (int i=0; i<model.getSize(); i++)
+    {
+      SerialPortInfo spi = (SerialPortInfo)model.getElementAt(i);
+      if (spi!=serialPortInfo)
+        continue;
+      comboInterface.setSelectedIndex(i);
+      textSerialConfig.setText(serialPortInfo.getConfigString()); 
+      //LOG.debug(textSerialConfig.getPreferredSize().toString());
+      //textSerialConfig.setColumns(textSerialConfig.getText().length());
+      //LOG.debug(textSerialConfig.getPreferredSize().toString());
+      panSerialInterface.validate();
+      panSerialInterface.repaint();
+      return;
+    }
+    model.addElement(serialPortInfo);
+    comboInterface.setSelectedIndex(model.getSize()-1);
+    textSerialConfig.setText(serialPortInfo.getConfigString());
+    textSerialConfig.setColumns(textSerialConfig.getText().length());
+    panSerialInterface.validate();
+    panSerialInterface.repaint();
+  }
+
+  protected void updateButtons ()
+  {
+    //LOG.debug("Update Buttons", 2);
+    this.menuEditProperties.setEnabled(true);
+    this.butProperties.setEnabled(true);
+
+    updateSerialButtons();
+    updateDownloadButtons();
+    iconCleanTerminal.setEnabled(true);
+    
+    if (this.swingWorker != null)
+    {
+      if (this.swingWorker.isDownloadInProgress() || this.swingWorker.isResetInProgress())
+      {
+        this.butSelectProgramFile.setEnabled(false);
+        this.butReset.setEnabled(false);
+        this.menuFileOpen.setEnabled(false);
+        this.iconFileOpen.setEnabled(false);
+        this.butRefresh.setEnabled(false);
+        this.iconRefresh.setEnabled(false);
+        this.comboInterface.setEnabled(false);
+        return;
+      }
+    }
+
+    this.butSelectProgramFile.setEnabled(true);
+    this.menuFileOpen.setEnabled(true);
+    this.iconFileOpen.setEnabled(true);
+    if (comboInterface.getModel().getSize()>0)
+      this.comboInterface.setEnabled(true);
+    if (serialInterface != null && serialInterface.isConnected())
+    {
+      this.butRefresh.setEnabled(false);
+      this.iconRefresh.setEnabled(false);
+      this.comboInterface.setEnabled(false);
+    }
+    else
+    {
+      this.butRefresh.setEnabled(true);
+      this.butRefresh.setEnabled(true);
+      this.iconRefresh.setEnabled(true);
+    }
+  }
+
+
+  protected void updateSerialButtons()
+  {
+    //LOG.debug("Serial Buttons update", 2);
+    if (this.swingWorker != null)
+    {
+      if (this.swingWorker.isDownloadInProgress() || this.swingWorker.isResetInProgress())
+      {
+        this.comboInterface.setEnabled(false);
+        this.butConnect.setEnabled(false);
+        this.butDisconnect.setEnabled(false);
+        this.iconConnect.setEnabled(false);
+        this.iconDisconnect.setEnabled(false);
+        this.butReset.setEnabled(false);
+        this.butSerialConfig.setEnabled(false);
+        if (this.terminalArea != null)
+          this.terminalArea.setFocusBlocked(true);
+        return;
+      }
+    }
+
+    SerialPortInfo name = (SerialPortInfo) comboInterface.getSelectedItem();
+    if (name != null)
+      textSerialConfig.setText(name.getConfigString());
+    else
+      textSerialConfig.setText(null);
+    
+    if (name == null)
+    {
+      this.comboInterface.setEnabled(false);
+      this.butConnect.setEnabled(false);
+      this.butDisconnect.setEnabled(false);
+      this.iconConnect.setEnabled(false);
+      this.iconDisconnect.setEnabled(false);
+      this.butReset.setEnabled(false);
+      this.butSerialConfig.setEnabled(false);
+      if (this.terminalArea != null)
+        this.terminalArea.setFocusBlocked(true);
+    }
+    else if (!serialInterface.isInterfaceAvailable(name) && serialInterface.getPort()==null)
+    {
+      this.comboInterface.setEnabled(false);
+      this.butConnect.setEnabled(false);
+      this.butDisconnect.setEnabled(false);
+      this.iconConnect.setEnabled(false);
+      this.iconDisconnect.setEnabled(false);
+      this.butReset.setEnabled(false);
+      this.butSerialConfig.setEnabled(true);
+      if (this.terminalArea != null)
+        this.terminalArea.setFocusBlocked(true);
+    }
+    else if(serialInterface.isInterfaceAvailable(name) == true && serialInterface.getPort() == null)
+    {
+      this.comboInterface.setEnabled(true);
+      this.butConnect.setEnabled(true);
+      this.butDisconnect.setEnabled(false);
+      this.iconConnect.setEnabled(true);
+      this.iconDisconnect.setEnabled(false);
+      this.butReset.setEnabled(false);
+      this.butSerialConfig.setEnabled(true);
+      if (this.terminalArea != null)
+        this.terminalArea.setFocusBlocked(true);
+    }
+    else
+    {
+      this.comboInterface.setEnabled(false);
+      this.butConnect.setEnabled(false);
+      this.butDisconnect.setEnabled(true);
+      this.iconConnect.setEnabled(false);
+      this.iconDisconnect.setEnabled(true);
+      this.butReset.setEnabled(true);
+      this.butSerialConfig.setEnabled(false);
+      if (this.terminalArea != null)
+        this.terminalArea.setFocusBlocked(false);
+    }
+  }
+
+  public void setFocusToTerminal ()
+  {
+    if (this.terminalArea == null)
+      return;
+
+    if (this.terminalArea.isFocusBlocked())
+      return;
+
+    this.terminalArea.requestFocus();
+  }
+  
+
+  protected void updateComboInterface()
+  {
+    boolean update = false;
+    ArrayList<SerialPortInfo> names = null;
+
+    SerialPortInfo selected = (SerialPortInfo) this.comboInterface.getSelectedItem();
+    ArrayList<SerialPortInfo> avail = serialInterface.getInterfaceNameList();
+    if (avail.contains(selected))
+      names = avail;
+    else
+    {
+      names = new  ArrayList<>(avail);
+      if (selected != null)
+        names.add(selected);
+      Collections.sort(names);
+    }
+    comboInterface.setModel(new DefaultComboBoxModel(names.toArray()));
+    if (selected != null)
+    {
+      comboInterface.setSelectedItem(selected);
+      comboInterface.validate();
+      comboInterface.repaint();
+    }
+    else if (!names.isEmpty())
+    {  
+      comboInterface.setSelectedIndex(0);
+      selected = (SerialPortInfo)comboInterface.getSelectedItem();
+    }
+    if (selected != null)
+    {
+      textSerialConfig.setText(selected.getConfigString());
+      panSerialInterface.validate();
+      panSerialInterface.repaint();
+    }
+    //LOG.debug(String.format("updateComboInterface avail=%d, selected=%s", avail.size(), selected));
+  }
+
+
+  protected void updateDownloadButtons()
+  {
+    if (this.swingWorker != null)
+    {
+      if (this.swingWorker.isDownloadInProgress())
+      {
+        butReset.setEnabled(false);
+        butDownloadStart.setEnabled(false);
+        iconDownload.setEnabled(false);
+        butDownloadStop.setEnabled(true);
+        iconStop.setEnabled(true);
+        this.chkResetBeforeDownload.setEnabled(false);
+        return;
+      }
+      if (this.swingWorker.isResetInProgress())
+      {
+        butReset.setEnabled(false);
+        butDownloadStart.setEnabled(false);
+        iconDownload.setEnabled(false);
+        butDownloadStop.setEnabled(false);
+        iconStop.setEnabled(false);
+        this.chkResetBeforeDownload.setEnabled(false);
+        return;
+      }
+    }
+
+    if (this.serialInterface.isConnected() == false)
+    {
+      butReset.setEnabled(false);
+      butDownloadStart.setEnabled(false);
+      iconDownload.setEnabled(false);
+      butDownloadStop.setEnabled(false);
+      iconStop.setEnabled(false);
+      this.chkResetBeforeDownload.setEnabled(false);
+      return;
+    }
+
+    if (this.programFile != null && this.programFile.getMemoryLength()>0)
+    {
+      butReset.setEnabled(true);
+      butDownloadStart.setEnabled(true);
+      iconDownload.setEnabled(true);
+      butDownloadStop.setEnabled(false);
+      iconStop.setEnabled(false);
+      this.chkResetBeforeDownload.setEnabled(true);
+      return;
+    }
+
+    butReset.setEnabled(true);
+    butDownloadStart.setEnabled(false);
+    iconDownload.setEnabled(false);
+    butDownloadStop.setEnabled(false);
+    iconStop.setEnabled(false);
+    this.chkResetBeforeDownload.setEnabled(false);
+  }
+
+
+  protected void updateTextHexSize()
+  {
+    ArrayList errList = programFile.getErrorList();
+    
+    if (programFile == null || dialogSelectProgramFile==null || dialogSelectProgramFile.getFileName() == null)
+    {
+      textHexSize.setText(null);
+      textHexSize.setToolTipText(null);
+      return;
+    }
+
+    String err = null;
+    if (programFile.getErrorList() != null && programFile.getErrorList().size()>0)
+    {
+      StringBuilder sb = new StringBuilder(128);
+
+      for (int i=0; i<errList.size(); i++)
+      {
+        if (programFile.getErrorList().get(i) instanceof String && sb.length()==0)
+        {
+          sb.append("Erster ");
+          sb.append((String)errList.get(i));
+        }
+      }
+      err = sb.toString();
+    }
+
+    if (programFile.getMemoryLength()==0)
+    {
+      textHexSize.setText("0 Bytes, Datei fehlerhaft");
+      textHexSize.setToolTipText(err);
+      return;
+    }
+
+    if (programFile.getErrorList()!=null && programFile.getMemoryLength()>0)
+    {
+      textHexSize.setText(programFile.getMemoryLength() + " Bytes, Datei fehlerhaft");
+      textHexSize.setToolTipText(err);
+      return;
+    }
+
+
+    // Program file ok
+    textHexSize.setText(programFile.getMemoryLength() + " Bytes, keine Fehler" );
+    textHexSize.setToolTipText(programFile.getLastModifiedString());
+  }
+
+
+  public String getProgramFileName ()
+  {
+    return dialogSelectProgramFile.getFileName();
+  }
+
+  public SerialPortInfo getSerialPortInfo ()
+  {
+    return serialPortInfo;
+  }
+
+  private void comboInterface (java.awt.event.ActionEvent evt)
+  {
+    updateSerialButtons();
+  }
+
+
+  public void execSwingWorkerProcess (SwingWorkerTyp swt, MessageTyp mt, List<String> chunks )
+  {
+    switch (swt)
+    {
+      case REFRESH: case CONNECT: case LOADPROGRAMFILE:
+        switch (chunks.size())
+        {
+          case 1:
+            setUserMessage((String)chunks.get(0));
+            return;
+
+          case 2:
+            setUserMessage((String)chunks.get(0));
+            setStatus((String)chunks.get(1));
+            return;
+        }
+        break;
+    }
+    throw new RuntimeException ("execSwingWorkerProcess - Unknown Typ/Message");
+  }
+
+
+  public void execSwingWorkerDone (SwingWorkerTyp swt, int result)
+  {
+    switch (swt)
+    {
+      case REFRESH:
+        //** BUTTON REFRESH START ********************************************
+        updateComboInterface();
+        updateSerialButtons();
+        if (result==0)
+          setUserMessage("Aktualisierung erfolgreich beendet");
+        else
+          setUserMessage("Fehler bei der Aktualisierung");
+        return;
+
+
+      case CONNECT:
+        switch (result)
+        {
+          case 0:
+            setUserMessage("Verbindung zu '" + serialPortInfo.getName() + "' erfolgreich geöffnet");
+            break;
+
+          default:
+            setUserMessage("Fehler: Schnittstelle kann nicht geöffnet werden");
+        }
+        updateButtons();
+        updateSerialButtons();
+        return;
+
+
+      case LOADPROGRAMFILE:
+        switch (result)
+        {
+          case 0: // thread ends with no errors
+            textHexSize.setText(programFile.getMemoryLength() + " Bytes, keine Fehler" );
+            textHexSize.setToolTipText(null);
+            setUserMessage("Programmdatei '" + dialogSelectProgramFile.getFileName() + "' erfolgreich geladen");
+            return;
+
+          case -1: // thread ends with "no memory byte found"
+            textHexSize.setText(programFile.getMemoryLength() + " Bytes, Datei fehlerhaft" );
+            textHexSize.setToolTipText(null);
+            setUserMessage("Fehlerhafte Programmdatei (keine Intel-Hex Datei?)");
+            return;
+
+          case -2: // thread ends with some errors in Intel Hex File
+            if (programFile.getErrorList() == null)
+            {
+              textHexSize.setText(programFile.getMemoryLength() + " Bytes, Datei fehlerhaft" );
+              textHexSize.setToolTipText(null);
+            }
+            else
+            {
+              ArrayList errList = programFile.getErrorList();
+              textHexSize.setText(programFile.getMemoryLength() + " Bytes, " + errList.size() + " Fehler" );
+              StringBuilder sb = new StringBuilder(128);
+              for (int i=0; i<errList.size(); i++)
+              {
+                if (errList.get(i) instanceof String && sb.length()==0)
+                {
+                  sb.append("Erster ");
+                  sb.append((String)errList.get(i));
+                }
+              }
+              textHexSize.setToolTipText(sb.toString());
+            }
+            setUserMessage("Fehlerhafte Programmdatei (Intel-Hex Formatfehler)");
+            return;
+
+          case -3: // thread ends with Exception
+            textHexSize.setText(programFile.getMemoryLength() + " Bytes, Datei fehlerhaft" );
+            textHexSize.setToolTipText(null);
+            setUserMessage("Fehlerhafte Programmdatei (Intel-Hex Formatfehler)");
+            return;
+
+          default:
+            textHexSize.setText(programFile.getMemoryLength() + " Bytes, Datei fehlerhaft" );
+            textHexSize.setToolTipText(null);
+            setUserMessage("Laden fehlgeschlagen (interner Fehler " +  + result + ")");
+            return;
+        }
+    }
+    throw new RuntimeException ("execSwingWorkerDone - Unknown typ/result");
+  }
+
+  
+  public void startSwingWorkerLater (SwingWorkerTyp typ)
+  {
+    this.swingWorker.startLater(typ);
+  }
+
+  
+  public void startSwingWorker (SwingWorkerTyp typ) throws Exception
+  {
+    if (this.swingWorker.isUsed())
+      throw new Exception("SwingWorker already used");
+
+    this.swingWorker.start(typ);
+  }
+
+
+  private void buttonRefresh (java.awt.event.ActionEvent evt)
+  {
+    this.setProgressBar(-1);
+    try { startSwingWorker(SwingWorkerTyp.REFRESH); }
+    catch (Exception ex)
+    {
+      System.err.println("Cannot execute 'refresh' (" + ex.getMessage() + ")");
+    }
+  }
+
+
+  private void buttonConnect(java.awt.event.ActionEvent evt)
+  {
+    serialPortInfo = (SerialPortInfo)comboInterface.getSelectedItem();
+    this.setProgressBar(-1);
+    try { startSwingWorker(SwingWorkerTyp.CONNECT); }
+    catch (Exception ex)
+    {
+      System.err.println("Cannot execute 'connect' (" + ex.getMessage() + ")");
+    }
+  }
+
+
+  private void buttonDisconnect(java.awt.event.ActionEvent evt)
+  {
+    serialInterface.disconnect();
+    this.setUserMessage("Verbindung geschlossen");
+    updateButtons();
+    updateSerialButtons();
+    updateDownloadButtons();
+    this.setProgressBar(-1);
+  }
+
+
+  private void buttonSelectProgramFile (java.awt.event.ActionEvent evt)
+  {
+    this.setProgressBar(-1);
+    this.dialogSelectProgramFile.setVisible(true);
+    if (this.dialogSelectProgramFile.isPressedOK())
+    {
+      tfProgramFileName.setText(dialogSelectProgramFile.getFileName());
+      tfProgramFileName.setToolTipText(dialogSelectProgramFile.getFolderName() + dialogSelectProgramFile.getFileName());
+
+      try { startSwingWorker(SwingWorkerTyp.LOADPROGRAMFILE); }
+      catch (Exception ex)
+      {
+        System.err.println("Cannot execute 'select program file' (" + ex.getMessage() + ")");
+      }
+   }
+  }
+
+  public String handleServerRequest (String command)
+  {
+    //System.out.println("Request eingetroffen: " + command);
+    if (command.equals("download"))
+    {
+      if (this.serialInterface.isConnected()==false)
+        return "download fails, target not connected";
+
+      buttonDownloadStart(null);
+      return "start download";
+    }
+
+    if (command.equals("connect"))
+    {
+      if (this.serialInterface.isConnected())
+        return "target is already connected";
+
+      buttonConnect(null);
+      return "start connect";
+    }
+
+    if (command.startsWith("send_") && command.length()==6)
+    {
+      char c = command.charAt(5);
+      this.serialInterface.write(this, c);
+      return (char)c + " gesendet";
+    }
+    
+    return "error (unvalid request)";
+  }
+
+
+  private void buttonDownloadStart (java.awt.event.ActionEvent evt)
+  {
+    this.setProgressBar(-1);
+    this.programFile.setDownloadModeFast(false);
+    try { startSwingWorker(SwingWorkerTyp.DOWNLOAD); }
+    catch (Exception ex)
+    {
+      System.err.println("Cannot execute 'Download' (" + ex.getMessage() + ")");
+    }
+  }
+
+  
+  private void buttonStop (java.awt.event.ActionEvent evt)
+  {
+    if (this.swingWorker == null || this.swingWorker.isDownloadInProgress()==false)
+      return;
+
+    this.swingWorker.stopDownload();
+  }
+
+
+  private void buttonReset (java.awt.event.ActionEvent evt)
+  {
+    this.setProgressBar(-1);
+    try { startSwingWorker(SwingWorkerTyp.RESET); }
+    catch (Exception ex)
+    {
+      System.err.println("Cannot execute 'reset' (" + ex.getMessage() + ")");
+    }
+  }
+
+
+  protected void setProgressBar (int value)
+  {
+    if (value<0)
+    {
+      this.progressBar.setValue(0);
+      this.progressBar.setStringPainted(false);
+      this.progressBar.setString(null);
+    }
+    else
+    {
+      this.progressBar.setValue(value);
+      this.progressBar.setStringPainted(true);
+      if (value < 100)
+        this.progressBar.setString(String.format("%3d %%", value));
+      else
+      this.progressBar.setString("Fertig");
+    }
+  }
+
+  public void copyToClipBoard () 
+  {
+    this.terminalArea.copyToClipBoard();
+  }
+
+  public void cleanTerminalContent ()
+  {
+    this.terminalArea.deleteContent();
+    this.invalidate();
+    this.repaint();
+  }
+
+  public boolean isResetBeforeDownloadSelected ()
+  {
+    return chkResetBeforeDownload.isSelected();
+  }
+
+  /** 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")
+  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+  private void initComponents()
+  {
+
+    toolBar = new javax.swing.JToolBar();
+    iconFileOpen = new javax.swing.JButton();
+    jLabel7 = new javax.swing.JLabel();
+    iconRefresh = new javax.swing.JButton();
+    jLabel1 = new javax.swing.JLabel();
+    iconConnect = new javax.swing.JButton();
+    iconDisconnect = new javax.swing.JButton();
+    jLabel5 = new javax.swing.JLabel();
+    iconCopy = new javax.swing.JButton();
+    iconPaste = new javax.swing.JButton();
+    iconProperties = new javax.swing.JButton();
+    iconCleanTerminal = new javax.swing.JButton();
+    jLabel6 = new javax.swing.JLabel();
+    iconDownload = new javax.swing.JButton();
+    iconStop = new javax.swing.JButton();
+    jLabel8 = new javax.swing.JLabel();
+    iconAbout = new javax.swing.JButton();
+    panCenter = new javax.swing.JPanel();
+    panCenterNorth = new javax.swing.JPanel();
+    panSerialInterface = new javax.swing.JPanel();
+    panSerialInterface2 = new javax.swing.JPanel();
+    comboInterface = new javax.swing.JComboBox();
+    panSerialInterfaceEast = new javax.swing.JPanel();
+    panSerialInterrfaceButtons = new javax.swing.JPanel();
+    butConnect = new javax.swing.JButton();
+    butDisconnect = new javax.swing.JButton();
+    jpanSerailConfig = new javax.swing.JPanel();
+    filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
+    textSerialConfig = new javax.swing.JTextField();
+    butSerialConfig = new javax.swing.JButton();
+    panProgramFile = new javax.swing.JPanel();
+    butSelectProgramFile = new javax.swing.JButton();
+    jPanel3 = new javax.swing.JPanel();
+    tfProgramFileName = new javax.swing.JTextField();
+    jPanel4 = new javax.swing.JPanel();
+    textHexSize = new javax.swing.JTextField();
+    panCenterCenter = new javax.swing.JPanel();
+    textTerminal = new javax.swing.JPanel();
+    panCenterSouth = new javax.swing.JPanel();
+    panDownload = new javax.swing.JPanel();
+    butReset = new javax.swing.JButton();
+    filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 32767));
+    chkResetBeforeDownload = new javax.swing.JCheckBox();
+    butDownloadStart = new javax.swing.JButton();
+    filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 0), new java.awt.Dimension(10, 32767));
+    butDownloadStop = new javax.swing.JButton();
+    filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 32767));
+    butDownloadProperties = new javax.swing.JButton();
+    panGlobal = new javax.swing.JPanel();
+    filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 12), new java.awt.Dimension(0, 12), new java.awt.Dimension(32767, 10));
+    jpanGlobalButtons = new javax.swing.JPanel();
+    butProperties = new javax.swing.JButton();
+    butRefresh = new javax.swing.JButton();
+    filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 4), new java.awt.Dimension(0, 4), new java.awt.Dimension(32767, 10));
+    panSouth = new javax.swing.JPanel();
+    panSouthSouth = new javax.swing.JPanel();
+    progressBar = new javax.swing.JProgressBar();
+    testUserMessage = new javax.swing.JTextField();
+    textStatus = new javax.swing.JTextField();
+    menuBar = new javax.swing.JMenuBar();
+    menuFile = new javax.swing.JMenu();
+    menuFileOpen = new javax.swing.JMenuItem();
+    jSeparator1 = new javax.swing.JPopupMenu.Separator();
+    menuExit = new javax.swing.JMenuItem();
+    menuEdit = new javax.swing.JMenu();
+    menuEditProperties = new javax.swing.JMenuItem();
+    menuSerialProperties = new javax.swing.JMenuItem();
+    jSeparator2 = new javax.swing.JPopupMenu.Separator();
+    menuCopy = new javax.swing.JMenuItem();
+    menuPaste = new javax.swing.JMenuItem();
+    jSeparator3 = new javax.swing.JPopupMenu.Separator();
+    menuDeleteTerminalContent = new javax.swing.JMenuItem();
+    menuHelp = new javax.swing.JMenu();
+    jmiHelp = new javax.swing.JMenuItem();
+    jmiMonitor = new javax.swing.JMenuItem();
+
+    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+    setTitle("EasyProgrammer (JSSC)");
+    setIconImage(appIcon);
+    setName("EasyProgrammer"); // NOI18N
+    setPreferredSize(new java.awt.Dimension(700, 383));
+
+    toolBar.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204)));
+    toolBar.setRollover(true);
+
+    iconFileOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif"))); // NOI18N
+    iconFileOpen.setToolTipText("Datei öffnen");
+    iconFileOpen.setBorderPainted(false);
+    iconFileOpen.setFocusable(false);
+    iconFileOpen.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconFileOpen.setMargin(new java.awt.Insets(1, 5, 1, 5));
+    iconFileOpen.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconFileOpen.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconFileOpen.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconFileOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconFileOpen.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconFileOpen(evt);
+      }
+    });
+    toolBar.add(iconFileOpen);
+
+    jLabel7.setMaximumSize(new java.awt.Dimension(10, 10));
+    jLabel7.setMinimumSize(new java.awt.Dimension(10, 10));
+    jLabel7.setPreferredSize(new java.awt.Dimension(10, 10));
+    toolBar.add(jLabel7);
+
+    iconRefresh.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif"))); // NOI18N
+    iconRefresh.setToolTipText("Aktualisieren");
+    iconRefresh.setBorderPainted(false);
+    iconRefresh.setFocusable(false);
+    iconRefresh.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconRefresh.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconRefresh.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconRefresh.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconRefresh.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconRefresh.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconRefresh.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconRefresh(evt);
+      }
+    });
+    toolBar.add(iconRefresh);
+
+    jLabel1.setMaximumSize(new java.awt.Dimension(10, 10));
+    jLabel1.setMinimumSize(new java.awt.Dimension(10, 10));
+    jLabel1.setPreferredSize(new java.awt.Dimension(10, 10));
+    toolBar.add(jLabel1);
+
+    iconConnect.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png"))); // NOI18N
+    iconConnect.setToolTipText("Mit µC-System verbinden");
+    iconConnect.setBorderPainted(false);
+    iconConnect.setFocusable(false);
+    iconConnect.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconConnect.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconConnect.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconConnect.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconConnect.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconConnect.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconConnect.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconConnect(evt);
+      }
+    });
+    toolBar.add(iconConnect);
+
+    iconDisconnect.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png"))); // NOI18N
+    iconDisconnect.setToolTipText("Von µC-System trennen");
+    iconDisconnect.setBorderPainted(false);
+    iconDisconnect.setFocusable(false);
+    iconDisconnect.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconDisconnect.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconDisconnect.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconDisconnect.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconDisconnect.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconDisconnect.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconDisconnect.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconDisconnect(evt);
+      }
+    });
+    toolBar.add(iconDisconnect);
+
+    jLabel5.setMaximumSize(new java.awt.Dimension(10, 10));
+    jLabel5.setMinimumSize(new java.awt.Dimension(10, 10));
+    jLabel5.setPreferredSize(new java.awt.Dimension(10, 10));
+    toolBar.add(jLabel5);
+
+    iconCopy.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif"))); // NOI18N
+    iconCopy.setToolTipText("Terminal-Inhalt in die Zwischenablage kopieren");
+    iconCopy.setBorderPainted(false);
+    iconCopy.setFocusable(false);
+    iconCopy.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconCopy.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconCopy.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconCopy.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconCopy.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconCopy.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconCopy.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconCopy(evt);
+      }
+    });
+    toolBar.add(iconCopy);
+
+    iconPaste.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif"))); // NOI18N
+    iconPaste.setToolTipText("Inhalt der Zwischenablage als Terminal-Eingabe verwenden");
+    iconPaste.setBorderPainted(false);
+    iconPaste.setEnabled(false);
+    iconPaste.setFocusable(false);
+    iconPaste.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconPaste.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconPaste.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconPaste.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconPaste.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconPaste.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconPaste.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconPaste(evt);
+      }
+    });
+    toolBar.add(iconPaste);
+
+    iconProperties.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif"))); // NOI18N
+    iconProperties.setToolTipText("Terminal Einstellungen verändern");
+    iconProperties.setBorderPainted(false);
+    iconProperties.setEnabled(false);
+    iconProperties.setFocusable(false);
+    iconProperties.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconProperties.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconProperties.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconProperties.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconProperties.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconProperties.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconProperties.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconProperties(evt);
+      }
+    });
+    toolBar.add(iconProperties);
+
+    iconCleanTerminal.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png"))); // NOI18N
+    iconCleanTerminal.setToolTipText("Terminalinhalt löschen");
+    iconCleanTerminal.setBorderPainted(false);
+    iconCleanTerminal.setEnabled(false);
+    iconCleanTerminal.setFocusable(false);
+    iconCleanTerminal.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconCleanTerminal.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconCleanTerminal.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconCleanTerminal.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconCleanTerminal.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconCleanTerminal.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconCleanTerminal.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconCleanTerminal(evt);
+      }
+    });
+    toolBar.add(iconCleanTerminal);
+
+    jLabel6.setMaximumSize(new java.awt.Dimension(10, 10));
+    jLabel6.setMinimumSize(new java.awt.Dimension(10, 10));
+    jLabel6.setPreferredSize(new java.awt.Dimension(10, 10));
+    toolBar.add(jLabel6);
+
+    iconDownload.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png"))); // NOI18N
+    iconDownload.setToolTipText("Download Hex-File");
+    iconDownload.setBorderPainted(false);
+    iconDownload.setEnabled(false);
+    iconDownload.setFocusable(false);
+    iconDownload.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconDownload.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconDownload.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconDownload.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconDownload.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconDownload.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconDownload.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconDownload(evt);
+      }
+    });
+    toolBar.add(iconDownload);
+
+    iconStop.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png"))); // NOI18N
+    iconStop.setToolTipText("Stop");
+    iconStop.setBorderPainted(false);
+    iconStop.setEnabled(false);
+    iconStop.setFocusable(false);
+    iconStop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconStop.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconStop.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconStop.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconStop.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconStop.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconStop.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconStop(evt);
+      }
+    });
+    toolBar.add(iconStop);
+
+    jLabel8.setMaximumSize(new java.awt.Dimension(10, 10));
+    jLabel8.setMinimumSize(new java.awt.Dimension(10, 10));
+    jLabel8.setPreferredSize(new java.awt.Dimension(10, 10));
+    toolBar.add(jLabel8);
+
+    iconAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif"))); // NOI18N
+    iconAbout.setToolTipText("Über EasyProgrammer (Version...)");
+    iconAbout.setBorderPainted(false);
+    iconAbout.setFocusable(false);
+    iconAbout.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+    iconAbout.setMargin(new java.awt.Insets(1, 10, 1, 10));
+    iconAbout.setMaximumSize(new java.awt.Dimension(30, 24));
+    iconAbout.setMinimumSize(new java.awt.Dimension(30, 24));
+    iconAbout.setPreferredSize(new java.awt.Dimension(30, 24));
+    iconAbout.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+    iconAbout.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onIconAbout(evt);
+      }
+    });
+    toolBar.add(iconAbout);
+
+    getContentPane().add(toolBar, java.awt.BorderLayout.PAGE_START);
+
+    panCenter.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 2, 2, 2));
+    panCenter.setLayout(new java.awt.BorderLayout());
+
+    panCenterNorth.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
+    panCenterNorth.setLayout(new java.awt.BorderLayout());
+
+    panSerialInterface.setBorder(javax.swing.BorderFactory.createTitledBorder("Serielle Schnittstelle"));
+    panSerialInterface.setLayout(new java.awt.BorderLayout());
+
+    panSerialInterface2.setLayout(new java.awt.BorderLayout());
+
+    comboInterface.setBorder(javax.swing.BorderFactory.createEmptyBorder(2, 1, 2, 1));
+    comboInterface.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onComboInterface(evt);
+      }
+    });
+    panSerialInterface2.add(comboInterface, java.awt.BorderLayout.NORTH);
+
+    panSerialInterface.add(panSerialInterface2, java.awt.BorderLayout.CENTER);
+
+    panSerialInterfaceEast.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 5, 0));
+
+    panSerialInterrfaceButtons.setLayout(new java.awt.GridLayout(1, 0, 5, 0));
+
+    butConnect.setText("Verbinden");
+    butConnect.setEnabled(false);
+    butConnect.setMargin(new java.awt.Insets(3, 10, 3, 10));
+    butConnect.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonConnect(evt);
+      }
+    });
+    panSerialInterrfaceButtons.add(butConnect);
+
+    butDisconnect.setText("Trennen");
+    butDisconnect.setEnabled(false);
+    butDisconnect.setMargin(new java.awt.Insets(3, 3, 3, 3));
+    butDisconnect.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonDisconnect(evt);
+      }
+    });
+    panSerialInterrfaceButtons.add(butDisconnect);
+
+    panSerialInterfaceEast.add(panSerialInterrfaceButtons);
+
+    jpanSerailConfig.add(filler4);
+
+    textSerialConfig.setEditable(false);
+    textSerialConfig.setText("115200,none,1.5");
+    textSerialConfig.setFocusable(false);
+    textSerialConfig.setMargin(new java.awt.Insets(0, 5, 0, 5));
+    textSerialConfig.setMinimumSize(new java.awt.Dimension(120, 27));
+    textSerialConfig.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        textSerialConfigActionPerformed(evt);
+      }
+    });
+    jpanSerailConfig.add(textSerialConfig);
+
+    panSerialInterfaceEast.add(jpanSerailConfig);
+
+    butSerialConfig.setText("Einstellungen");
+    butSerialConfig.setMargin(new java.awt.Insets(3, 3, 3, 3));
+    butSerialConfig.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonSerialConfig(evt);
+      }
+    });
+    panSerialInterfaceEast.add(butSerialConfig);
+
+    panSerialInterface.add(panSerialInterfaceEast, java.awt.BorderLayout.EAST);
+
+    panCenterNorth.add(panSerialInterface, java.awt.BorderLayout.PAGE_START);
+
+    panProgramFile.setBorder(javax.swing.BorderFactory.createTitledBorder("Programmdatei (Hex-File)"));
+    panProgramFile.setLayout(new java.awt.BorderLayout());
+
+    butSelectProgramFile.setText("Datei");
+    butSelectProgramFile.setMargin(new java.awt.Insets(3, 10, 3, 10));
+    butSelectProgramFile.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onSelectProgramFile(evt);
+      }
+    });
+    panProgramFile.add(butSelectProgramFile, java.awt.BorderLayout.WEST);
+
+    jPanel3.setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 1, 3, 1));
+    jPanel3.setLayout(new java.awt.GridLayout(1, 0));
+
+    tfProgramFileName.setEditable(false);
+    tfProgramFileName.setToolTipText("");
+    tfProgramFileName.setFocusable(false);
+    tfProgramFileName.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        tfProgramFileNameActionPerformed(evt);
+      }
+    });
+    jPanel3.add(tfProgramFileName);
+
+    panProgramFile.add(jPanel3, java.awt.BorderLayout.CENTER);
+
+    jPanel4.setBorder(javax.swing.BorderFactory.createEmptyBorder(3, 1, 3, 1));
+    jPanel4.setMinimumSize(new java.awt.Dimension(40, 33));
+    jPanel4.setLayout(new java.awt.GridLayout(1, 0));
+
+    textHexSize.setEditable(false);
+    textHexSize.setFocusable(false);
+    jPanel4.add(textHexSize);
+
+    panProgramFile.add(jPanel4, java.awt.BorderLayout.EAST);
+
+    panCenterNorth.add(panProgramFile, java.awt.BorderLayout.PAGE_END);
+
+    panCenter.add(panCenterNorth, java.awt.BorderLayout.NORTH);
+
+    panCenterCenter.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 5, 5, 5));
+    panCenterCenter.setLayout(new java.awt.GridLayout(1, 0));
+
+    textTerminal.setBorder(javax.swing.BorderFactory.createTitledBorder("Terminal"));
+    textTerminal.setLayout(new java.awt.GridLayout(1, 0));
+    panCenterCenter.add(textTerminal);
+
+    panCenter.add(panCenterCenter, java.awt.BorderLayout.CENTER);
+
+    panCenterSouth.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
+    panCenterSouth.setLayout(new java.awt.BorderLayout());
+
+    panDownload.setBorder(javax.swing.BorderFactory.createTitledBorder("Zielsystem / Download"));
+    panDownload.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT));
+
+    butReset.setText("Reset");
+    butReset.setEnabled(false);
+    butReset.setMargin(new java.awt.Insets(5, 5, 5, 5));
+    butReset.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonReset(evt);
+      }
+    });
+    panDownload.add(butReset);
+    panDownload.add(filler1);
+
+    chkResetBeforeDownload.setSelected(true);
+    chkResetBeforeDownload.setText("Reset");
+    chkResetBeforeDownload.setEnabled(false);
+    panDownload.add(chkResetBeforeDownload);
+
+    butDownloadStart.setText("Start");
+    butDownloadStart.setEnabled(false);
+    butDownloadStart.setMargin(new java.awt.Insets(5, 10, 5, 10));
+    butDownloadStart.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onDownload(evt);
+      }
+    });
+    panDownload.add(butDownloadStart);
+    panDownload.add(filler3);
+
+    butDownloadStop.setText("Stop");
+    butDownloadStop.setEnabled(false);
+    butDownloadStop.setMargin(new java.awt.Insets(5, 10, 5, 10));
+    butDownloadStop.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonStop(evt);
+      }
+    });
+    panDownload.add(butDownloadStop);
+    panDownload.add(filler2);
+
+    butDownloadProperties.setText("Einstellungen");
+    butDownloadProperties.setEnabled(false);
+    butDownloadProperties.setMargin(new java.awt.Insets(5, 5, 5, 5));
+    butDownloadProperties.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        butDownloadPropertiesonButtonStop(evt);
+      }
+    });
+    panDownload.add(butDownloadProperties);
+
+    panCenterSouth.add(panDownload, java.awt.BorderLayout.CENTER);
+
+    panGlobal.setLayout(new java.awt.BorderLayout());
+    panGlobal.add(filler5, java.awt.BorderLayout.PAGE_START);
+
+    jpanGlobalButtons.setLayout(new java.awt.GridLayout(2, 1, 0, 5));
+
+    butProperties.setText("Einstellungen µC");
+    butProperties.setMargin(new java.awt.Insets(2, 2, 2, 2));
+    butProperties.addFocusListener(new java.awt.event.FocusAdapter()
+    {
+      public void focusLost(java.awt.event.FocusEvent evt)
+      {
+        onFilePropertiesGainLost(evt);
+      }
+    });
+    butProperties.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onButtonProperties(evt);
+      }
+    });
+    jpanGlobalButtons.add(butProperties);
+
+    butRefresh.setText("Aktualisieren");
+    butRefresh.setActionCommand("Refresh");
+    butRefresh.setMargin(new java.awt.Insets(2, 2, 2, 2));
+    butRefresh.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onRefresh(evt);
+      }
+    });
+    jpanGlobalButtons.add(butRefresh);
+
+    panGlobal.add(jpanGlobalButtons, java.awt.BorderLayout.CENTER);
+    panGlobal.add(filler6, java.awt.BorderLayout.PAGE_END);
+
+    panCenterSouth.add(panGlobal, java.awt.BorderLayout.EAST);
+
+    panCenter.add(panCenterSouth, java.awt.BorderLayout.PAGE_END);
+
+    getContentPane().add(panCenter, java.awt.BorderLayout.CENTER);
+
+    panSouth.setLayout(new java.awt.BorderLayout());
+
+    panSouthSouth.setBackground(new java.awt.Color(204, 204, 204));
+    panSouthSouth.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 6, 5, 5));
+    panSouthSouth.setLayout(new java.awt.BorderLayout());
+    panSouthSouth.add(progressBar, java.awt.BorderLayout.WEST);
+
+    testUserMessage.setEditable(false);
+    testUserMessage.setText("User Message");
+    testUserMessage.setFocusable(false);
+    panSouthSouth.add(testUserMessage, java.awt.BorderLayout.CENTER);
+
+    textStatus.setEditable(false);
+    textStatus.setHorizontalAlignment(javax.swing.JTextField.CENTER);
+    textStatus.setText("Status");
+    panSouthSouth.add(textStatus, java.awt.BorderLayout.EAST);
+
+    panSouth.add(panSouthSouth, java.awt.BorderLayout.SOUTH);
+
+    getContentPane().add(panSouth, java.awt.BorderLayout.SOUTH);
+
+    menuFile.setText("Datei");
+
+    menuFileOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif"))); // NOI18N
+    menuFileOpen.setText("Öffnen");
+    menuFileOpen.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuFileOpen(evt);
+      }
+    });
+    menuFile.add(menuFileOpen);
+    menuFile.add(jSeparator1);
+
+    menuExit.setText("Beenden");
+    menuExit.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuExit(evt);
+      }
+    });
+    menuFile.add(menuExit);
+
+    menuBar.add(menuFile);
+
+    menuEdit.setText("Bearbeiten");
+
+    menuEditProperties.setText("Einstellungen µC");
+    menuEditProperties.setEnabled(false);
+    menuEditProperties.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuEditProperties(evt);
+      }
+    });
+    menuEdit.add(menuEditProperties);
+
+    menuSerialProperties.setText("Serielle Schnittstelle");
+    menuSerialProperties.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuEditSerialProperties(evt);
+      }
+    });
+    menuEdit.add(menuSerialProperties);
+    menuEdit.add(jSeparator2);
+
+    menuCopy.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif"))); // NOI18N
+    menuCopy.setText("Kopieren");
+    menuCopy.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuCopy(evt);
+      }
+    });
+    menuEdit.add(menuCopy);
+
+    menuPaste.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif"))); // NOI18N
+    menuPaste.setText("Einfügen");
+    menuPaste.setEnabled(false);
+    menuEdit.add(menuPaste);
+    menuEdit.add(jSeparator3);
+
+    menuDeleteTerminalContent.setText("Terminalinhalt löschen");
+    menuDeleteTerminalContent.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuDeleteTerminalContent(evt);
+      }
+    });
+    menuEdit.add(menuDeleteTerminalContent);
+
+    menuBar.add(menuEdit);
+
+    menuHelp.setText("Hilfe");
+
+    jmiHelp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif"))); // NOI18N
+    jmiHelp.setText("Über EasyProgrammer...");
+    jmiHelp.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        onMenuAbout(evt);
+      }
+    });
+    menuHelp.add(jmiHelp);
+
+    jmiMonitor.setText("Monitor");
+    jmiMonitor.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(java.awt.event.ActionEvent evt)
+      {
+        jmiMonitoronMenuAbout(evt);
+      }
+    });
+    menuHelp.add(jmiMonitor);
+
+    menuBar.add(menuHelp);
+
+    setJMenuBar(menuBar);
+
+    pack();
+  }// </editor-fold>//GEN-END:initComponents
+
+    private void onMenuAbout(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuAbout
+    {//GEN-HEADEREND:event_onMenuAbout
+      DialogAbout aboutDialog = new DialogAbout(this, true);
+      aboutDialog.setVisible(true);
+    }//GEN-LAST:event_onMenuAbout
+
+    private void onMenuEditProperties(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuEditProperties
+    {//GEN-HEADEREND:event_onMenuEditProperties
+      this.runDialogProperties();
+    }//GEN-LAST:event_onMenuEditProperties
+
+    private void onIconFileOpen(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconFileOpen
+    {//GEN-HEADEREND:event_onIconFileOpen
+      buttonSelectProgramFile(evt);
+    }//GEN-LAST:event_onIconFileOpen
+
+    private void onIconAbout(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconAbout
+    {//GEN-HEADEREND:event_onIconAbout
+      this.onMenuAbout(evt);
+    }//GEN-LAST:event_onIconAbout
+
+    private void tfProgramFileNameActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_tfProgramFileNameActionPerformed
+    {//GEN-HEADEREND:event_tfProgramFileNameActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_tfProgramFileNameActionPerformed
+
+    private void onRefresh(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onRefresh
+    {//GEN-HEADEREND:event_onRefresh
+      this.buttonRefresh(evt);
+    }//GEN-LAST:event_onRefresh
+
+    private void onComboInterface(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onComboInterface
+    {//GEN-HEADEREND:event_onComboInterface
+      this.comboInterface(evt);
+    }//GEN-LAST:event_onComboInterface
+
+    private void onButtonConnect(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonConnect
+    {//GEN-HEADEREND:event_onButtonConnect
+      buttonConnect(evt);
+    }//GEN-LAST:event_onButtonConnect
+
+    private void onButtonDisconnect(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonDisconnect
+    {//GEN-HEADEREND:event_onButtonDisconnect
+      buttonDisconnect(evt);
+    }//GEN-LAST:event_onButtonDisconnect
+
+    private void onFilePropertiesGainLost(java.awt.event.FocusEvent evt)//GEN-FIRST:event_onFilePropertiesGainLost
+    {//GEN-HEADEREND:event_onFilePropertiesGainLost
+      //this.terminalArea.requestFocus();
+    }//GEN-LAST:event_onFilePropertiesGainLost
+
+    private void onSelectProgramFile(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onSelectProgramFile
+    {//GEN-HEADEREND:event_onSelectProgramFile
+      buttonSelectProgramFile(evt);
+    }//GEN-LAST:event_onSelectProgramFile
+
+    private void onDownload(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onDownload
+    {//GEN-HEADEREND:event_onDownload
+      buttonDownloadStart(evt);
+    }//GEN-LAST:event_onDownload
+
+    private void onButtonStop(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonStop
+    {//GEN-HEADEREND:event_onButtonStop
+      buttonStop(evt);
+    }//GEN-LAST:event_onButtonStop
+
+    private void onButtonReset(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonReset
+    {//GEN-HEADEREND:event_onButtonReset
+      buttonReset(evt);
+    }//GEN-LAST:event_onButtonReset
+
+    private void onMenuFileOpen(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuFileOpen
+    {//GEN-HEADEREND:event_onMenuFileOpen
+      buttonSelectProgramFile(evt);
+    }//GEN-LAST:event_onMenuFileOpen
+
+    private void onMenuExit(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuExit
+    {//GEN-HEADEREND:event_onMenuExit
+      this.setVisible(false);
+      this.dispose();
+    }//GEN-LAST:event_onMenuExit
+
+    private void textSerialConfigActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_textSerialConfigActionPerformed
+    {//GEN-HEADEREND:event_textSerialConfigActionPerformed
+      // TODO add your handling code here:
+    }//GEN-LAST:event_textSerialConfigActionPerformed
+
+    private void onIconCopy(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconCopy
+    {//GEN-HEADEREND:event_onIconCopy
+      this.copyToClipBoard();
+    }//GEN-LAST:event_onIconCopy
+
+    private void onIconPaste(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconPaste
+    {//GEN-HEADEREND:event_onIconPaste
+      // TODO add your handling code here:
+    }//GEN-LAST:event_onIconPaste
+
+    private void onIconProperties(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconProperties
+    {//GEN-HEADEREND:event_onIconProperties
+      // TODO add your handling code here:
+    }//GEN-LAST:event_onIconProperties
+
+    private void onIconRefresh(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconRefresh
+    {//GEN-HEADEREND:event_onIconRefresh
+      buttonRefresh(evt);
+    }//GEN-LAST:event_onIconRefresh
+
+    private void onButtonSerialConfig(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonSerialConfig
+    {//GEN-HEADEREND:event_onButtonSerialConfig
+      runDialogSerialProperties();
+    }//GEN-LAST:event_onButtonSerialConfig
+
+    private void onIconConnect(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconConnect
+    {//GEN-HEADEREND:event_onIconConnect
+       buttonConnect(evt);
+    }//GEN-LAST:event_onIconConnect
+
+    private void onIconDisconnect(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconDisconnect
+    {//GEN-HEADEREND:event_onIconDisconnect
+      buttonDisconnect(evt);
+    }//GEN-LAST:event_onIconDisconnect
+
+    private void butDownloadPropertiesonButtonStop(java.awt.event.ActionEvent evt)//GEN-FIRST:event_butDownloadPropertiesonButtonStop
+    {//GEN-HEADEREND:event_butDownloadPropertiesonButtonStop
+      // TODO add your handling code here:
+    }//GEN-LAST:event_butDownloadPropertiesonButtonStop
+
+    private void onMenuEditSerialProperties(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuEditSerialProperties
+    {//GEN-HEADEREND:event_onMenuEditSerialProperties
+      this.runDialogSerialProperties();
+    }//GEN-LAST:event_onMenuEditSerialProperties
+
+    private void onMenuCopy(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuCopy
+    {//GEN-HEADEREND:event_onMenuCopy
+      copyToClipBoard();
+    }//GEN-LAST:event_onMenuCopy
+
+    private void onMenuDeleteTerminalContent(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onMenuDeleteTerminalContent
+    {//GEN-HEADEREND:event_onMenuDeleteTerminalContent
+      cleanTerminalContent();
+    }//GEN-LAST:event_onMenuDeleteTerminalContent
+
+    private void onIconDownload(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconDownload
+    {//GEN-HEADEREND:event_onIconDownload
+      buttonDownloadStart(evt);
+    }//GEN-LAST:event_onIconDownload
+
+    private void onIconStop(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconStop
+    {//GEN-HEADEREND:event_onIconStop
+      buttonStop(evt);
+    }//GEN-LAST:event_onIconStop
+
+    private void onIconCleanTerminal(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onIconCleanTerminal
+    {//GEN-HEADEREND:event_onIconCleanTerminal
+      cleanTerminalContent();
+    }//GEN-LAST:event_onIconCleanTerminal
+
+    private void onButtonProperties(java.awt.event.ActionEvent evt)//GEN-FIRST:event_onButtonProperties
+    {//GEN-HEADEREND:event_onButtonProperties
+      this.runDialogProperties();
+    }//GEN-LAST:event_onButtonProperties
+
+  private void jmiMonitoronMenuAbout(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jmiMonitoronMenuAbout
+  {//GEN-HEADEREND:event_jmiMonitoronMenuAbout
+    serialInterface.printMonitor();
+  }//GEN-LAST:event_jmiMonitoronMenuAbout
+
+
+  private static String [] getOptionInfo (String s)
+  {
+    String [] f = new String [4];
+    f[0] = s.substring(0,2);
+    f[1] = s.substring(3,4);
+    f[2] = s.substring(4,26).trim();
+    f[3] = s.substring(26).trim();
+    
+    return f;    
+  }
+
+  /**
+   * @param args the command line arguments
+   */
+  public static void main(final String args[]) throws FileNotFoundException
+  {
+    boolean linux = System.getProperty("os.name").contains("nux") ? true : false;
+    
+    String [] availOptions = {
+      "-h 0 --help               @Afor help of command line options",
+      "-V 0 --version            @Afor current software version",
+      "-b 0 --batch              @Aexecute easyprogrammer in batch mode (without GUI)",
+      "-i 1 --interface          @Wfor desired interface ( -i COM1 or -i COM1:57600/N/1",
+      "-i 1 --interface          @Lfor desired interface ( -i /dev/ttyUSB0 or -i /dev/ttyUSB0:57600/N/1)",
+      "-n 1 --interface-names    @Wfor available interface names ( -n COM1,COM2,COM3)",
+      "-n 1 --interface-names    @Lfor available interface names ( -n /dev/ttyS0,/dev/ttyUSB0)",
+      "-d 1 --directory          @Ldirectory path for program file (-d /home/user/hex-files)",
+      "-d 1 --directory          @Wdirectory path for program file (-d C:\\temp)",
+      "-f 1 --hexfile            @Aname of program-file (-f test.hex)",
+      "-r 0 --noreset            @Asend no reset-command before download",
+      "-C 1 --resetcmd           @Asend '@reset' (or given string) +CR +LF before download",
+      "-R 1 --resetseq           @Asend '@reset' (or given string) (without CR or LF) before download",
+      "-c 0 --nocheck            @Adon't check system response after download",
+      "-t 1 --target             @A'-t atmeag328p' or '-t atmega16' or -t atmega8L'  (default atmega328p)",
+      "-p 1 --port               @Astart server on specified port ( -p 4711)", 
+      "-w 1 --wait               @ATime in ms waiting for Bootloader repsonse",
+      "-l 1 --loglevel           @ALOG-Level (SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL)"
+    }; 
+
+    if (args.length>0 && (args[0].equals("-h") || args[0].equals("--help")))
+    {
+      System.out.println("EasyProgrammer Version " + DialogAbout.version);
+      System.out.println("(C) Manfred Steiner (sx@htl-kaindorf.ac.at)");
+      System.out.println();
+      System.out.println("Available argument options are:");
+      
+      for (String s : availOptions)
+      {
+        String [] f = getOptionInfo(s);
+        int argcnt = Integer.parseInt(f[1]);
+        if (f[3].startsWith("@A") || (linux && f[3].startsWith("@L")) || (!linux && f[3].startsWith("@W")) )
+        {
+          System.out.print("  " + f[0]);
+          System.out.print("  " + f[2]);
+          for (int i=0; i<(20-f[2].length()); i++)
+            System.out.print(" ");
+          if (argcnt==0)
+            System.out.print("       ");
+          else for (int i=0; i<argcnt; i++)
+            System.out.print("<...>  ");
+          System.out.println(f[3].substring(2));  
+        }        
+      }
+
+      System.out.println();
+      System.exit(0);
+    }
+
+    final ArrayList<String>  arglist = new ArrayList<String>();
+    
+    for (int pos=0; pos<args.length; pos++)
+    {
+      String a = args[pos];
+      if (a.charAt(0) == '-' && a.charAt(1) != '-')
+      {
+        for (int i = 1; i<a.length(); i++ )
+        {
+          boolean found = false;
+          for (String s : availOptions)
+          {
+            String [] f = getOptionInfo(s);
+            int argcnt = Integer.parseInt(f[1]);
+            
+            if (f[0].equals(a))
+            {
+              arglist.add(f[2]);
+              for (int j=0; j<argcnt; j++)
+                arglist.add(args[pos+j+1]);
+              pos += argcnt;
+              found = true;
+            }
+          }
+          if (!found)
+          {
+            String msg = "Error: unknown option (-" + a.charAt(i) + ")";
+            System.err.println(msg);
+            if (arglist.contains("--batch")==false)
+              JOptionPane.showMessageDialog(null, msg, "Programmstart fehlgeschlagen", JOptionPane.ERROR_MESSAGE);
+            System.exit(-1);
+          }
+        }
+      }
+      else if (a.startsWith("--"))
+      {
+        boolean found = false;
+        for (String s : availOptions)
+        {
+          String [] f = getOptionInfo(s);
+          int argcnt = Integer.parseInt(f[1]);
+
+          if (f[2].equals(a))
+          {
+            arglist.add(f[2]);
+            for (int j=0; j<argcnt; j++)
+              arglist.add(args[pos+j+1]);
+            pos += argcnt;
+            found = true;
+            break;
+          }
+        }
+        if (!found)
+        {
+          String msg = "Error: unknown option (" + a + ")";
+          System.err.println(msg);
+          if (arglist.contains("--batch")==false)
+            JOptionPane.showMessageDialog(null, msg, "Programmstart fehlgeschlagen", JOptionPane.ERROR_MESSAGE);
+          System.exit(-1);
+        }
+      }
+      else
+      {
+        String msg = "Error: unknown option (" + a + ")";
+        System.err.println(msg);
+        if (arglist.contains("--batch")==false)
+          JOptionPane.showMessageDialog(null, msg, "Programmstart fehlgeschlagen", JOptionPane.ERROR_MESSAGE);
+        System.exit(-1);
+      }
+        
+    }
+    //System.out.println(arglist);
+
+    if (arglist.contains("--version"))
+    {
+      System.out.println("EasyProgrammer Version " + DialogAbout.version);
+      System.out.println("(C) Manfred Steiner (sx@htl-kaindorf.ac.at)");
+      System.out.println(" ... start with -h or --help for more information");
+      System.out.println();
+    }
+    
+    if (arglist.contains("--batch"))
+    {
+      int ret = new EasyProgrammer(arglist).executeInBatchMode();
+      System.exit(ret);
+    }
+
+    Logger.setParentLogger(LOG);
+    LOG.setUseParentHandlers(false);
+    LogWriterHandler logWriterHandler = new LogWriterHandler(System.out, System.out);
+    LOG.setLevel(Level.WARNING);
+    logWriterHandler.setLevel(Level.WARNING);
+    LOG.setLocationShown(false);
+    LOG.addHandler(logWriterHandler);
+    if (arglist.contains("--loglevel"))
+    {
+      LOG.setLocationShown(true);
+      switch (arglist.get(arglist.indexOf("--loglevel")+1))
+      {
+        case "SEVERE":  LOG.setLevel(Level.SEVERE); break;
+        case "WARNING": LOG.setLevel(Level.WARNING); break;
+        case "INFO":    LOG.setLevel(Level.INFO); break;       
+        case "CONFIG":  LOG.setLevel(Level.CONFIG); break;
+        case "FINE":    LOG.setLevel(Level.FINE); break;
+        case "FINER":   LOG.setLevel(Level.FINER); break;
+        case "FINEST":  LOG.setLevel(Level.FINEST); break;
+        case "ALL":     LOG.setLevel(Level.ALL); break;
+        default: 
+          System.out.println("Unvalid Log-Level, stay on WARNING");
+      }
+
+      switch (arglist.get(arglist.indexOf("--loglevel")+1))
+      {
+        case "SEVERE":  logWriterHandler.setLevel(Level.SEVERE); break;
+        case "WARNING": logWriterHandler.setLevel(Level.WARNING); break;
+        case "INFO":    logWriterHandler.setLevel(Level.INFO); break;       
+        case "CONFIG":  logWriterHandler.setLevel(Level.CONFIG); break;
+        case "FINE":    logWriterHandler.setLevel(Level.FINE); break;
+        case "FINER":   logWriterHandler.setLevel(Level.FINER); break;
+        case "FINEST":  logWriterHandler.setLevel(Level.FINEST); break;
+        case "ALL":     logWriterHandler.setLevel(Level.ALL); break;
+      }
+    }
+    
+    try
+    {
+      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
+      {
+        if ("Nimbus".equals(info.getName()))
+        {
+          javax.swing.UIManager.setLookAndFeel(info.getClassName());
+          break;
+        }
+      }
+    }
+    catch (ClassNotFoundException ex)
+    {
+      java.util.logging.Logger.getLogger(EasyProgrammer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+    }
+    catch (InstantiationException ex)
+    {
+      java.util.logging.Logger.getLogger(EasyProgrammer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+    }
+    catch (IllegalAccessException ex)
+    {
+      java.util.logging.Logger.getLogger(EasyProgrammer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+    }
+    catch (javax.swing.UnsupportedLookAndFeelException ex)
+    {
+      java.util.logging.Logger.getLogger(EasyProgrammer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+    }    
+    
+    UIManager.getLookAndFeelDefaults().put("ScrollBar.minimumThumbSize", new Dimension(30, 30));
+
+    java.awt.EventQueue.invokeLater(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        new EasyProgrammer(arglist).setVisible(true);
+      }
+    });
+  }
+  // Variables declaration - do not modify//GEN-BEGIN:variables
+  private javax.swing.JButton butConnect;
+  private javax.swing.JButton butDisconnect;
+  private javax.swing.JButton butDownloadProperties;
+  private javax.swing.JButton butDownloadStart;
+  private javax.swing.JButton butDownloadStop;
+  private javax.swing.JButton butProperties;
+  private javax.swing.JButton butRefresh;
+  private javax.swing.JButton butReset;
+  private javax.swing.JButton butSelectProgramFile;
+  private javax.swing.JButton butSerialConfig;
+  private javax.swing.JCheckBox chkResetBeforeDownload;
+  private javax.swing.JComboBox comboInterface;
+  private javax.swing.Box.Filler filler1;
+  private javax.swing.Box.Filler filler2;
+  private javax.swing.Box.Filler filler3;
+  private javax.swing.Box.Filler filler4;
+  private javax.swing.Box.Filler filler5;
+  private javax.swing.Box.Filler filler6;
+  private javax.swing.JButton iconAbout;
+  private javax.swing.JButton iconCleanTerminal;
+  private javax.swing.JButton iconConnect;
+  private javax.swing.JButton iconCopy;
+  private javax.swing.JButton iconDisconnect;
+  private javax.swing.JButton iconDownload;
+  private javax.swing.JButton iconFileOpen;
+  private javax.swing.JButton iconPaste;
+  private javax.swing.JButton iconProperties;
+  private javax.swing.JButton iconRefresh;
+  private javax.swing.JButton iconStop;
+  private javax.swing.JLabel jLabel1;
+  private javax.swing.JLabel jLabel5;
+  private javax.swing.JLabel jLabel6;
+  private javax.swing.JLabel jLabel7;
+  private javax.swing.JLabel jLabel8;
+  private javax.swing.JPanel jPanel3;
+  private javax.swing.JPanel jPanel4;
+  private javax.swing.JPopupMenu.Separator jSeparator1;
+  private javax.swing.JPopupMenu.Separator jSeparator2;
+  private javax.swing.JPopupMenu.Separator jSeparator3;
+  private javax.swing.JMenuItem jmiHelp;
+  private javax.swing.JMenuItem jmiMonitor;
+  private javax.swing.JPanel jpanGlobalButtons;
+  private javax.swing.JPanel jpanSerailConfig;
+  private javax.swing.JMenuBar menuBar;
+  private javax.swing.JMenuItem menuCopy;
+  private javax.swing.JMenuItem menuDeleteTerminalContent;
+  private javax.swing.JMenu menuEdit;
+  private javax.swing.JMenuItem menuEditProperties;
+  private javax.swing.JMenuItem menuExit;
+  private javax.swing.JMenu menuFile;
+  private javax.swing.JMenuItem menuFileOpen;
+  private javax.swing.JMenu menuHelp;
+  private javax.swing.JMenuItem menuPaste;
+  private javax.swing.JMenuItem menuSerialProperties;
+  private javax.swing.JPanel panCenter;
+  private javax.swing.JPanel panCenterCenter;
+  private javax.swing.JPanel panCenterNorth;
+  private javax.swing.JPanel panCenterSouth;
+  private javax.swing.JPanel panDownload;
+  private javax.swing.JPanel panGlobal;
+  private javax.swing.JPanel panProgramFile;
+  private javax.swing.JPanel panSerialInterface;
+  private javax.swing.JPanel panSerialInterface2;
+  private javax.swing.JPanel panSerialInterfaceEast;
+  private javax.swing.JPanel panSerialInterrfaceButtons;
+  private javax.swing.JPanel panSouth;
+  private javax.swing.JPanel panSouthSouth;
+  private javax.swing.JProgressBar progressBar;
+  private javax.swing.JTextField testUserMessage;
+  private javax.swing.JTextField textHexSize;
+  private javax.swing.JTextField textSerialConfig;
+  private javax.swing.JTextField textStatus;
+  private javax.swing.JPanel textTerminal;
+  private javax.swing.JTextField tfProgramFileName;
+  private javax.swing.JToolBar toolBar;
+  // End of variables declaration//GEN-END:variables
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/GUISwingWorker.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/GUISwingWorker.java
new file mode 100644 (file)
index 0000000..b371cb7
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.gui.EasyProgrammer.SwingWorkerTyp;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import at.htlkaindorf.sx.EasyProgrammer.serial.DownloadProtocol;
+import at.htlkaindorf.sx.EasyProgrammer.serial.ResetProtocol;
+import at.htlkaindorf.sx.EasyProgrammer.server.IDEServer;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PipedReader;
+import java.io.PipedWriter;
+import java.util.ArrayList;
+import java.util.InputMismatchException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Scanner;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import javax.swing.SwingWorker;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author Manfred Steiner
+ */
+public class GUISwingWorker
+{
+
+  private static final Logger LOG = Logger.getLogger(GUISwingWorker.class.getName());
+  LinkedList<SwingWorkerTyp> list = new LinkedList();
+  
+  EasyProgrammer easyProgrammer;
+  SwingWorker sw;
+  IDEServerSwingWorker idesw;
+
+
+  public GUISwingWorker(EasyProgrammer easyProgrammer)
+  {
+    this.easyProgrammer = easyProgrammer;
+    if (easyProgrammer.getServerPort()>1000)
+    {
+      this.idesw = new IDEServerSwingWorker();
+      this.idesw.execute();
+    }
+  }
+
+  public boolean isUsed ()
+  {
+    if (sw != null)
+      return true;
+
+    return false;
+  }
+
+  public void setProgress (int progress)
+  {
+    
+  }
+
+  public boolean isDownloadInProgress ()
+  {
+    if (this.sw != null && this.sw instanceof DownloadSwingWorker)
+      return true;
+
+    return false;
+  }
+
+  public boolean isResetInProgress ()
+  {
+    if (this.sw != null && this.sw instanceof ResetSwingWorker)
+    return true;
+
+    return false;
+  }
+
+  
+  public void stopDownload ()
+  {
+    if (this.isDownloadInProgress() == false)
+      return;
+    
+    this.sw.cancel(true);
+  }
+
+  
+  public void startLater (SwingWorkerTyp typ)
+  {
+    if (easyProgrammer==null)
+      throw new RuntimeException("Internal error");
+    if (isUsed())
+      list.add(typ);
+    else
+      start(typ);
+  }
+
+  public void start (SwingWorkerTyp typ)
+  {
+    if (isUsed() || easyProgrammer==null)
+      throw new RuntimeException("Internal error");
+
+    switch (typ)
+    {
+      case REFRESH:
+        easyProgrammer.startProcess("Aktualisieren");
+        sw = new RefreshSwingWorker();
+        break;
+
+      case CONNECT:
+        easyProgrammer.startProcess("Verbinden");
+        sw = new ConnectSwingWorker();
+        break;
+
+      case LOADPROGRAMFILE:
+        easyProgrammer.startProcess("Hex-File laden");
+        sw = new LoadProgramFileSwingWorker();
+        break;
+
+      case DOWNLOAD:
+        if (easyProgrammer.serialInterface.isConnected())
+        {
+          easyProgrammer.startProcess("Download");
+          sw = new DownloadSwingWorker(easyProgrammer.containsArgument("--nocheck"));
+          easyProgrammer.updateButtons();
+          sw.addPropertyChangeListener((PropertyChangeListener)sw);
+        }
+        else
+          throw new RuntimeException("Download not possible when interface not connected");
+
+        break;
+        
+      case RESET:
+        if (easyProgrammer.serialInterface.isConnected())
+        {
+          easyProgrammer.startProcess("Reset");
+          sw = new ResetSwingWorker();
+          easyProgrammer.updateButtons();
+          sw.addPropertyChangeListener((PropertyChangeListener)sw);
+        }
+        else
+          throw new RuntimeException("Reset not possible when interface not connected");
+        break;
+
+    }
+    
+    sw.execute();
+  }
+
+
+  private void removeActiveSwingWorker ()
+  {
+    sw = null;
+    if (list.size()>0)
+      start(list.remove(0));
+  }
+
+
+  public void execSwingWorkerProcess (SwingWorkerTyp swt, List<String> chunks )
+  {
+    switch (swt)
+    {
+      case REFRESH: case CONNECT: case LOADPROGRAMFILE:
+        if (chunks.size()>0)
+        {
+          easyProgrammer.setUserMessage((String)chunks.get(chunks.size()-1));
+          return;
+        }
+    }
+    throw new RuntimeException ("execSwingWorkerProcess - Unknown Typ/Message");
+  }
+
+
+  public void execSwingWorkerDone (SwingWorkerTyp swt, int result)
+  {
+    switch (swt)
+    {
+      case LOADPROGRAMFILE:
+        switch (result)
+        {
+          case 0: // thread ends with no errors
+            easyProgrammer.updateTextHexSize();
+            if (easyProgrammer.getProgramFileName() != null)
+              easyProgrammer.setUserMessage("Programmdatei '" + easyProgrammer.getProgramFileName() + "' erfolgreich geladen");
+            else
+              easyProgrammer.setUserMessage("Initialisierung abgeschlossen");
+            return;
+
+          case -1: // thread ends with "no memory byte found"
+            easyProgrammer.updateTextHexSize();
+            easyProgrammer.setUserMessage("Fehlerhafte Programmdatei (keine Intel-Hex Datei?)");
+            return;
+
+          case -2: // thread ends with some errors in Intel Hex File
+            easyProgrammer.updateTextHexSize();
+            easyProgrammer.setUserMessage("Fehlerhafte Programmdatei (Intel-Hex Formatfehler)");
+            return;
+
+          case -3: // thread ends with Exception
+            easyProgrammer.updateTextHexSize();
+            easyProgrammer.setUserMessage("Fehlerhafte Programmdatei (Intel-Hex Formatfehler)");
+            return;
+
+          default:
+            easyProgrammer.updateTextHexSize();
+            easyProgrammer.setUserMessage("Laden fehlgeschlagen (interner Fehler " +  + result + ")");
+            return;
+        }
+    }
+    throw new RuntimeException ("execSwingWorkerDone - Unknown typ/result");
+  }
+
+
+  public void loadFile () throws Exception
+  {
+    try
+    {
+      easyProgrammer.programFile.loadFile();
+      if (easyProgrammer.programFile.getMemoryLength()<=0)
+        throw new Exception("Datei kann nicht geladen werden");
+
+      ArrayList errList = easyProgrammer.programFile.getErrorList();
+      if (errList != null)
+        throw new Exception("Datei fehlerhaft (1)");
+    }
+    catch (Exception ex)
+    {
+      throw new Exception("Datei fehlerhaft (2)");
+    }
+  }
+
+
+  public void propertyChange(PropertyChangeEvent evt)
+  {
+    System.out.println(evt);
+    //throw new UnsupportedOperationException("Not supported yet.");
+  }
+
+
+
+  class RefreshSwingWorker extends SwingWorker<Integer,String>
+  {
+    // Job wird in eigenem Thread ausgeführt. Hier dürfen keine Manipulationen
+    // an Swing-Komponenten stattfinden.
+    @Override
+    protected Integer doInBackground() throws Exception
+    {
+      publish("Verfügbare serielle Schnittstellen finden...");
+      easyProgrammer.serialInterface.updateInterfaces();
+      publish("Serielle Schnittstellen testen");
+      easyProgrammer.serialInterface.checkInterfaces();
+      if (easyProgrammer.getProgramFileName() == null)
+        return 0;
+        
+      publish("Hex-Datei aktualisieren");
+      if (easyProgrammer.programFile.isModified())
+      {
+        publish("Aktualisiere Programmdatei '" + easyProgrammer.getProgramFileName() + "'");
+        //System.out.println("Aktualisiere Datei");
+        try
+        { 
+          loadFile();
+          LOG.info("reloading file ");
+        }
+        catch (Exception ex)
+        {
+          ex.printStackTrace(System.err);
+          return -1;
+        }
+      }
+      return 0;
+    }
+
+    // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+    // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+    // an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void process(List<String> chunks)
+    {
+      execSwingWorkerProcess(SwingWorkerTyp.REFRESH, chunks);
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      try
+      { 
+        int result = get();
+        execSwingWorkerDone(SwingWorkerTyp.LOADPROGRAMFILE, result);
+        easyProgrammer.setProgressBar(100);
+      }              
+      catch (Exception ex)
+      {
+        LOG.warning(ex);
+        easyProgrammer.setProgressBar(-1);
+        if (ex instanceof ExecutionException && ex.getCause() instanceof Exception)
+          ex = (Exception) ex.getCause();
+        String msg = ex.getMessage();
+        if (msg==null || msg.isEmpty())
+          msg = ex.getClass().getSimpleName();
+        easyProgrammer.setUserMessage(String.format("Error (%s)", msg));
+      }
+      finally
+      {
+        easyProgrammer.updateComboInterface();
+        easyProgrammer.updateSerialButtons();
+        easyProgrammer.updateTextHexSize();
+
+        removeActiveSwingWorker();
+        easyProgrammer.updateButtons();
+        easyProgrammer.setFocusToTerminal();
+        easyProgrammer.endProcess();
+      }
+      
+      
+//      Integer result = -1000;
+//
+//      try { result = get(); }
+//      catch (InterruptedException ex) { throw new RuntimeException(ex); }
+//      catch (ExecutionException ex) { /* throw new RuntimeException(ex); */ }
+//      finally
+//      {
+//        //System.out.println("Swingworker done");
+//        //execSwingWorkerDone(SwingWorkerTyp.REFRESH, result);
+//        easyProgrammer.updateComboInterface();
+//        easyProgrammer.updateSerialButtons();
+//        easyProgrammer.updateTextHexSize();
+//
+//        if (result>-200 && result<=-100)
+//        {
+//          execSwingWorkerDone(SwingWorkerTyp.LOADPROGRAMFILE, result+100);
+//        }
+//        if (result==0 || result==-100)
+//          easyProgrammer.setUserMessage("Aktualisierung erfolgreich beendet");
+//        else
+//          easyProgrammer.setUserMessage("Fehler bei der Aktualisierung");
+//
+//        easyProgrammer.updateButtons();
+//        removeActiveSwingWorker();
+//        easyProgrammer.endProcess();
+//      }
+    }
+  }
+
+
+  class ConnectSwingWorker extends SwingWorker<Integer,String>
+  {
+    // Job wird in eigenem Thread ausgeführt. Hier dürfen keine Manipulationen
+    // an Swing-Komponenten stattfinden.
+    @Override
+    protected Integer doInBackground() throws Exception
+    {
+      publish("Öffne Schnittstelle '" + easyProgrammer.getSerialPortInfo() + "'");
+      easyProgrammer.serialInterface.connect(easyProgrammer.getSerialPortInfo());
+      //System.out.println("  " + easyProgrammer);
+      //System.out.println("  " + easyProgrammer.serialInterface);
+      //System.out.println("  " + easyProgrammer.serialInterface.getPort());
+      if (easyProgrammer.serialInterface.getPort()==null)
+        return -1;
+      return 0;
+    }
+
+    // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+    // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+    // an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void process(List<String> chunks)
+    {
+      execSwingWorkerProcess(SwingWorkerTyp.CONNECT, chunks);
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      Integer result = -1000;
+
+      try { result = get(); }
+      catch (InterruptedException ex) { throw new RuntimeException(ex); }
+      catch (ExecutionException ex) { /*throw new RuntimeException(ex); */ }
+      finally
+      {
+        switch (result)
+        {
+          case 0:
+            easyProgrammer.setUserMessage("Verbindung zu '" + easyProgrammer.getSerialPortInfo() + "' erfolgreich geöffnet");
+            break;
+
+          default:
+            easyProgrammer.setUserMessage("Fehler: Schnittstelle kann nicht geöffnet werden");
+        }
+        easyProgrammer.updateButtons();
+        easyProgrammer.updateSerialButtons();
+        easyProgrammer.updateDownloadButtons();
+        removeActiveSwingWorker();
+        easyProgrammer.setFocusToTerminal();
+        easyProgrammer.endProcess();
+      }
+    }
+  }
+
+  class LoadProgramFileSwingWorker extends SwingWorker<Integer,String>
+  {
+    // Job wird in eigenem Thread ausgeführt. Hier dürfen keine Manipulationen
+    // an Swing-Komponenten stattfinden.
+    @Override
+    protected Integer doInBackground() throws Exception
+    {
+      publish("Lade Programmdatei '" + easyProgrammer.getProgramFileName() + "'");
+      try { loadFile(); }
+      catch (Exception ex)
+      {
+        ex.printStackTrace(System.err);
+        return -1;
+      }
+      return 0;
+    }
+
+    // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+    // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+    // an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void process(List<String> chunks)
+    {
+      execSwingWorkerProcess(SwingWorkerTyp.LOADPROGRAMFILE, chunks);
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      Integer result = -1000;
+
+      try { result = get(); }
+      catch (InterruptedException ex) { throw new RuntimeException(ex); }
+      catch (ExecutionException ex)   { /* throw new RuntimeException(ex); */ }
+      finally
+      {
+        execSwingWorkerDone(SwingWorkerTyp.LOADPROGRAMFILE, result);
+        easyProgrammer.updateDownloadButtons();
+        easyProgrammer.updateTextHexSize();
+        removeActiveSwingWorker();
+        easyProgrammer.endProcess();
+      }
+    }
+  }
+
+  class IDEServerSwingWorker extends SwingWorker<Integer,String>
+  {
+    final private Thread thread;
+    private BufferedReader inPipeReader;
+    private BufferedWriter outPipeWriter;
+    private PipedReader inPipe;
+    private PipedWriter outPipe;
+
+
+    public IDEServerSwingWorker()
+    {
+      super();
+      this.thread = Thread.currentThread();
+      inPipe = new PipedReader();
+      inPipeReader = new BufferedReader(inPipe);
+      try
+      {
+        outPipe = new PipedWriter(inPipe);
+        outPipeWriter = new BufferedWriter(outPipe);
+      }
+      catch (IOException ex)
+      {
+        ex.printStackTrace(System.err);
+      }
+    }
+
+
+    // Job wird in eigenem Thread ausgeführt. Hier dürfen keine Manipulationen
+    // an Swing-Komponenten stattfinden.
+    @Override
+    protected Integer doInBackground() throws Exception
+    {
+      //System.out.println("Starte IDEServer...");
+      IDEServer server = new IDEServer(easyProgrammer.getServerPort());
+      
+      while (server != null)
+      {
+        try
+        {
+          //System.out.println("Server: Wait for Request ");
+          String [] request = server.getRequest().split(" ");
+          //System.out.println("Server: Request eingetroffen (" + request + ")");
+          String answer = "";
+          for (String cmd : request)
+          {
+            if (cmd.startsWith("wait_") && cmd.endsWith("ms"))
+            {
+              long time = -1;
+              try
+              {
+                Scanner scanner = new Scanner(cmd.substring(5, cmd.length()-2));
+                time = scanner.nextInt();
+              }
+              catch (InputMismatchException ex) {}
+              if (time>0 && time<1000)
+              {
+                Thread.sleep(time);
+                answer = answer + " '" + time + "ms delay done'";
+              }
+              else
+                answer = answer + "'wait_???ms error'";
+            }
+            else
+            {
+              publish(cmd);
+              String cmd_answer = inPipeReader.readLine();
+              if (cmd_answer != null && cmd_answer.startsWith("start"))
+              {
+                int i = 0;
+                for (i=0; i<20000 && sw != null; i++)
+                  Thread.sleep(50);
+                String [] s = cmd_answer.split(" ");
+                cmd_answer = s[1] + " done in " + (i*50) + "ms";
+              }
+              answer = answer + " '" + cmd_answer + "'";
+            }
+          }
+          server.send(answer);
+        }
+        catch (Exception ex)
+        {
+          ex.printStackTrace(System.err);
+          return -1;
+        }
+      }
+
+      return 0;
+    }
+
+    // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+    // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+    // an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void process(List<String> chunks)
+    {
+      //System.out.println("Process request " + chunks.get(0));
+      try
+      {
+        outPipeWriter.write(easyProgrammer.handleServerRequest(chunks.get(0)));
+        outPipeWriter.newLine(); outPipeWriter.flush();
+      }
+      catch (IOException ex)
+      {
+        ex.printStackTrace(System.err);
+      }
+      chunks.remove(0);
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      Integer result = -1000;
+
+      try { result = get(); }
+      catch (InterruptedException ex) { throw new RuntimeException(ex); }
+      catch (ExecutionException ex)   { /* throw new RuntimeException(ex); */ }
+      finally
+      {
+        System.out.println("IDEServer beendet");
+      }
+    }
+  }
+
+
+ class DownloadSwingWorker extends SwingWorker<Integer,String>  implements PropertyChangeListener, ChangeListener
+  {
+    DownloadProtocol downloadProtocol;
+    boolean nocheck;
+
+
+    public DownloadSwingWorker(boolean nocheck)
+    {
+      super();
+      this.nocheck = nocheck;
+    }
+
+    private void updateFile () throws Exception
+    {
+      if (easyProgrammer.programFile.isModified())
+      {
+        publish("Aktualisiere Programmdatei '" + easyProgrammer.getProgramFileName() + "'");
+        //System.out.println("Aktualisiere Datei");
+        try 
+        {
+          loadFile();
+          LOG.info("reloading file");
+        }
+        catch (Exception ex)
+        {
+          ex.printStackTrace(System.err);
+          throw new Exception("Hex-File Aktualisierung gscheitert");
+        }
+        finally
+        {
+          publish("FileUpdate"); // update TolTipp data
+        }
+      }
+    }
+
+    private void resetTarget () throws Exception
+    {
+      easyProgrammer.programFile.setBootloaderMode(2);
+      setProgress(0);
+
+      try
+      {
+        downloadProtocol = new DownloadProtocol(easyProgrammer.serialInterface, easyProgrammer.terminalArea);
+        //downloadProtocol.connect();
+        if (easyProgrammer.isResetBeforeDownloadSelected())
+        {
+          publish("Reset + Warten auf Bootloader-Antwort");
+          String resetCmd = easyProgrammer.getCpuTyp().getResetCommand();
+          downloadProtocol.reset(this, true, resetCmd);
+        }
+      }
+      catch (UnsupportedOperationException ex)
+      {
+        ex.printStackTrace(System.err);
+        throw new Exception("Reset kann nicht ausgeführt werden (2)");
+      }
+      catch (Exception ex)
+      {
+        ex.printStackTrace(System.err);
+        throw new Exception("Reset kann nicht ausgeführt werden (1)");
+      }
+    }
+
+    private void waitForBootloader () throws Exception
+    {
+      if (downloadProtocol.isBootloaderDetetcted())
+        return;
+      
+      if (downloadProtocol.isBootloaderDetetcted() == false)
+      {
+        int timeout = easyProgrammer.getWaitTimeMillis();
+        if (easyProgrammer.isResetBeforeDownloadSelected())
+          publish("Reset gescheitert. Warte " + timeout + "ms auf Bootloader...");
+        else
+          publish("Warte " + timeout + "ms auf Bootloader...");
+        for (int i=0; i<=timeout/100; i++)
+        {
+          if (downloadProtocol.isBootloaderDetetcted())
+            return;
+          setProgress(i*10000/timeout);
+          try { Thread.sleep(100); }
+          catch (Exception ex)
+          {
+            throw new Exception ("Warten auf Bootloader - abgebrochen");
+          }
+        }
+      }
+      throw new Exception("Bootloader nicht detektiert (Timeout)");
+    }
+
+    private void downloadFile () throws Exception
+    {
+      setProgress(0);
+      try { downloadProtocol.download(easyProgrammer.programFile, this); }
+      catch (UnsupportedOperationException ex)
+      {
+        LOG.warning(ex);
+        throw new Exception ("Download gescheitert (1)", ex);
+      }
+      catch (Exception ex)
+      {
+        if (!ex.getMessage().contains("Download ok"))
+          LOG.warning(ex);
+        if (ex instanceof InterruptedException)
+          throw new Exception ("Download abgebrochen", ex);
+        else
+        {
+          if (ex.getMessage().contains("Download ok"))
+          {
+            if (this.nocheck==false)
+              throw ex;
+          }
+          else
+          {
+            LOG.warning(ex);
+            throw new Exception ("Download gescheitert (2)", ex);
+          }
+        }
+      }
+    }
+    
+
+    @Override
+    protected Integer doInBackground() throws Exception
+    {
+      int ret = 0;
+      
+      try
+      {
+        updateFile();
+        resetTarget();
+        waitForBootloader();
+        downloadFile();
+        setProgress(100);
+        publish("Download erfolgreich abgeschlossen");
+      }
+      catch (Exception ex)
+      {
+        if (ex.getMessage().contains("Download ok") == false)
+        {
+          publish("Fehler: " + ex.getMessage());
+          ret = -1;
+        }
+        else
+        {
+          // Download ok but no correct system answer
+          publish (ex.getMessage());
+          ret = -2;
+        }
+        //stateChanged(new ChangeEvent("Error (-997): Download gescheitert"));
+      }
+      finally
+      {
+        if (downloadProtocol.isConnected())
+          downloadProtocol.disconnect();
+        downloadProtocol = null;
+      }
+      
+      return ret;
+    }
+
+
+    @Override
+    protected void process(List<String> chunks)
+    {
+      if (chunks.size()>0)
+      {
+        for (String str : chunks)
+        {
+          if (str != null && str.contains("FileUpdate"))
+            easyProgrammer.updateTextHexSize();
+        }
+        easyProgrammer.setUserMessage((String)chunks.get(chunks.size()-1));
+      }
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      try
+      { 
+        int result = get();
+        easyProgrammer.setProgressBar(100);
+        easyProgrammer.programFile.completeDownloadDone();
+      }              
+      catch (Exception ex)
+      {
+        LOG.warning(ex);
+        easyProgrammer.setProgressBar(-1);
+        if (ex instanceof ExecutionException && ex.getCause() instanceof Exception)
+          ex = (Exception) ex.getCause();
+        String msg = ex.getMessage();
+        if (msg==null || msg.isEmpty())
+          msg = ex.getClass().getSimpleName();
+        easyProgrammer.setUserMessage(String.format("Error (%s)", msg));
+      }
+      finally
+      {
+        removeActiveSwingWorker();
+        easyProgrammer.updateButtons();
+        easyProgrammer.setFocusToTerminal();
+        easyProgrammer.endProcess();
+      }
+    }
+
+    
+    public void stopDownload ()
+    {
+      System.out.println("Stop");
+    }
+
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+      if (this.isDone() == false)
+        easyProgrammer.setProgressBar(this.getProgress());
+    }
+
+
+    public void stateChanged(ChangeEvent e)
+    {
+      Object obj = e.getSource();
+
+      if (obj instanceof Integer)
+        setProgress((Integer)obj);
+      else if(obj instanceof String)
+        publish((String)obj);
+    }
+  }
+
+
+  class ResetSwingWorker extends SwingWorker<Integer,String>  implements PropertyChangeListener, ChangeListener
+  {
+    ResetProtocol resetProtocol;
+    
+    @Override
+    @SuppressWarnings("SleepWhileHoldingLock")
+    protected Integer doInBackground() throws Exception
+    {
+      setProgress(0);
+      try
+      {
+        resetProtocol = new ResetProtocol(easyProgrammer.serialInterface, easyProgrammer.terminalArea);
+        resetProtocol.connect();
+        resetProtocol.reset(this, false, easyProgrammer.getCpuTyp().getResetCommand());
+      }
+      catch (UnsupportedOperationException ex)
+      {
+        stateChanged(new ChangeEvent("Error (-997): Download gescheitert"));
+        return -3;
+      }
+      catch (Exception ex)
+      {
+        throw ex;
+      }
+      finally
+      {
+        resetProtocol.disconnect();
+        resetProtocol = null;
+      }
+
+      setProgress(100);
+      stateChanged(new ChangeEvent("Reset erfolgreich"));
+      return 0;
+    }
+
+    // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+    // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+    // an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void process(List<String> chunks)
+    {
+      if (chunks.size()>0)
+      {
+        easyProgrammer.setUserMessage((String)chunks.get(chunks.size()-1));
+      }
+      //System.out.println("Progress: " + getProgress());
+    }
+
+    // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+    // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+    @Override
+    protected void done()
+    {
+      try
+      { 
+        int result = get();
+        easyProgrammer.setProgressBar(100);
+      }              
+      catch (Exception ex)
+      {
+        LOG.warning(ex);
+        easyProgrammer.setProgressBar(-1);
+        if (ex instanceof ExecutionException && ex.getCause() instanceof Exception)
+          ex = (Exception) ex.getCause();
+        String msg = ex.getMessage();
+        if (msg==null || msg.isEmpty())
+          msg = ex.getClass().getSimpleName();
+        easyProgrammer.setUserMessage(String.format("Error (%s)", msg));
+      }
+      finally
+      {
+        removeActiveSwingWorker();
+        easyProgrammer.updateButtons();
+        easyProgrammer.setFocusToTerminal();
+        easyProgrammer.endProcess();
+      }
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+      if (this.isDone() == false)
+        easyProgrammer.setProgressBar(this.getProgress());
+    }
+
+
+    @Override
+    public void stateChanged(ChangeEvent e)
+    {
+      Object obj = e.getSource();
+
+      if (obj instanceof Integer)
+        setProgress((Integer)obj);
+      else if(obj instanceof String)
+        publish((String)obj);
+    }
+  }
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/SlidingWidthLayout.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/SlidingWidthLayout.java
new file mode 100644 (file)
index 0000000..b3ceea0
--- /dev/null
@@ -0,0 +1,192 @@
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+
+
+/**
+ *
+ * @author steiner
+ */
+public class SlidingWidthLayout implements LayoutManager, java.io.Serializable
+{
+  private int hgap;
+  private int vgap;
+  
+  @Override
+  public void addLayoutComponent (String name, Component comp)
+  {
+    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+  }
+
+
+  @Override
+  public void removeLayoutComponent (Component comp)
+  {
+    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+  }
+
+
+  @Override
+  public Dimension preferredLayoutSize (Container parent)
+  {
+    synchronized (parent.getTreeLock())
+    {
+      Insets insets = parent.getInsets();
+      int ncomponents = parent.getComponentCount();
+      int nrows = 1;
+      int ncols = 1;
+
+      if (nrows > 0)
+      {
+        ncols = (ncomponents + nrows - 1) / nrows;
+      }
+      else
+      {
+        nrows = (ncomponents + ncols - 1) / ncols;
+      }
+      int w = 0;
+      int h = 0;
+      for (int i = 0; i < ncomponents; i++)
+      {
+        Component comp = parent.getComponent(i);
+        Dimension d = comp.getPreferredSize();
+        if (w < d.width)
+        {
+          w = d.width;
+        }
+        if (h < d.height)
+        {
+          h = d.height;
+        }
+      }
+      return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
+                           insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
+    }
+  }
+
+
+  @Override
+  public Dimension minimumLayoutSize (Container parent)
+  {
+    synchronized (parent.getTreeLock())
+    {
+      Insets insets = parent.getInsets();
+      int ncomponents = parent.getComponentCount();
+      int nrows = 1;
+      int ncols = 1;
+
+      if (nrows > 0)
+      {
+        ncols = (ncomponents + nrows - 1) / nrows;
+      }
+      else
+      {
+        nrows = (ncomponents + ncols - 1) / ncols;
+      }
+      int w = 0;
+      int h = 0;
+      for (int i = 0; i < ncomponents; i++)
+      {
+        Component comp = parent.getComponent(i);
+        Dimension d = comp.getMinimumSize();
+        if (w < d.width)
+        {
+          w = d.width;
+        }
+        if (h < d.height)
+        {
+          h = d.height;
+        }
+      }
+      return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
+                           insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
+    }
+  }
+
+
+  @Override
+  public void layoutContainer (Container parent)
+  {
+    synchronized (parent.getTreeLock())
+    {
+      Insets insets = parent.getInsets();
+      int ncomponents = parent.getComponentCount();
+      int nrows = 1;
+      int ncols = 1;
+      boolean ltr = parent.getComponentOrientation().isLeftToRight();
+
+      if (ncomponents == 0)
+      {
+        return;
+      }
+      if (nrows > 0)
+      {
+        ncols = (ncomponents + nrows - 1) / nrows;
+      }
+      else
+      {
+        nrows = (ncomponents + ncols - 1) / ncols;
+      }
+      // 4370316. To position components in the center we should:
+      // 1. get an amount of extra space within Container
+      // 2. incorporate half of that value to the left/top position
+      // Note that we use trancating division for widthOnComponent
+      // The reminder goes to extraWidthAvailable
+      int totalGapsWidth = (ncols - 1) * hgap;
+      int widthWOInsets = parent.getWidth() - (insets.left + insets.right);
+      int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols;
+      int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2;
+
+      int totalGapsHeight = (nrows - 1) * vgap;
+      int heightWOInsets = parent.getHeight() - (insets.top + insets.bottom);
+      int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows;
+      int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2;
+      if (ltr)
+      {
+        for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols; c++, x += widthOnComponent + hgap)
+        {
+          for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap)
+          {
+            int i = r * ncols + c;
+            if (i < ncomponents)
+            {
+              // parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
+              int h = parent.getComponent(i).getPreferredSize().height;
+              if (h<heightOnComponent)
+              {
+                y = y + (heightOnComponent-h)/2;
+                parent.getComponent(i).setBounds(x, y, widthOnComponent, h);
+              }
+              else
+              {
+                parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
+              }
+              
+            }
+          }
+        }
+      }
+      else
+      {
+        for (int c = 0, x = (parent.getWidth() - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols; c++, x -= widthOnComponent + hgap)
+        {
+          for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap)
+          {
+            int i = r * ncols + c;
+            if (i < ncomponents)
+            {
+              parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  
+    
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/gui/TerminalArea.java b/src/at/htlkaindorf/sx/EasyProgrammer/gui/TerminalArea.java
new file mode 100644 (file)
index 0000000..cb87889
--- /dev/null
@@ -0,0 +1,656 @@
+
+package at.htlkaindorf.sx.EasyProgrammer.gui;
+
+import at.htlkaindorf.sx.EasyProgrammer.data.LineTerminal;
+import at.htlkaindorf.sx.EasyProgrammer.serial.SerialInterface;
+import at.htlkaindorf.sx.EasyProgrammer.serial.TerminalProtocol;
+import java.awt.AWTEvent;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.datatransfer.Clipboard;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import javax.accessibility.Accessible;
+import javax.swing.JComponent;
+import javax.swing.JViewport;
+import javax.swing.Scrollable;
+import javax.swing.SwingConstants;
+import javax.swing.SwingWorker;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Implementation of a Text Terminal GUI.
+ * @author Manfred Steiner
+ * see also http://download.oracle.com/javase/tutorial/uiswing/components/scrollpane.html
+ */
+public final class TerminalArea extends JComponent implements Scrollable, Accessible
+{
+  private LineTerminal terminal;  //
+  private InputListener inputListener;
+  private JViewport viewport;
+  //private SerialInterface serialInterface;
+  private TerminalProtocol terminalProtocol;
+  private Font font;              // font for drawing text
+  private Color noFocusBGColor;   // bgColor in case of focus is lost
+  private Color lineBGColor;      // backgrund Color for line output
+  private Dimension charSize;     // width and heigth of one character (monospaced font)
+  private Dimension terminalSize;
+  private Rectangle visibleText;  // visible area in lines and columns
+  private Point textOffset;       // start point of text area in panel area (normally x=1,y=10)
+  private StringBuilder tempText;     // text for special purposes (line number...)
+  private char[] tempChar;
+  private boolean hasFocus;       // =true when TerminalArea has focus (background is white)
+  private boolean focusBlocked;   // =true when no focus should be accepted (i.e. no interface available)
+  private boolean printLine;
+  private boolean printRow;
+  private boolean isfontChanged;  // indicates change of Font (size)
+  private int paintCounter;
+
+
+  public TerminalArea()
+  {
+    super();
+
+    this.terminal = new LineTerminal(300);
+    this.noFocusBGColor = new Color(240,240,240);
+    this.lineBGColor = new Color(255,255,150);
+    enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
+    inputListener = new InputListener(this);
+    addMouseListener(inputListener);
+    addMouseWheelListener(inputListener);
+    addFocusListener(inputListener);
+    addKeyListener(inputListener);
+    setLayout(null);
+    updateUI();
+
+    font = new Font("Monospaced", Font.PLAIN, 16);
+    this.charSize = new Dimension(16,16);
+    this.terminalSize = new Dimension(0,0);
+    this.visibleText = new Rectangle();
+    this.textOffset = new Point(1,4);
+    this.tempText = new StringBuilder(20);
+    this.tempChar = new char [1];
+    this.printLine = true;
+    this.printRow = false;
+    this.isfontChanged = true;
+
+    if (printRow)
+      this.textOffset.x += 4*16;
+
+    if (printLine)
+      this.textOffset.x += 6*16;
+
+  }
+
+  public void copyToClipBoard ()
+  {
+    Clipboard clip = getToolkit().getSystemClipboard();
+    terminal.copyToClipboard(clip);
+  }
+
+  public void deleteContent ()
+  {
+    this.terminal.deleteContent();
+
+  }
+
+
+  public void setFocusBlocked(boolean focusBlocked)
+  {
+    this.focusBlocked = focusBlocked;
+    if (this.hasFocus)
+      this.setFocus(false);
+  }
+
+
+  public boolean isFocusBlocked()
+  {
+    return focusBlocked;
+  }
+
+
+  public void resizeFont (int sizeChange)
+  {
+    if (sizeChange == 0)
+      return;
+
+    int size = this.font.getSize();
+    size += sizeChange;
+
+    if (size<2) size=2;
+    if (size>100) size=100;
+
+    font = new Font("Monospaced", Font.PLAIN, size);
+    this.charSize = new Dimension(size, size);
+    this.isfontChanged = true;
+    this.revalidate();
+    this.repaint();
+  }
+
+  // viewport must be known to set scroll position by program
+  public void setViewport(JViewport viewport)
+  {
+    this.viewport = viewport;
+    this.viewport.setScrollMode(JViewport.BLIT_SCROLL_MODE);
+  }
+
+
+  public void setTerminalProtocol(TerminalProtocol terminalProtocol)
+  {
+    this.terminalProtocol = terminalProtocol;
+  }
+
+
+  public void append (String s)
+  {
+    for (int i=0; i<s.length(); i++)
+      append(s.charAt(i));
+  }
+
+
+  public void append (char c)
+  {
+    int lines = terminal.getLines();
+    int columns = terminal.getColumns();
+    int lastLine = terminal.getLastLine();
+    terminal.append(c);
+
+    int posY = terminal.getCursorLine();
+
+    if (lines != terminal.getLines() || columns != terminal.getColumns() || lastLine != terminal.getLastLine()
+        || posY > (this.visibleText.y + + this.visibleText.height + terminal.getFirstLine()) )
+    {
+      //System.out.println("posY=" + posY + "  visible=" + this.visibleText);
+      updateSize();
+      Rectangle nrect = new Rectangle();
+      nrect.width = textOffset.x + terminal.getColumns()*charSize.width;
+      nrect.height = 2*textOffset.y + terminal.getLines()*charSize.height;
+      Rectangle rect = this.viewport.getViewRect();
+      if (nrect.height > rect.height)
+      {
+        //System.out.print("Scroll Y: " + rect + "  terminal:" + nrect);
+        nrect.y = nrect.height - rect.height;
+        nrect.height = rect.height;
+        this.viewport.scrollRectToVisible(nrect);
+        //System.out.println("  scroll: " + nrect);
+      }
+    }
+
+    //this.revalidate();
+    this.repaint();
+    //if (c=='\n') System.out.println("append: " + terminal);
+  }
+
+
+  private void updateSize ()
+  {
+    int lines = terminal.getLines();
+    int columns = terminal.getColumns();
+    terminalSize.width = charSize.width*columns + textOffset.x;
+    terminalSize.height = charSize.height*lines + 2*textOffset.y;
+
+    Dimension dimParent = this.getParent().getSize();
+    if (dimParent.width > terminalSize.width)
+      terminalSize.width = dimParent.width;
+    if (dimParent.height > terminalSize.height)
+      terminalSize.height = dimParent.height;
+    this.setPreferredSize(terminalSize);
+    this.setSize(terminalSize);
+    //System.out.println("updateSize:" + terminalSize);
+  }
+
+  
+  private void setVisible (Rectangle rect)
+  {
+    int x = rect.x - textOffset.x;
+    this.visibleText.x = x / this.charSize.width;
+    visibleText.width = rect.width / charSize.width + 1;
+    if (x % charSize.width == 0 && rect.width % charSize.width != 0)
+      visibleText.width--;
+
+    int y = rect.y - textOffset.y;
+    visibleText.y = y / charSize.height;
+    visibleText.height = rect.height / charSize.height + 1;
+    if (y % charSize.height == 0 && rect.height % charSize.height != 0)
+      visibleText.height--;
+
+    if (visibleText.width<0 || visibleText.height<0)
+      throw new RuntimeException("setVisible <0 ???");
+
+    //System.out.println("setVisible: " + rect + " --> " + visibleText);
+  }
+
+
+  public void setFocus(boolean focus)
+  {
+    if (focusBlocked)
+      focus = false;
+
+    this.hasFocus = focus;
+    if (focus)
+    {
+      this.viewport.setBackground(Color.WHITE);
+      this.setBackground(Color.WHITE);
+    }
+    else
+    {
+      this.viewport.setBackground(this.noFocusBGColor);
+      this.setBackground(this.noFocusBGColor);
+    }
+    this.revalidate();
+    this.repaint();
+  }
+
+
+  
+  @Override
+  public void paint(Graphics g)
+  {
+    super.paint(g);
+    paintCounter++;
+
+    g.setFont(font);
+    if (isfontChanged)
+    {
+      FontMetrics fontMetrics = g.getFontMetrics();
+      charSize.height = (fontMetrics.getHeight()-fontMetrics.getHeight()/4);
+      if (charSize.height <= 0) charSize.height = 1;
+      charSize.width = fontMetrics.charWidth('0');
+      isfontChanged = false;
+      updateSize();
+      this.textOffset.x = 1;
+      if (printRow) this.textOffset.x += 4*charSize.width;
+      if (printLine) this.textOffset.x += 6*charSize.width;
+    }
+
+    // clear background
+    Rectangle rect = g.getClipBounds();
+    if (this.printLine==true)
+    {
+      g.setColor(this.lineBGColor);
+      g.fillRect(rect.x, rect.y, this.textOffset.x-charSize.width/2, rect.height);
+      rect.x = this.textOffset.x - charSize.width/2;
+    }
+    g.setColor(this.getBackground());
+    g.fillRect(rect.x, rect.y, rect.width,rect.height);
+    g.setColor(Color.BLACK);
+    rect = g.getClipBounds();
+    
+    if (rect.height>20)
+      this.tempChar[0] = 'h';
+
+    //if (rect.height>20) System.out.println("Paint: " + rect);
+
+    if (rect.height>10 && rect.height<20)
+      g.drawRect(rect.x, rect.y, rect.width-1, rect.height-1);
+
+    // calculate visible rows and cols
+    setVisible(rect);
+
+    for (int i= visibleText.y; i< (visibleText.y + visibleText.height); i++)
+    {
+      int line = i + terminal.getFirstLine();
+      this.tempText.delete(0, this.tempText.length());
+
+      if (visibleText.x<0 && terminal.isLineAvailable(line, 0))
+      {
+        if (this.printLine==true)
+          this.tempText.append(String.format("%5d ", line));
+        if (this.printRow==true)
+          this.tempText.append(String.format("%3d ", 0));
+          g.drawString(this.tempText.toString(), 1, textOffset.y + charSize.height*(i+1));
+        //System.out.println("Draw: " + this.tempText + "  y=" + (textOffset.y + charSize.height*(i+1)));
+      }
+      
+      for (int j = Math.max(0,visibleText.x); j<=Math.min(visibleText.x+visibleText.width, terminal.length(line)-1); j++)
+      {
+        //System.out.print(paintCounter + ":  Char " + i + "/" + j);
+        if (terminal.isTextAvailable(line, j))
+        {
+          this.tempChar[0] = terminal.getText(line, j);
+          g.drawChars(this.tempChar, 0, 1, textOffset.x + this.charSize.width*j, textOffset.y + this.charSize.height*(i+1));
+          //System.out.print(" available");
+        }
+       // System.out.println("");
+      }
+    }
+
+  }
+
+
+
+
+
+
+
+
+
+  // The scroll pane calls the client's getScrollableUnitIncrement method whenever
+  // the user clicks one of the buttons on the scroll bar.
+  // This method returns the number of pixels to scroll.
+  @Override
+  public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
+  {
+    //System.out.println("Terminal: getScrollableUnitIncrement");
+    if (orientation == SwingConstants.HORIZONTAL)
+    {
+      return charSize.width;
+    }
+    else
+    {
+      return charSize.height;
+    }
+  }
+
+  // Get the preferred size of the viewport. This allows the client to influence the size of the viewport
+  // in which it is displayed.
+  @Override
+  public Dimension getPreferredScrollableViewportSize()
+  {
+    //System.out.println("Terminal: getPreferredScrollableViewportSize" + this.getPreferredSize());
+    return this.getPreferredSize();
+  }
+
+
+  // The scroll pane calls the client's getScrollableBlockIncrement method each time the user clicks on the track.
+  // This method returns the height of the visible rectangle minus a tick mark. This behavior is typical,
+  // but true if scrolling vertically, otherwise, it's the width.
+  // A block increment should be slightly smaller than the viewport to leave a littl of the previous visible area
+  // for context. For example, a text area might leave one or two lines of text for context
+  @Override
+  public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
+  {
+    //System.out.println("Terminal: getScrollableBlockIncrement");
+     if (orientation == SwingConstants.HORIZONTAL)
+    {
+      return (visibleRect.width/charSize.width) * charSize.width;
+    }
+    else
+    {
+      return (visibleRect.height/charSize.height) * charSize.height;
+    }
+  }
+
+  // Get whether the scroll pane should force the client to be the same width as the viewport.
+  // A return value of true effectively disallows horizontal scrolling.
+  @Override
+  public boolean getScrollableTracksViewportWidth()
+  {
+    //System.out.println("Terminal: getScrollableTracksViewportWidth");
+    return false;
+  }
+
+  // Get whether the scroll pane should force the client to be the same height as the viewport.
+  // A return value of true effectively disallows vertical scrolling.
+  @Override
+  public boolean getScrollableTracksViewportHeight()
+  {
+    //System.out.println("Terminal: getScrollableTracksViewportHeight");
+    return false;
+  }
+
+
+  @Override
+  protected void processKeyEvent(KeyEvent e)
+  {
+    super.processKeyEvent(e);
+    //System.out.println("processKeyEvent");
+  }
+
+
+  @Override
+  protected void processMouseEvent(MouseEvent e)
+  {
+    super.processMouseEvent(e);
+    //System.out.println("processMouseEvent");
+  }
+
+
+  @Override
+  protected void processMouseMotionEvent(MouseEvent e)
+  {
+    super.processMouseMotionEvent(e);
+    //System.out.println("processMouseMotionEvent");
+  }
+
+
+  @Override
+  protected void processMouseWheelEvent(MouseWheelEvent e)
+  {
+    super.processMouseWheelEvent(e);
+    //System.out.println("processMouseWheelEvent");
+  }
+
+  @Override
+  //public boolean isFocusTraversable()
+  public boolean isFocusable()
+  {
+    return true;
+  }
+
+
+  static final class InputListener implements ChangeListener, FocusListener, MouseListener, MouseWheelListener, KeyListener
+  {
+    TerminalArea terminalArea;
+    private boolean dragActive;
+    private int dot;
+    private int mark;
+
+    InputListener (TerminalArea terminalArea)
+    {
+      this.terminalArea = terminalArea;
+    }
+
+
+    @Override
+    public final String toString ()
+    {
+      return "InputEvent";
+    }
+
+
+    // --- ChangeListener methods -------------------
+
+    public final void stateChanged (ChangeEvent e)
+    {
+    }
+
+    // --- FocusListener methods -----------------------------------
+    public void focusGained (FocusEvent fe)
+    {
+      //AppContext.getAppContext().put(FOCUSED_COMPONENT, fe.getSource());
+      terminalArea.setFocus(true);
+      //System.out.println("Focus gained");
+    }
+
+    public void focusLost (FocusEvent fe)
+    {
+      terminalArea.setFocus(false);
+      //System.out.println("Focus lost");
+    }
+
+    // --- MouseListener methods -----------------------------------
+
+    public final void mousePressed (MouseEvent e)
+    {
+      dragActive = true;
+      //System.out.println("mousePressed");
+    }
+
+    public final void mouseReleased (MouseEvent e)
+    {
+      dragActive = false;
+      //System.out.println(" mouseReleased");
+    }
+
+    public final void mouseClicked (MouseEvent e)
+    {
+      terminalArea.requestFocus();
+      //System.out.println("mouseClicked");
+    }
+
+    public final void mouseEntered (MouseEvent e)
+    {
+      //System.out.println("mouseEntered");
+    }
+
+    public final void mouseExited(MouseEvent e)
+    {
+      //System.out.println("mouseExited");
+    }
+
+    // --- KeyListener methods -------------------
+
+    public void keyTyped(KeyEvent e)
+    {
+      char c;
+      //System.out.println("keytyped code=" + e.getKeyCode() + "  char=" + (int)e.getKeyChar() + "  mod=" + e.getModifiers() + "  " + KeyEvent.getKeyModifiersText(e.getModifiers()));
+      //this.terminalArea.append(e.getKeyChar());
+      //System.out.println();
+      //System.out.println(KeyEvent.CTRL_DOWN_MASK);
+      //System.out.println(InputEvent.CTRL_DOWN_MASK);
+      
+      if (this.terminalArea.terminalProtocol.isConnected())
+      {
+        try
+        {
+          c = e.getKeyChar();
+
+          if ((e.getModifiersEx()&KeyEvent.CTRL_DOWN_MASK) == KeyEvent.CTRL_DOWN_MASK)
+          {
+            if (c==10) c=10;
+          }
+          else
+          {
+            if (c==10)
+            {
+              this.terminalArea.terminalProtocol.write('\r');
+              this.terminalArea.terminalProtocol.write('\n');
+              //System.out.println("write char=" + (int)'\r' + " " + (int)'\n');
+              return;
+            }
+          }
+          //System.out.println("write char=" + (int)c);
+          this.terminalArea.terminalProtocol.write(c);
+        }
+        catch (Exception ex)
+        {
+          ex.printStackTrace(System.err);
+        }
+
+        /*
+        if (c=='\n')
+        {
+          this.terminalArea.serialInterface.write('\r');
+          this.terminalArea.serialInterface.write('\n');
+        }
+        else
+          this.terminalArea.serialInterface.write(e.getKeyChar());
+        */
+      }
+
+    }
+
+    public void keyPressed(KeyEvent e)
+    {
+      if (e.getKeyChar() == KeyEvent.CHAR_UNDEFINED)
+      {
+        int key = e.getKeyCode();
+        //Funktionstaste abfragen
+        if (key == KeyEvent.VK_F1)
+        {
+          SwingWorker<Integer, String> worker = new SwingWorker<Integer, String>()
+          {
+            // Job wird in eigenem Thread ausgeführt. Hier dürfen keine Manipulationen
+            // an Swing-Komponenten stattfinden.
+            @Override
+            protected Integer doInBackground() throws Exception
+            {
+              for (int zeile=0; zeile<300; zeile++)
+              {
+                int spalten = (3*zeile) % 20 + 1;
+                if (zeile==20) spalten=90;
+                for (int spalte=0; spalte<spalten; spalte++)
+                {
+                  terminalArea.append(Character.toChars(48 + (spalte+zeile)%10)[0]);
+                  Thread.sleep(1);
+
+                }
+                  terminalArea.append('\n');
+                //this.terminalArea.append('\r');
+              }
+
+              //publish("Verfügbare serielle Schnittstellen finden...", "Aktualisieren");
+              //serialInterface.updateInterfaces();
+              //blish("Serielle Schnittstellen testen");
+              //serialInterface.checkInterfaces();
+              return 0;
+            }
+
+            // Durch publish() veröffentliche Zwischenergebnisse behandeln.
+            // process() wird innerhalb des EDT aufgerufen. Hier können Manipulationen
+            // an GUI-Elementen sicher vorgenommen werden.
+            @Override
+            protected void process(List<String> chunks)
+            {
+            }
+
+            // Worker hat seinen Job beendet. done() wird innerhalb des EDT aufgerufen.
+            // Hier können Manipulationen an GUI-Elementen sicher vorgenommen werden.
+            @Override
+            protected void done()
+            {
+              Integer result = -1;
+
+              try
+              {
+                result = get(); // Endergebnis aus doInBackground() holen.
+              }
+              catch (InterruptedException ex)
+              {
+                 throw new RuntimeException(ex);
+              }
+              catch (ExecutionException ex)
+              {
+                 //throw new RuntimeException(ex);
+              }
+              finally
+              {
+              }
+            }
+
+          };
+          worker.execute();
+        }
+      }
+    }
+
+    public void keyReleased(KeyEvent e)
+    {
+      //System.out.println("keyreleased");
+    }
+
+
+    public void mouseWheelMoved(MouseWheelEvent e)
+    {
+      if (e.isControlDown())
+        this.terminalArea.resizeFont(e.getWheelRotation());
+    }
+  }
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif
new file mode 100644 (file)
index 0000000..04da95e
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/About16.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif
new file mode 100644 (file)
index 0000000..9e11689
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/About24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal.png
new file mode 100644 (file)
index 0000000..89420eb
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal16.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal16.png
new file mode 100644 (file)
index 0000000..152787a
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal16.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png
new file mode 100644 (file)
index 0000000..a39e0f9
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/CleanTerminal24.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif
new file mode 100644 (file)
index 0000000..fa98681
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy16.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif
new file mode 100644 (file)
index 0000000..c665d07
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Copy24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download.png
new file mode 100644 (file)
index 0000000..1dbf99f
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download16.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download16.png
new file mode 100644 (file)
index 0000000..7ad6177
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download16.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png
new file mode 100644 (file)
index 0000000..7d3e816
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Download24.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png
new file mode 100644 (file)
index 0000000..9cf502d
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/EasyProgrammer.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information16.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information16.gif
new file mode 100644 (file)
index 0000000..5748e32
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information16.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information24.gif
new file mode 100644 (file)
index 0000000..16cb3de
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Information24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif
new file mode 100644 (file)
index 0000000..fabd567
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open16.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif
new file mode 100644 (file)
index 0000000..2086bc2
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Open24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif
new file mode 100644 (file)
index 0000000..f118c7e
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste16.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif
new file mode 100644 (file)
index 0000000..26cc4c5
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Paste24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif
new file mode 100644 (file)
index 0000000..2e727b2
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Preferences24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif
new file mode 100644 (file)
index 0000000..577c462
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Refresh24.gif differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop.png
new file mode 100644 (file)
index 0000000..398597e
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop16.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop16.png
new file mode 100644 (file)
index 0000000..59b0824
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop16.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png
new file mode 100644 (file)
index 0000000..59429ce
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/Stop24.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png
new file mode 100644 (file)
index 0000000..d2c7c51
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/connect24.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png b/src/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png
new file mode 100644 (file)
index 0000000..8903bf1
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/disconnect24.png differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_128x128.ico b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_128x128.ico
new file mode 100644 (file)
index 0000000..213d5c7
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_128x128.ico differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_16x16.ico b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_16x16.ico
new file mode 100644 (file)
index 0000000..1b2478c
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_16x16.ico differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_32x32.ico b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_32x32.ico
new file mode 100644 (file)
index 0000000..697aaea
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_32x32.ico differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_64x64.ico b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_64x64.ico
new file mode 100644 (file)
index 0000000..47863fe
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/icons/easyprogrammer_64x64.ico differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/EasyProgrammer32.dll b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/EasyProgrammer32.dll
new file mode 100644 (file)
index 0000000..b8f0061
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/EasyProgrammer32.dll differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/version.txt b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win32/version.txt
new file mode 100644 (file)
index 0000000..a4d477c
--- /dev/null
@@ -0,0 +1 @@
+EasyProgrammer32.dll_1.00_x86_Dec 30 2010_16:12:51_SX
\ No newline at end of file
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/EasyProgrammer64.dll b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/EasyProgrammer64.dll
new file mode 100644 (file)
index 0000000..eaa8b72
Binary files /dev/null and b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/EasyProgrammer64.dll differ
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/version.txt b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammer/win64/version.txt
new file mode 100644 (file)
index 0000000..fb892c1
--- /dev/null
@@ -0,0 +1 @@
+EasyProgrammer64.dll_1.00_amd64_Dec 30 2010_17:32:40_SX
\ No newline at end of file
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammerLib.java b/src/at/htlkaindorf/sx/EasyProgrammer/libs/EasyProgrammerLib.java
new file mode 100644 (file)
index 0000000..00153ca
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.libs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ *
+ * @author steiner
+ */
+public class EasyProgrammerLib
+{
+  private static final String libVersion = "1.00";
+  private static final String libMinorSuffix = "0";
+  private static String libNativeVersion;
+
+  public static final int OS_LINUX = 0;
+  public static final int OS_WINDOWS = 1;
+  public static final int OS_SOLARIS = 2;
+  public static final int OS_MAC_OS_X = 3;
+  private static int osType = -1;
+  
+  public final static long OFN_PATHMUSTEXIST = 2048;
+  public final static long OFN_FILEMUSTEXIST = 4096;
+  public final static long OFN_HIDEREADONLY  = 4;
+
+  private static String libPlatform;
+  private static String libDate;
+  private static String libTime;
+  private static String libAutor;
+  private static Throwable staticException;
+  private static File libFile;
+
+  private static File selectedFile;
+
+  private static native String getLibVersionString ();
+  private static native void   enableFunctionTest ();
+  private static native void   disableFunctionTest ();
+  private static native void   openFileName (String filename) throws Exception;
+  private static native void   zeroGlobalVariable (String variable) throws Exception;
+  private static native void   setGlobalString (String variable, String field, byte [] value) throws Exception;
+  private static native void   setGlobalLONG (String variable, String field, long value) throws Exception;
+  private static native void   setGlobalWORD (String variable, String field, long value) throws Exception;
+  private static native void   setGlobalDWORD (String variable, String field, long value) throws Exception;
+  private static native void   setGlobalLPARAM (String variable, String field, long value) throws Exception;
+  private static native String getGlobalString (String variable, String field) throws Exception;
+  private static native long   getGlobalLONG (String variable, String field) throws Exception;
+  private static native long   getGlobalWORD (String variable, String field) throws Exception;
+  private static native long   getGlobalDWORD (String variable, String field) throws Exception;
+  private static native long   getGlobalLPARAM (String variable, String field) throws Exception;
+  private static native void   printStatus();
+  
+
+  static
+  {
+    String libFolderPath;
+    String libName;
+
+    String osName = System.getProperty("os.name");
+    String architecture = System.getProperty("os.arch");
+    String userHome = System.getProperty("user.home");
+    String fileSeparator = System.getProperty("file.separator");
+    String tmpFolder = System.getProperty("java.io.tmpdir");
+    String libRootFolder = new File(userHome).canWrite() ? userHome : tmpFolder;
+    String javaLibPath = System.getProperty("java.library.path");
+
+    if (osName.equals("Linux"))
+    {
+      osName = "linux";
+      osType = OS_LINUX;
+    }
+    else if (osName.startsWith("Win"))
+    {
+      osName = "windows";
+      osType = OS_WINDOWS;
+    }//since 0.9.0 ->
+    else if (osName.equals("SunOS"))
+    {
+      osName = "solaris";
+      osType = OS_SOLARIS;
+    }
+    else if (osName.equals("Mac OS X") || osName.equals("Darwin"))
+    {//os.name "Darwin" since 2.6.0
+      osName = "mac_os_x";
+      osType = OS_MAC_OS_X;
+    }//<- since 0.9.0
+
+    if (architecture.equals("i386") || architecture.equals("i686"))
+    {
+      architecture = "x86";
+    }
+    else if (architecture.equals("amd64") || architecture.equals("universal"))
+    {//os.arch "universal" since 2.6.0
+      architecture = "x86_64";
+    }
+    else if (architecture.equals("arm"))
+    {//since 2.1.0
+      String floatStr = "sf";
+      if (javaLibPath.toLowerCase().contains("gnueabihf") || javaLibPath.toLowerCase().contains("armhf"))
+      {
+        floatStr = "hf";
+      }
+      else
+      {
+        try
+        {
+          Process readelfProcess = Runtime.getRuntime().exec("readelf -A /proc/self/exe");
+          BufferedReader reader = new BufferedReader(new InputStreamReader(readelfProcess.getInputStream()));
+          String buffer = "";
+          while ((buffer = reader.readLine()) != null && !buffer.isEmpty())
+          {
+            if (buffer.toLowerCase().contains("Tag_ABI_VFP_args".toLowerCase()))
+            {
+              floatStr = "hf";
+              break;
+            }
+          }
+          reader.close();
+        }
+        catch (Exception ex)
+        {
+          //Do nothing
+        }
+      }
+      architecture = "arm" + floatStr;
+    }
+
+    libFolderPath = libRootFolder + fileSeparator + ".easyprogrammer" + fileSeparator + osName;
+    libName = "EasyProgrammer-" + libVersion + "_" + architecture;
+    libName = System.mapLibraryName(libName);
+
+    if (libName.endsWith(".dylib"))
+    { // MacOSX 10.8 fix
+      libName = libName.replace(".dylib", ".jnilib");
+    }
+
+    boolean loadLib = false;
+
+    if (isLibFolderExist(libFolderPath))
+    {
+      if (isLibFileExist(libFolderPath + fileSeparator + libName))
+      {
+        loadLib = true;
+      }
+      else if (extractLib((libFolderPath + fileSeparator + libName), osName, libName))
+      {
+        loadLib = true;
+      }
+    }
+    else if (new File(libFolderPath).mkdirs())
+    {
+      if (extractLib((libFolderPath + fileSeparator + libName), osName, libName))
+      {
+        loadLib = true;
+      }
+    }
+
+    try
+    {
+      if (loadLib)
+      {
+        String libFileName = libFolderPath + fileSeparator + libName;
+        libFile = new File(libFileName);
+        System.load(libFileName);
+        String versionBase = libVersion;
+        String versionNative = getLibVersionString();
+
+        if (versionNative != null && !versionNative.isEmpty())
+        {
+          String [] info = versionNative.split("_");
+          if (info.length>=1) libName = info[0];
+          if (info.length>=2) libNativeVersion = info[1];
+          if (info.length>=3) libPlatform = info[2];
+          if (info.length>=4) libDate = info[3];
+          if (info.length>=5) libTime = info[4];
+          if (info.length>=6) libAutor = info[5];
+        }
+
+        if (!versionBase.equals(libNativeVersion))
+        {
+          System.err.println("Warning! EasyProgrammer Java and Native versions mismatch (Java: " + versionBase + ", Native: " + versionNative + ")");
+        }
+      }
+    }
+    catch (Throwable th)
+    {
+      libFile = null;
+    }
+  }
+
+    
+  private static boolean isLibFolderExist (String libFolderPath)
+  {
+    boolean returnValue = false;
+    File folder = new File(libFolderPath);
+    if (folder.exists() && folder.isDirectory())
+    {
+      returnValue = true;
+    }
+    return returnValue;
+  }
+
+
+  private static boolean isLibFileExist (String libFilePath)
+  {
+    boolean returnValue = false;
+    File folder = new File(libFilePath);
+    if (folder.exists() && folder.isFile())
+    {
+      returnValue = true;
+    }
+    return returnValue;
+  }
+
+    
+  private static boolean extractLib (String libFilePath, String osName, String libName)
+  {
+    boolean returnValue = false;
+    libFile = new File(libFilePath);
+    InputStream input;
+    FileOutputStream output = null;
+    input = EasyProgrammerLib.class.getResourceAsStream("/libs/" + osName + "/" + libName);
+    if (input != null)
+    {
+      int read;
+      byte[] buffer = new byte[4096];
+      try
+      {
+        output = new FileOutputStream(libFilePath);
+        while ((read = input.read(buffer)) != -1)
+        {
+          output.write(buffer, 0, read);
+        }
+        output.close();
+        input.close();
+        returnValue = true;
+      }
+      catch (Exception ex)
+      {
+        try
+        {
+          output.close();
+          if (libFile.exists())
+            libFile.delete();
+        }
+        catch (Exception ex_out) { }
+        finally
+        {
+          libFile = null;
+        }
+        
+        try
+        {
+          input.close();
+        }
+        catch (Exception ex_in) { }
+      }
+    }
+    return returnValue;
+  }
+
+
+    public static String getLibraryVersion()
+    {
+      return libVersion + "." + libMinorSuffix;
+    }
+
+    public static String getLibraryBaseVersion()
+    {
+      return libVersion;
+    }
+
+    public static String getLibraryMinorSuffix()
+    {
+      return libMinorSuffix;
+    }
+
+    public static String getNativeLibraryVersion()
+    {
+      return libNativeVersion;
+    }
+
+
+  public static File getLibFile ()
+  {
+    return libFile;
+  }
+          
+  
+  public static boolean isLibAvailable()
+  {
+    return libFile!=null && libFile.canRead();
+  }
+
+
+
+  public static String getLibAutor()
+  {
+    return libAutor;
+  }
+
+
+  public static String getLibDate()
+  {
+    return libDate;
+  }
+
+
+  public static String getLibTime()
+  {
+    return libTime;
+  }
+
+
+  public static String getLibPlatform()
+  {
+    return libPlatform;
+  }
+  
+  
+  public static void showOpenHexFileDialog (String path, String fileName)
+  {
+    String name = null;
+    int indexPath = -1;
+    int indexExtension = -1;
+
+    try
+    {
+      zeroGlobalVariable("openFileName");
+      if (selectedFile != null)
+      {
+         System.out.println("Name = " + selectedFile.getPath() );
+         //setGlobalString("openFileName", "lpstrFile", selectedFile.getPath().getBytes());
+      }
+
+      setGlobalString("openFileName", "lpstrFilter", "Alle Dateien\0*.*\0Programmdatei (*.hex)\0*.hex\0\0".getBytes());
+      setGlobalDWORD("openFileName", "nFilterIndex", 2);
+      setGlobalString("openFileName", "lpstrTitle", "Programmdatei (Hex-File) fuer ATmega328P auswaehlen...".getBytes());
+      setGlobalDWORD("openFileName", "Flags", OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY);
+      if (selectedFile != null)
+        openFileName(selectedFile.getPath());
+      else
+        openFileName(null);
+      
+      name = getGlobalString("openFileName", "lpstrFile");
+      indexPath =  (int) getGlobalWORD("openFileName", "nFileOffset");
+      indexExtension = (int) getGlobalWORD("openFileName", "nFileExtension");
+    }
+    catch (Exception ex)
+    {
+      throw new RuntimeException(ex.getMessage());
+    }
+
+    if (name == null || name.length() == 0)
+      selectedFile = null;
+    else
+      selectedFile = new File(name);
+  }
+
+  public static File getSelectedFile ()
+  {
+    return selectedFile;
+  }
+
+  public static void main(String[] args)
+  {
+    System.out.println("Lib available: " + isLibAvailable());
+    if (isLibAvailable())
+    {
+      System.out.println("Library:  " + getLibVersionString());
+      System.out.println("Platform: " + getLibPlatform());
+      System.out.println("Date:     " + getLibDate());
+      System.out.println("Time:     " + getLibTime());
+      System.out.println("Autor:    " + getLibAutor());
+    }
+    else
+    {
+      System.out.println("Error: " + staticException);
+    }
+    
+    //EasyProgrammerLib ep = new EasyProgrammerLib();
+    //EasyProgrammerLib.enableFunctionTest();
+    //EasyProgrammerLib.disableFunctionTest();
+    //EasyProgrammerLib.printStatus();
+    int err = 0;
+    try
+    {
+      zeroGlobalVariable("openFileName");
+      setGlobalString("openFileName", "lpstrFilter", "Alle Dateien\0*.*\0Programmdatei (*.hex)\0*.hex\0\0".getBytes());
+      setGlobalDWORD("openFileName", "nFilterIndex", 2);
+      setGlobalString("openFileName", "lpstrTitle", "Programmdatei öffnen".getBytes());
+      setGlobalDWORD("openFileName", "Flags", OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY);
+      openFileName(null);
+      System.out.println("FileName = " + getGlobalString("openFileName", "lpstrFile"));
+      System.out.println("nFilterIndex = " + getGlobalDWORD("openFileName", "nFilterIndex"));
+      System.out.println("nFileOffset = " + getGlobalWORD("openFileName", "nFileOffset"));
+      System.out.println("nFileExtension = " + getGlobalWORD("openFileName", "nFileExtension"));
+
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+    //EasyProgrammerLib.printStatus();
+  }
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega328P.hex b/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega328P.hex
new file mode 100644 (file)
index 0000000..68297cf
--- /dev/null
@@ -0,0 +1,129 @@
+:107800000C94343C0C94513C0C94513C0C94513CE1\r
+:107810000C94513C0C94513C0C94513C0C94513CB4\r
+:107820000C94513C0C94513C0C94513C0C94513CA4\r
+:107830000C94513C0C94513C0C94513C0C94513C94\r
+:107840000C94513C0C94513C0C94513C0C94513C84\r
+:107850000C94513C0C94513C0C94513C0C94513C74\r
+:107860000C94513C0C94513C11241FBECFEFD8E036\r
+:10787000DEBFCDBF11E0A0E0B1E0E0E9FFE702C06C\r
+:1078800005900D92A631B107D9F711E0A6E1B1E05C\r
+:1078900001C01D92A931B107E1F70E94793F0C9414\r
+:1078A000C63F0C94003C14BE88E10FB6F894809358\r
+:1078B0006000109260000FBE92E09093C000809331\r
+:1078C000C1001092C50089E18093C40008958091A1\r
+:1078D000C000881F8827881F08958091C00087FFF7\r
+:1078E000FCCF8091C60008958093C6008091C000AF\r
+:1078F00085FFFCCF0895FC0107C08093C6008091EE\r
+:10790000C00085FFFCCF319680818823B1F70895B0\r
+:107910009C01F9012F5F3F4F8491882339F08093B8\r
+:10792000C6008091C00085FFFCCFF3CF08958DE0A5\r
+:107930008093C6008091C00085FFFCCF8AE08093D1\r
+:10794000C6008091C00085FFFCCF0895982F80531A\r
+:107950008A3068F08151863010F4865F0895892F4F\r
+:107960008156863010F080E00895892F875508955C\r
+:107970000F931F93062F0E94A63C182F802F0E9462\r
+:10798000A63C1295107F810F1F910F910895FC0165\r
+:10799000808161810E94B83C809318010895FC01A8\r
+:1079A000808161810E94B83C282F90E00497803646\r
+:1079B000910548F41092C1001092C5002093C400B4\r
+:1079C00088E18093C1000895982F92959F708F70E1\r
+:1079D0009A3018F0292F295C02C0292F205D8A30A7\r
+:1079E00018F0982F995C02C0982F905D2093C600E4\r
+:1079F0008091C00085FFFCCF9093C6008091C000AD\r
+:107A000085FFFCCF0895EF92FF921F93CF93DF93F2\r
+:107A1000EC0189816A810E94B83C182FE82EFF246E\r
+:107A20000E94973C812F0E94E43C8AE38093C60029\r
+:107A30008091C00085FFFCCFF694FE2CEE24F794D5\r
+:107A4000E79410E0F701E10FF11D949188818236EF\r
+:107A500039F49093C6008091C00085FFFCCF03C02D\r
+:107A6000892F0E94E43C1F5F103861F70E94973C09\r
+:107A7000DF91CF911F91FF90EF9008952F923F9249\r
+:107A80004F925F926F927F928F929F92AF92BF922E\r
+:107A9000CF92DF92EF92FF920F931F93DF93CF93DA\r
+:107AA000CDB7DEB7CD58D1400FB6F894DEBF0FBECC\r
+:107AB000CDBF88EE93E02CE231E0F9013197F1F788\r
+:107AC0000197D9F70E94973C80E091E00E947B3CAF\r
+:107AD000CC24DD24F2E88F2E912C8C0E9D1E1E01ED\r
+:107AE0000894211C311CBE016F577F4FC457DE4FD5\r
+:107AF00079836883CC58D1408091C00087FFFCCF48\r
+:107B00008091C600F401EC0DFD1D80830894C11C1A\r
+:107B1000D11C73E0C716D10461F4F401808186346E\r
+:107B200059F7F8E5F093C6008091C00085FFFCCFBF\r
+:107B300020C063E8C616D104F9F67DE37093C60051\r
+:107B40008091C00085FFFCCFF40181818093C60045\r
+:107B50008091C00085FFFCCFF40182818093C60034\r
+:107B60008091C00085FFFCCFCB5FDE4F1882C550EF\r
+:107B7000D140F4018081863471F488EE93E0ECE228\r
+:107B8000F1E03197F1F70197D1F7E0911601F0910B\r
+:107B900017010995F8C0803509F0F5C0F401F181AD\r
+:107BA000C657DE4FF883CA58D140F401A280B09086\r
+:107BB0001801EE24FF2403E010E090E03FC0F1E064\r
+:107BC000FB1538F463E06B15F8F48601EE24FF240E\r
+:107BD00027C0D401A00FB11F0F5F1F4FF401E00FAA\r
+:107BE000F11F8C916081C557DE4F9883CB58D140EF\r
+:107BF0000E94B83CF101EE0DFF1D8083C557DE4F9A\r
+:107C00009881CB58D14008C0F101EE0DFF1DD40181\r
+:107C1000A00FB11F8C91808370E8E716F1042CF45B\r
+:107C2000F101EE0DFF1D8081980F0894E11CF11CFD\r
+:107C300081E8E816F10434F40F5F1F4F0C151D05A1\r
+:107C40000CF4BDCFBB2019F0E2E0BE1641F4F0E821\r
+:107C5000EF16F104F1F01E2D0027016076C061E0FF\r
+:107C6000B61619F073E0B716A1F481E8E816F1042E\r
+:107C700021F01E2D0027026068C0CF57DF4F88819A\r
+:107C8000C158D040981729F0792E662483010360EB\r
+:107C90005CC0F999FECFC657DE4F8881CA58D140E3\r
+:107CA0006A2D0E94B83C482F50E05695542F442727\r
+:107CB0005795479563E0FA0160935700E89507B63A\r
+:107CC00000FCFDCFD1019A0111965C9011974424DC\r
+:107CD0008C91F201E80FF11DCF0161E0F9010C0177\r
+:107CE00060935700E895112412962E5F3F4FC457BA\r
+:107CF000DE4F88819981CC58D140A817B90721F768\r
+:107D000065E0FA0160935700E89507B600FCFDCFE7\r
+:107D100071E170935700E89520E030E090E0F901C0\r
+:107D2000E40FF51FE4919E0FD101A20FB31F8C91B8\r
+:107D3000E81721F0122F0027046007C02F5F3F4F84\r
+:107D40002038310561F700E010E080E28093C60042\r
+:107D50008091C00085FFFCCF892F0E94E43C90E217\r
+:107D60009093C6008091C00085FFFCCF802F0E94B9\r
+:107D7000E43CE0E2E093C6008091C00085FFFCCFC8\r
+:107D8000812F0E94E43C0E94973C80E091E00E9499\r
+:107D90007B3CCC24DD24B0CEFC018081813391F486\r
+:107DA0008181823379F48281883361F48091180172\r
+:107DB000843018F40E943E3D05C0E0911401F0911A\r
+:107DC00015010995E0911601F091170109950895A3\r
+:107DD000EF92FF920F931F93DF93CF93CDB7DEB750\r
+:107DE00060970FB6F894DEBF0FBECDBF982F20E08E\r
+:107DF000AE014F5F5F4F992371F02F3060F4909385\r
+:107E0000C6008091C00085FFFCCFFA01E20FF11D92\r
+:107E100090832F5F90E08091C00087FF06C0809123\r
+:107E2000C00087FFFCCF9091C6009A3011F09D30C2\r
+:107E300011F7CE010196FC01E20FF11D1082022F15\r
+:107E40000F5F10E07C0140C0F701E10FF11D808160\r
+:107E50008034C9F51F5F812F90E0F701E80FF91F0B\r
+:107E6000E081E73631F1E83628F4E436E1F0E63631\r
+:107E700051F513C0E23711F1E33719F0ED3619F57A\r
+:107E800006C001968E0D9F1D0E94CF3C1CC001961E\r
+:107E90008E0D9F1D0E94C73C16C001968E0D9F1D22\r
+:107EA0000E94CC3E10C001968E0D9F1D0E94033D86\r
+:107EB0000AC0E0911601F091170104C0E09114018D\r
+:107EC000F091150109951F5F101708F4BDCFE091DF\r
+:107ED0001401F0911501099560960FB6F894DEBF74\r
+:107EE0000FBECDBFCF91DF911F910F91FF90EF900B\r
+:107EF0000895EF92FF921F93CF93DF930E94533C1C\r
+:107F0000109218010E94973C84EC9FE70E94883CE5\r
+:107F10000E94973C83E091E00E947B3C0E94973C4A\r
+:107F2000C0E0D0E010E0ACE2EA2EA1E0FA2E82E15F\r
+:107F300091E00E947B3C219684EF91E0F70131971C\r
+:107F4000F1F70197D9F78091C00087FF06C08091B3\r
+:107F5000C00087FFFCCF1091C600C832D10511F0D8\r
+:107F6000103429F70E94973CA8971CF4812F0E9497\r
+:107F7000E83EE0911601F0911701099580E090E04C\r
+:107F8000DF91CF911F91FF90EF900895F894FFCF6C\r
+:107F9000663E00202E2E2E207072657373202740BF\r
+:067FA00027002E0000780E\r
+:107FC400426F6F746C6F6164657220566572736979\r
+:107FD4006F6E20322E3035205B41746D65676133DE\r
+:107FE4003238502C323031312D30382D32372C5339\r
+:0C7FF400585D2000E83EC47F02003412FB\r
+:040000030000780081\r
+:00000001FF\r
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega8L.hex b/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_Atmega8L.hex
new file mode 100644 (file)
index 0000000..ce5d378
--- /dev/null
@@ -0,0 +1,112 @@
+:1018000012C02CC02BC02AC029C028C027C026C0A7\r
+:1018100025C024C023C022C021C020C01FC01EC0BC\r
+:101820001DC01CC01BC011241FBECFE5D4E0DEBF0D\r
+:10183000CDBF10E0A0E6B0E0ECE7FEE102C005900D\r
+:101840000D92A637B107D9F710E0A6E7B0E001C0C6\r
+:101850001D92A937B107E1F7D0D20EC3D1CF14BE84\r
+:1018600088E10FB6F89481BD11BC0FBE92E09BB920\r
+:101870008AB910BC89E189B908958BB1881F88277E\r
+:10188000881F08955F9BFECF8CB108958CB95D9B36\r
+:10189000FECF0895FC0104C08CB95D9BFECF31964C\r
+:1018A00080818823C9F70895FC01019624912223A1\r
+:1018B00021F02CB95D9BFECFF7CF08958DE08CB958\r
+:1018C0005D9BFECF8AE08CB95D9BFECF0895982F7B\r
+:1018D00080538A3068F08151863010F4865F089515\r
+:1018E000892F8156863010F080E00895892F875522\r
+:1018F00008950F931F93062FEADF182F802FE7DF3D\r
+:101900001295107F810F1F910F910895FC01808126\r
+:101910006181EFDF809378000895FC01808161810F\r
+:10192000E8DF282F90E004978036910528F41AB854\r
+:1019300010BC29B988E18AB90895982F92959F70B3\r
+:101940008F709A3010F0995C01C0905D8A3010F071\r
+:10195000895C01C0805D9CB95D9BFECF8CB95D9BAD\r
+:10196000FECF0895FF920F931F93CF93DF93FC0157\r
+:1019700080816181BEDF182FA1DF812FDEDF8AE346\r
+:101980008CB95D9BFECF012F10E096E0000F111F78\r
+:101990009A95E1F7C0E0D0E080E2F82EFE01E00F7A\r
+:1019A000F11FE4918E2FC9DFFCB85D9BFECFCE0105\r
+:1019B00087709070892B19F4FCB85D9BFECF21963F\r
+:1019C000C034D10559F77ADFDF91CF911F910F9184\r
+:1019D000FF9008952F923F924F925F926F927F9265\r
+:1019E0008F929F92AF92BF92CF92DF92EF92FF922F\r
+:1019F0000F931F93DF93CF93CDB7DEB7CD5CD0406D\r
+:101A00000FB6F894DEBF0FBECDBF88EE93E02CE298\r
+:101A100031E0F9013197F1F70197D9F74FDF80E60F\r
+:101A200090E038DF20E030E0F2E48F2E912C8C0E35\r
+:101A30009D1E1E010894211C311CBE016F5B7F4F4F\r
+:101A4000C453DF4F79836883CC5CD04001C09601DA\r
+:101A50005F9BFECF8CB1F401E20FF31F808369011D\r
+:101A60000894C11CD11C71E0C716D10429F4F401FB\r
+:101A700080818A3061F76901F3E0CF16D10449F41F\r
+:101A8000F4018081863419F7F8E5FCB95D9BFECF3F\r
+:101A900017C063E4C616D104D1F67DE37CB95D9B23\r
+:101AA000FECFF40181818CB95D9BFECFF401828170\r
+:101AB0008CB95D9BFECFCB57DF4F1882C558D04005\r
+:101AC000F4018081863471F488EE93E0ECE2F1E079\r
+:101AD0003197F1F70197D1F7E0917600F091770017\r
+:101AE0000995E8C0803509F0E5C0F401F181C653DD\r
+:101AF000DF4FF883CA5CD040F401A280B090780038\r
+:101B0000EE24FF2403E010E090E03EC0F1E0FB157E\r
+:101B100038F463E06B15F0F48601EE24FF2426C050\r
+:101B2000D401A00FB11F0F5F1F4FF401E00FF11F91\r
+:101B30008C916081C553DF4F9883CB5CD040D9DE58\r
+:101B4000F101EE0DFF1D8083C553DF4F9881CB5C03\r
+:101B5000D04008C0F101EE0DFF1DD401A00FB11F50\r
+:101B60008C91808370E4E716F1042CF4F101EE0D02\r
+:101B7000FF1D8081980F0894E11CF11C81E4E81698\r
+:101B8000F10434F40F5F1F4F0C151D050CF4BECF8C\r
+:101B9000BB2019F0E2E0BE1641F4F0E4EF16F104C8\r
+:101BA000E1F01E2D0027016073C061E0B61619F048\r
+:101BB00073E0B71691F481E4E816F10421F01E2DCC\r
+:101BC0000027026065C022968FAD2297981729F0F2\r
+:101BD000792E6624830103605BC0E199FECFC65372\r
+:101BE000DF4F8881CA5CD0406A2D83DE482F50E0E9\r
+:101BF00066E0440F551F6A95E1F763E0FA016093D0\r
+:101C00005700E89507B600FCFDCFD1019A01119667\r
+:101C10005C90119744248C91F201E80FF11DCF01E3\r
+:101C200061E0F9010C0160935700E89511241296C8\r
+:101C30002E5F3F4FC453DF4F88819981CC5CD040E9\r
+:101C4000A817B90721F765E0FA0160935700E895F6\r
+:101C500007B600FCFDCF71E170935700E89520E0D6\r
+:101C600030E090E0F901E40FF51FE4919E0FD101FF\r
+:101C7000A20FB31F8C91E81721F0122F00270460E8\r
+:101C800007C02F5F3F4F2034310561F700E010E0BF\r
+:101C900080E28CB95D9BFECF892F4FDE90E29CB92C\r
+:101CA0005D9BFECF802F49DEE0E2ECB95D9BFECF6D\r
+:101CB000812F43DE03DE80E690E0ECDDCC24DD24E2\r
+:101CC000C6CEFC018081863371F48181843359F45E\r
+:101CD00080917800843010F47DDE05C0E0917400BE\r
+:101CE000F09175000995E0917600F09177000995E3\r
+:101CF0000895EF92FF920F931F93DF93CF93CDB789\r
+:101D0000DEB760970FB6F894DEBF0FBECDBF20E000\r
+:101D1000AE014F5F5F4F882359F02F3048F48CB9E4\r
+:101D20005D9BFECFFA01E20FF11D80832F5F80E003\r
+:101D30005F9B03C05F9BFECF8CB18A3011F08D306A\r
+:101D400051F7CE010196FC01E20FF11D1082022F26\r
+:101D50000F5F10E07C013CC0F701E10FF11D8081B5\r
+:101D60008034A9F51F5F812F90E0F701E80FF91F7C\r
+:101D7000E081E73611F1E83628F4E436C9F0E636BA\r
+:101D800031F511C0E237F1F0E33719F0ED36F9F42F\r
+:101D900005C001968E0D9F1DC0DD19C001968E0DE8\r
+:101DA0009F1DB4DD14C001968E0D9F1D8ADF0FC0EC\r
+:101DB00001968E0D9F1DD6DD0AC0E0917600F09150\r
+:101DC000770004C0E0917400F091750009951F5FE1\r
+:101DD000101710F273DDE0917400F0917500099511\r
+:101DE00060960FB6F894DEBF0FBECDBFCF91DF91E6\r
+:101DF0001F910F91FF90EF900895EF92FF921F9324\r
+:101E0000CF93DF932CDD1092780058DD84EC9FE1B6\r
+:101E10004BDD54DD83E690E03DDD50DDC0E0D0E0F9\r
+:101E200010E0ACE2EA2EA1E0FA2E82E790E032DD8B\r
+:101E3000219684EF91E0F7013197F1F70197D9F7F7\r
+:101E40005F9B03C05F9BFECF1CB1C832D10511F070\r
+:101E5000103459F733DDA89714F4812F4ADFE0914D\r
+:101E60007600F0917700099580E090E0DF91CF91C6\r
+:0C1E70001F91FF90EF900895F894FFCFB1\r
+:101E7C00663E00202E2E2E20707265737320274034\r
+:061E8C0027002E000018E3\r
+:101FC400426F6F746C6F61646572205665727369D9\r
+:101FD4006F6E20322E3035205B41746D6567613839\r
+:101FE4004C2C323031312D30382D32382C53585D51\r
+:0C1FF40020000000790EC41F020034120F\r
+:0400000300001800E1\r
+:00000001FF\r
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_atmega16.hex b/src/at/htlkaindorf/sx/EasyProgrammer/libs/bootloader/bootloader_atmega16.hex
new file mode 100644 (file)
index 0000000..1d3a7c7
--- /dev/null
@@ -0,0 +1,114 @@
+:103800000C942A1C0C94471C0C94471C0C94471CC9\r
+:103810000C94471C0C94471C0C94471C0C94471C9C\r
+:103820000C94471C0C94471C0C94471C0C94471C8C\r
+:103830000C94471C0C94471C0C94471C0C94471C7C\r
+:103840000C94471C0C94471C0C94471C0C94471C6C\r
+:103850000C94471C11241FBECFE5D4E0DEBFCDBFC2\r
+:1038600010E0A0E6B0E0E0EAFEE302C005900D92B1\r
+:10387000A637B107D9F710E0A6E7B0E001C01D9266\r
+:10388000A937B107E1F70E94061F0C944E1F0C9454\r
+:10389000001C14BE88E10FB6F89481BD11BC0FBEA8\r
+:1038A00092E09BB98AB910BC89E189B9089508955D\r
+:1038B0008BB1881F8827881F08955F9BFECF8CB12E\r
+:1038C00008958CB95D9BFECF0895FC0104C08CB9AE\r
+:1038D0005D9BFECF319680818823C9F70895FC0156\r
+:1038E00001962491222321F02CB95D9BFECFF7CFC6\r
+:1038F00008958DE08CB95D9BFECF8AE08CB95D9B0D\r
+:10390000FECF0895982F80538A3068F08151863019\r
+:1039100010F4865F0895892F8156863010F080E07C\r
+:103920000895892F875508950F931F93062F0E949E\r
+:10393000821C182F802F0E94821C1295107F810FED\r
+:103940001F910F910895FC01808161810E94941C58\r
+:10395000809378000895982F92959F708F709A3079\r
+:1039600010F0995C01C0905D8A3010F0895C01C054\r
+:10397000805D9CB95D9BFECF8CB95D9BFECF0895A9\r
+:10398000EF92FF921F93CF93DF93EC0189816A81BD\r
+:103990000E94941C182FE82EFF240E94791C812F6E\r
+:1039A0000E94AB1C8AE38CB95D9BFECFF694FE2C83\r
+:1039B000EE24F794E79410E0F701E10FF11D9491E4\r
+:1039C0008881823621F49CB95D9BFECF03C0892F8C\r
+:1039D0000E94AB1C1F5F103879F70E94791CDF91A1\r
+:1039E000CF911F91FF90EF9008952F923F924F92A9\r
+:1039F0005F926F927F928F929F92AF92BF92CF927F\r
+:103A0000DF92EF92FF920F931F93DF93CF93CDB787\r
+:103A1000DEB7CD58D1400FB6F894DEBF0FBECDBF94\r
+:103A200088EE93E02CE231E0F9013197F1F701974C\r
+:103A3000D9F70E94791C80E690E00E94651CCC2496\r
+:103A4000DD24F2E88F2E912C8C0E9D1E1E01089411\r
+:103A5000211C311CBE016F577F4FC457DE4F798345\r
+:103A60006883CC58D1405F9BFECF8CB1F401EC0D44\r
+:103A7000FD1D80830894C11CD11C73E0C716D104BE\r
+:103A800049F4F4018081863471F7F8E5FCB95D9B57\r
+:103A9000FECF17C063E8C616D10429F77DE37CB9D1\r
+:103AA0005D9BFECFF40181818CB95D9BFECFF4015B\r
+:103AB00082818CB95D9BFECFCB5FDE4F1882C550F3\r
+:103AC000D140F4018081863471F488EE93E0ECE219\r
+:103AD000F1E03197F1F70197D1F7E0917600F0919D\r
+:103AE00077000995EFC0803509F0ECC0F401F18151\r
+:103AF000C657DE4FF883CA58D140F401A280B09077\r
+:103B00007800EE24FF2403E010E090E03FC0F1E0F5\r
+:103B1000FB1538F463E06B15F8F48601EE24FF24FE\r
+:103B200027C0D401A00FB11F0F5F1F4FF401E00F9A\r
+:103B3000F11F8C916081C557DE4F9883CB58D140DF\r
+:103B40000E94941CF101EE0DFF1D8083C557DE4FCE\r
+:103B50009881CB58D14008C0F101EE0DFF1DD40172\r
+:103B6000A00FB11F8C91808370E8E716F1042CF44C\r
+:103B7000F101EE0DFF1D8081980F0894E11CF11CEE\r
+:103B800081E8E816F10434F40F5F1F4F0C151D0592\r
+:103B90000CF4BDCFBB2019F0E2E0BE1641F4F0E812\r
+:103BA000EF16F104F1F01E2D0027016076C061E0F0\r
+:103BB000B61619F073E0B716A1F481E8E816F1041F\r
+:103BC00021F01E2D0027026068C0CF57DF4F88818B\r
+:103BD000C158D040981729F0792E662483010360DC\r
+:103BE0005CC0E199FECFC657DE4F8881CA58D140EC\r
+:103BF0006A2D0E94941C482F50E05695542F44275C\r
+:103C00005795479563E0FA0160935700E89507B62A\r
+:103C100000FCFDCFD1019A0111965C9011974424CC\r
+:103C20008C91F201E80FF11DCF0161E0F9010C0167\r
+:103C300060935700E895112412962E5F3F4FC457AA\r
+:103C4000DE4F88819981CC58D140A817B90721F758\r
+:103C500065E0FA0160935700E89507B600FCFDCFD8\r
+:103C600071E170935700E89520E030E090E0F901B1\r
+:103C7000E40FF51FE4919E0FD101A20FB31F8C91A9\r
+:103C8000E81721F0122F0027046007C02F5F3F4F75\r
+:103C90002038310561F700E010E080E28CB95D9BCF\r
+:103CA000FECF892F0E94AB1C90E29CB95D9BFECF9A\r
+:103CB000802F0E94AB1CE0E2ECB95D9BFECF812F10\r
+:103CC0000E94AB1C0E94791C80E690E00E94651C5B\r
+:103CD000CC24DD24C8CEFC018081813391F4818124\r
+:103CE000823379F48281883361F480917800843062\r
+:103CF00018F40E94F51C05C0E0917400F091750065\r
+:103D00000995E0917600F091770009950895EF927A\r
+:103D1000FF920F931F93DF93CF93CDB7DEB76097DA\r
+:103D20000FB6F894DEBF0FBECDBF20E0AE014F5FEF\r
+:103D30005F4F882359F02F3048F48CB95D9BFECF3C\r
+:103D4000FA01E20FF11D80832F5F80E05F9B03C0CB\r
+:103D50005F9BFECF8CB18A3011F08D3051F7CE01D0\r
+:103D60000196FC01E20FF11D1082022F0F5F10E09F\r
+:103D70007C0138C0F701E10FF11D8081803489F5A5\r
+:103D80001F5F812F90E0F701E80FF91FE081E73610\r
+:103D9000F1F0E83628F4E436A1F0E63611F50BC070\r
+:103DA000ED3619F0E237E9F417C001968E0D9F1D2C\r
+:103DB0000E94A31C16C001968E0D9F1D0E946B1EB3\r
+:103DC00010C001968E0D9F1D0E94C01C0AC0E0917C\r
+:103DD0007600F091770004C0E0917400F0917500D6\r
+:103DE00009951F5F101730F2E0917400F091750093\r
+:103DF000099560960FB6F894DEBF0FBECDBFCF9188\r
+:103E0000DF911F910F91FF90EF900895EF92FF9235\r
+:103E10001F93CF93DF930E94491C109278000E9459\r
+:103E2000791C84EC9FE30E946F1C0E94791C83E63E\r
+:103E300090E00E94651C0E94791CC0E0D0E010E078\r
+:103E4000ACE2EA2EA1E0FA2E82E790E00E94651C27\r
+:103E5000219684EF91E0F7013197F1F70197D9F7B7\r
+:103E60005F9B03C05F9BFECF1CB1C832D10511F030\r
+:103E7000103451F70E94791CA8971CF4812F0E94DE\r
+:103E8000871EE0917600F0917700099580E090E040\r
+:103E9000DF91CF911F91FF90EF900895F894FFCF9D\r
+:103EA000663E00202E2E2E207072657373202740F0\r
+:063EB00027002E0000387F\r
+:103FC400426F6F746C6F61646572205665727369B9\r
+:103FD4006F6E20322E3035205B41746D6567613120\r
+:103FE400362C323031312D30382D32372C53585D48\r
+:0C3FF40020202000871EC43F0200341271\r
+:0400000300003800C1\r
+:00000001FF\r
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/ExtendedLogRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/ExtendedLogRecord.java
new file mode 100644 (file)
index 0000000..a6f0500
--- /dev/null
@@ -0,0 +1,101 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public abstract class ExtendedLogRecord extends LogRecord
+{
+  protected final StackTraceElement location;
+  protected final StackTraceElement [] stackTrace;
+
+  public ExtendedLogRecord (Level level, String msg, int locationStackTraceIndex)
+  {
+    this(level, msg, locationStackTraceIndex+1, 0);
+  }
+  
+  
+  public ExtendedLogRecord (Level level, String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(level, msg);
+    Throwable th = new Throwable();
+
+//    for (StackTraceElement e : th.getStackTrace())
+//      System.out.println(String.format("at %s.%s(%s:%d)",
+//                         e.getClassName(), e.getMethodName(),
+//                         e.getFileName(), e.getLineNumber()));
+    
+    location = th.getStackTrace()[locationStackTraceIndex];
+        if (locationStackTraceDepth !=0)
+    {
+      stackTrace = new StackTraceElement[locationStackTraceDepth>0 ? Math.min(locationStackTraceDepth, th.getStackTrace().length-locationStackTraceIndex-1) : th.getStackTrace().length-locationStackTraceIndex-1];
+      for (int i=0; i<stackTrace.length; i++)
+        stackTrace[i] = th.getStackTrace()[locationStackTraceIndex+i+1];
+    }
+    else
+      stackTrace = null;
+  }
+    
+  
+  public ExtendedLogRecord (Level level, String msg, Throwable th, int locationStackTraceIndex)
+  {
+    this(level, msg, th, locationStackTraceIndex+1, 0);
+  }
+      
+  
+  public ExtendedLogRecord (Level level, String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(level, msg);
+    setThrown(th);
+    location = th.getStackTrace()[locationStackTraceIndex];
+    if (locationStackTraceDepth != 0)
+    {
+      stackTrace = new StackTraceElement[locationStackTraceDepth>0 ? locationStackTraceDepth : th.getStackTrace().length-locationStackTraceIndex-1];
+      for (int i=0; i<stackTrace.length; i++)
+        stackTrace[i] = th.getStackTrace()[locationStackTraceIndex+i+1];
+    }
+    else
+      stackTrace = null;
+  }
+
+  public StackTraceElement getLocation ()
+  {
+    return location;
+  }
+
+  public StackTraceElement getStackTraceElement (int index)
+  {
+    return index>=0 && index<stackTrace.length ? stackTrace[index] : null;
+  }
+  
+  public StackTraceElement [] getStackTraceElements ()
+  {
+    return stackTrace;
+  }
+  
+  
+  public String getLocationAsString ()
+  {
+    return String.format("at %s.%s(%s:%d)",
+                         location.getClassName(), location.getMethodName(),
+                         location.getFileName(), location.getLineNumber());
+  }
+
+
+  public String getStackTraceElementAsString (int index)
+  {
+    StackTraceElement e = stackTrace[index];
+    return String.format("at %s.%s(%s:%d)",
+                         e.getClassName(), e.getMethodName(),
+                         e.getFileName(), e.getLineNumber());
+  }
+    
+  public boolean isCallStackEmpty ()
+  {
+    return stackTrace==null || stackTrace.length==0;
+  }
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogConfigRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogConfigRecord.java
new file mode 100644 (file)
index 0000000..d6c4dbc
--- /dev/null
@@ -0,0 +1,45 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogConfigRecord extends ExtendedLogRecord
+{
+  LogConfigRecord (String msg)
+  {
+    super(Level.CONFIG, msg, 2);
+  }
+  
+  LogConfigRecord (String msg, Throwable th)
+  {
+    super(Level.CONFIG, msg, 2);
+    setThrown(th);
+  }
+
+  LogConfigRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.CONFIG, msg, locationStackTraceIndex);
+  }
+  
+  LogConfigRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.CONFIG, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogConfigRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.CONFIG, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogConfigRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.CONFIG, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }  
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogDebugRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogDebugRecord.java
new file mode 100644 (file)
index 0000000..769f529
--- /dev/null
@@ -0,0 +1,44 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogDebugRecord extends ExtendedLogRecord
+{
+  LogDebugRecord (Level level, String msg)
+  {
+    super(level, msg, 2);
+  }
+  
+  LogDebugRecord (Level level, String msg, Throwable th)
+  {
+    super(level, msg, 2);
+    setThrown(th);
+  }
+
+  LogDebugRecord (Level level, String msg, int locationStackTraceIndex)
+  {
+    super(level, msg, locationStackTraceIndex);
+  }
+  
+  LogDebugRecord (Level level, String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(level, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogDebugRecord (Level level, String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(level, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogDebugRecord (Level level, String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(level, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }    
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFineRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFineRecord.java
new file mode 100644 (file)
index 0000000..4eca8a5
--- /dev/null
@@ -0,0 +1,43 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogFineRecord extends ExtendedLogRecord
+{
+  public LogFineRecord (String msg)
+  {
+    super(Level.FINE, msg, 2);
+  }
+  
+  public LogFineRecord (String msg, Throwable th)
+  {
+    super(Level.FINE, msg, 2);
+    setThrown(th);
+  }
+  
+  LogFineRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.FINE, msg, locationStackTraceIndex);
+  }
+
+  LogFineRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.FINE, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+
+  LogFineRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINE, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogFineRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINE, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinerRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinerRecord.java
new file mode 100644 (file)
index 0000000..06ea2d4
--- /dev/null
@@ -0,0 +1,44 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogFinerRecord extends ExtendedLogRecord
+{
+  public LogFinerRecord (String msg)
+  {
+    super(Level.FINER, msg, 2);
+  }
+  
+  public LogFinerRecord (String msg, Throwable th)
+  {
+    super(Level.FINER, msg, 2);
+    setThrown(th);
+  }
+
+  LogFinerRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.FINER, msg, locationStackTraceIndex);
+  }
+  
+  LogFinerRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.FINER, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogFinerRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINER, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogFinerRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINER, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }  
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinestRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogFinestRecord.java
new file mode 100644 (file)
index 0000000..11f1c4b
--- /dev/null
@@ -0,0 +1,45 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogFinestRecord extends ExtendedLogRecord
+{
+  public LogFinestRecord (String msg)
+  {
+    super(Level.FINEST, msg, 2);
+  }
+  
+  public LogFinestRecord (String msg, Throwable th)
+  {
+    super(Level.FINEST, msg, 2);
+    setThrown(th);
+  }
+  
+  LogFinestRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.FINEST, msg, locationStackTraceIndex);
+  }
+  
+  LogFinestRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.FINEST, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogFinestRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINEST, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogFinestRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.FINEST, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }  
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogInfoRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogInfoRecord.java
new file mode 100644 (file)
index 0000000..43189bc
--- /dev/null
@@ -0,0 +1,44 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogInfoRecord extends ExtendedLogRecord
+{
+  LogInfoRecord (String msg)
+  {
+    super(Level.INFO, msg, 2);
+  }
+  
+  LogInfoRecord (String msg, Throwable th)
+  {
+    super(Level.INFO, msg, 2);
+    setThrown(th);
+  }
+
+  LogInfoRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.INFO, msg, locationStackTraceIndex);
+  }
+  
+  LogInfoRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.INFO, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogInfoRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.INFO, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogInfoRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.INFO, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }    
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogSevereRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogSevereRecord.java
new file mode 100644 (file)
index 0000000..7cf4c30
--- /dev/null
@@ -0,0 +1,43 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogSevereRecord extends ExtendedLogRecord
+{
+  public LogSevereRecord (String msg)
+  {
+    super(Level.SEVERE, msg, 2);
+  }
+  
+  public LogSevereRecord (String msg, Throwable th)
+  {
+    super(Level.SEVERE, msg, 2);
+    setThrown(th);
+  }
+
+  LogSevereRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.SEVERE, msg, locationStackTraceIndex);
+  }
+  
+  LogSevereRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.SEVERE, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+
+  LogSevereRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.SEVERE, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogSevereRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.SEVERE, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }    
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogStackHandler.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogStackHandler.java
new file mode 100644 (file)
index 0000000..27de2ed
--- /dev/null
@@ -0,0 +1,126 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogStackHandler extends Handler
+{
+  private static LogStackHandler instance;
+  
+  public synchronized static LogStackHandler getInstance()
+  {
+    if (instance == null)
+      instance = new LogStackHandler();
+    return instance;
+  }
+
+  // ******************************************************************************
+  
+  private final LinkedList<LogRecord> recordList = new LinkedList<>();
+  
+  private LogStackHandler ()
+  {
+  }
+  
+  public synchronized void clear ()
+  {
+    recordList.clear();
+  }
+  
+  @Override
+  public synchronized void publish (LogRecord record)
+  {
+    if (record.getLevel().intValue() >= getLevel().intValue())
+      recordList.add(record);
+  }
+  
+  @Override
+  public void close () throws SecurityException
+  {
+    recordList.clear();
+  }
+
+  @Override
+  public void flush ()
+  {
+  }
+
+  public synchronized String getLogRecordsAsString ()
+  {
+    StringBuilder sb = new StringBuilder();
+    
+    sb.append(at.htlkaindorf.sx.EasyProgrammer.gui.DialogAbout.version).append("\n\n");
+    sb.append(String.format("Logging: %d records available:\n\n", recordList.size()));
+    String f = String.format("%%d: ", Math.max(1, Math.log(recordList.size()+1)));
+    for (int i=0; i<recordList.size(); i++)
+    {
+      LogRecord record = recordList.get(i);
+      int l1 = Level.INFO.intValue();
+      int l2 = record.getLevel().intValue();
+      sb.append(String.format(f, i+1, record.getLevel().intValue() <= Level.INFO.intValue() ? " " : "--- ERROR ---"));
+      String s = String.format("%1$-7s%2$c%3$tT.%3$tL: ", record.getLevel().getName(), (record instanceof LogDebugRecord ? '*' : ' '), new Date(record.getMillis())); 
+      sb.append(s);
+      int len = s.length();
+
+      if (record.getMessage() != null)
+      {
+        sb.append(record.getMessage());
+        len += record.getMessage().length();
+      }
+    
+      Throwable th = record.getThrown();
+      //if (th==null && record instanceof ExtendedLogRecord)
+      if (record instanceof ExtendedLogRecord)
+      {
+        ExtendedLogRecord elr = (ExtendedLogRecord)record;
+        StackTraceElement location = elr.getLocation();
+        sb.append(" [");
+        sb.append(elr.getLocationAsString());
+        sb.append("]");
+        if (!elr.isCallStackEmpty())
+        {
+          String format = String.format("%%%dd -> [%%s]", len-3);
+          for (int j=0; j<elr.getStackTraceElements().length; j++)
+          {
+            sb.append("\n");
+            sb.append(String.format(format, j+1, elr.getStackTraceElementAsString(j)));
+          }
+        }
+      }
+    
+
+      sb.append("\n");
+      if (th != null)
+      {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        th.printStackTrace(ps);
+        sb.append(baos.toString());
+        sb.append("================================================================================\n");
+      }
+    }
+    
+    return sb.toString();
+  }
+
+  public synchronized boolean isEmpty ()
+  {
+    return recordList.isEmpty();
+  }
+
+  public synchronized int size ()
+  {
+    return recordList.size();
+  }
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWarningRecord.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWarningRecord.java
new file mode 100644 (file)
index 0000000..f9c0dd1
--- /dev/null
@@ -0,0 +1,43 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.logging.Level;
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogWarningRecord extends ExtendedLogRecord
+{
+  public LogWarningRecord (String msg)
+  {
+    super(Level.WARNING, msg, 2);
+  }
+  
+  public LogWarningRecord (String msg, Throwable th)
+  {
+    super(Level.WARNING, msg, 2);
+    setThrown(th);
+  }
+
+  LogWarningRecord (String msg, int locationStackTraceIndex)
+  {
+    super(Level.WARNING, msg, locationStackTraceIndex);
+  }
+  
+  LogWarningRecord (String msg, Throwable th, int locationStackTraceIndex)
+  {
+    super(Level.WARNING, msg, locationStackTraceIndex);
+    setThrown(th);
+  }
+  
+  LogWarningRecord (String msg, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.WARNING, msg, locationStackTraceIndex, locationStackTraceDepth);
+  }
+
+  LogWarningRecord (String msg, Throwable th, int locationStackTraceIndex, int locationStackTraceDepth)
+  {
+    super(Level.WARNING, msg, locationStackTraceIndex, locationStackTraceDepth);
+    setThrown(th);
+  }  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWriterHandler.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/LogWriterHandler.java
new file mode 100644 (file)
index 0000000..c5a0bf5
--- /dev/null
@@ -0,0 +1,143 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class LogWriterHandler extends Handler
+{
+  private final PrintWriter out;
+  private final PrintWriter err;
+  private final PrintStream outStream;
+  private final PrintStream errStream;
+
+  public LogWriterHandler (PrintWriter out, PrintWriter err)
+  {
+    if (out == null || err == null)
+      throw new NullPointerException();
+    this.out = out;    
+    this.err = err;
+    this.outStream = null;
+    this.errStream = null;
+  }
+
+  public LogWriterHandler (PrintStream out, PrintStream err)
+  {
+    if (out == null || err == null)
+      throw new NullPointerException();
+    this.outStream = out;
+    this.errStream = err;
+    this.out = new PrintWriter(out);
+    this.err = new PrintWriter(err);
+  }
+  
+  @Override
+  public void publish (LogRecord record)
+  {
+    if (record.getLevel().intValue() < getLevel().intValue())
+      return;
+      
+    int l1 = Level.INFO.intValue();
+    int l2 = record.getLevel().intValue();
+
+    PrintWriter pw = record.getLevel().intValue() <= Level.INFO.intValue() ? out : err;
+    String s = String.format("%1$-7s%2$c%3$tT.%3$tL: ", record.getLevel().getName(), (record instanceof LogDebugRecord ? '*' : ' '), new Date(record.getMillis())); 
+    pw.print(s);
+    int len = s.length();
+
+    if (record.getMessage() != null)
+    {
+      String msg = record.getMessage();
+      for (int i=0; i<msg.length(); i++)
+      {
+        char c = msg.charAt(i);
+        int x = (int)c;
+        if (Character.isISOControl(c))
+        {
+          pw.print("<");
+          pw.print(String.format("%02x", (int)c));
+          pw.print(">");
+          len +=4;
+        }
+        else
+        {
+          pw.print(c);
+          len++;
+        }
+      }
+    }
+    
+    Throwable th = record.getThrown();
+    //if (th==null && record instanceof ExtendedLogRecord)
+    if (record instanceof ExtendedLogRecord)
+    {
+      ExtendedLogRecord elr = (ExtendedLogRecord)record;
+      StackTraceElement location = elr.getLocation();
+      pw.print(" [");
+      pw.print(elr.getLocationAsString());
+      String str = elr.getLocationAsString();
+      pw.print("]");
+      if (!elr.isCallStackEmpty())
+      {
+        String format = String.format("%%%dd -> [%%s]", len-3);
+        for (int i=0; i<elr.getStackTraceElements().length; i++)
+        {
+          pw.println();
+          pw.print(String.format(format, i+1, elr.getStackTraceElementAsString(i)));
+        }
+      }
+    }
+
+    pw.println();
+    if (th != null)
+    {
+      pw.println("--------------------------------------------------------------------------------");
+      th.printStackTrace(pw);
+      pw.println("================================================================================");
+    }
+    
+    pw.flush();
+  }
+
+  @Override
+  public void flush ()
+  {
+    out.flush();
+    err.flush();
+  }
+
+  @Override
+  public void close () throws SecurityException
+  {
+    
+  }
+  
+  public PrintWriter getErrorWriter ()
+  {
+    return err;
+  }
+  
+  public PrintWriter getOutWriter ()
+  {
+    return out;
+  }
+
+    public PrintStream getErrorStream ()
+  {
+    return errStream;
+  }
+  
+  public PrintStream getOutStream ()
+  {
+    return outStream;
+  }
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/logging/Logger.java b/src/at/htlkaindorf/sx/EasyProgrammer/logging/Logger.java
new file mode 100644 (file)
index 0000000..334be4b
--- /dev/null
@@ -0,0 +1,476 @@
+package at.htlkaindorf.sx.EasyProgrammer.logging;
+
+import java.util.HashMap;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+
+/**
+ *
+ * @author Manfred Steiner (sx@htl-kaindorf.ac.at)
+ */
+public class Logger 
+{  
+  private static final HashMap<String,Logger> loggerMap = new HashMap<>();
+  private static Logger parentLogger;
+  
+  public static synchronized Logger getLogger (String name)
+  {
+    Logger logger = loggerMap.get(name);
+    if (logger == null)
+    {
+      logger = new Logger(name);
+      if (parentLogger != null)
+      {
+        logger.setParent(parentLogger);
+        logger.setUseParentHandlers(true);
+      }
+      loggerMap.put(name, logger);
+    }
+    return logger;
+  }
+  
+  public static synchronized Logger getLogger (String name, Logger parent)
+  {
+    Logger logger = loggerMap.get(name);
+    if (logger == null)
+    {
+      logger = new Logger(name);
+      logger.setParent(parent);
+      loggerMap.put(name, logger);
+    }
+    return logger;
+  }
+  
+  public static synchronized void setParentLogger (Logger logger)
+  {
+    parentLogger = logger;
+    for (Logger l : loggerMap.values())
+    {
+      if (l != logger)
+      {
+        l.setParent(logger);
+        l.setUseParentHandlers(true);
+      }
+    }
+  }
+  
+  // *********************************************************
+  
+  protected final java.util.logging.Logger logger;
+  protected boolean locationShown = true;
+  protected Level debugLevel = Level.INFO;
+  
+  private  Logger (String name)
+  {
+    logger = java.util.logging.Logger.getLogger(name);
+  }
+  
+  
+  /**
+   * Readjusting the logging level of this logger.
+   * The level is adjusted to the logging level of the parent and the registered handlers.
+   * If no handler is registered and no parent is active, the level is set to Level.OFF
+   */
+  public synchronized void updateEffectiveLevel ()
+  {
+    int levelValue = Level.OFF.intValue();
+    
+    if (logger.getUseParentHandlers() && getParent()!=null)
+      levelValue = getParent().getLevel().intValue();
+      
+    for (Handler h : getHandlers())
+      levelValue = Math.min(levelValue, h.getLevel().intValue());
+    
+    if (levelValue>=Level.OFF.intValue())
+      setLevel(Level.OFF);
+    else if (levelValue>=Level.SEVERE.intValue())
+      setLevel(Level.SEVERE);
+    else if (levelValue>=Level.WARNING.intValue())
+      setLevel(Level.WARNING);
+    else if (levelValue>=Level.INFO.intValue())
+      setLevel(Level.INFO);
+    else if (levelValue>=Level.CONFIG.intValue())
+      setLevel(Level.CONFIG);
+    else if (levelValue>=Level.FINE.intValue())
+      setLevel(Level.FINE);
+    else if (levelValue>=Level.FINER.intValue())
+      setLevel(Level.FINER);
+    else if (levelValue>=Level.FINEST.intValue())
+      setLevel(Level.FINEST);
+    else 
+      setLevel(Level.ALL);
+  }
+  
+  public synchronized void setLocationShown (boolean showLocation)
+  {
+    this.locationShown = showLocation;
+  }
+
+  public boolean isLocationShown ()
+  {
+    return locationShown;
+  }
+  
+  public java.util.logging.Logger getParent ()
+  {
+    return logger.getParent();
+  }
+
+  public void setParent (Logger parent)
+  {
+    logger.setParent(parent.logger);
+  }
+  
+  public void setUseParentHandlers (boolean useParentHandlers)
+  {
+    logger.setUseParentHandlers(useParentHandlers);
+  }
+
+  public boolean getUseParentHandlers ()
+  {
+    return logger.getUseParentHandlers();
+  }
+  
+  public void addHandler (Handler handler)
+  {
+    logger.addHandler(handler);
+    updateEffectiveLevel();
+  }
+  
+  public java.util.logging.Handler [] getHandlers ()
+  {
+    return logger.getHandlers();
+  }
+
+  public void removeHandler (java.util.logging.Handler handler)
+  {
+    logger.removeHandler(handler);
+  }
+  
+  
+  public void setLevel (Level level)
+  {
+    logger.setLevel(level);
+  }
+  
+  public void setLevel (String level)
+  {
+    switch (level)
+    {
+      case "ALL":     logger.setLevel(Level.ALL); break;
+      case "FINEST":  logger.setLevel(Level.FINEST); break;
+      case "FINER":   logger.setLevel(Level.FINER); break;
+      case "FINE":    logger.setLevel(Level.FINE); break;
+      case "CONFIG":  logger.setLevel(Level.CONFIG); break;
+      case "INFO":    logger.setLevel(Level.INFO); break;
+      case "WARNING": logger.setLevel(Level.WARNING); break;
+      case "SEVERE":  logger.setLevel(Level.SEVERE); break;
+      case "OFF":     logger.setLevel(Level.OFF); break;
+      default:
+        int l = Integer.parseInt(level);
+        logger.setLevel(new SpecialLevel("Level " + l, l));
+        break;
+    }
+  }
+
+  public Level getLevel ()
+  {
+    Level rv = logger.getLevel();
+    if (rv == null && logger.getParent() != null)
+      rv = logger.getParent().getLevel();
+    return rv;
+  }
+
+  public boolean isLoggable (Level level)
+  {
+    return logger.isLoggable(level);
+  }
+  
+  public boolean isFinestLogged ()
+  {
+    return logger.isLoggable(Level.FINEST);
+  }
+
+  public boolean isFinerLogged ()
+  {
+    return logger.isLoggable(Level.FINER);
+  }
+
+  public boolean isFineLogged ()
+  {
+    return logger.isLoggable(Level.FINE);
+  }
+
+  public boolean isConfigLogged ()
+  {
+    return logger.isLoggable(Level.CONFIG);
+  }
+
+  public boolean isInfoLogged ()
+  {
+    return logger.isLoggable(Level.INFO);
+  }
+
+  public boolean isWarningLogged ()
+  {
+    return logger.isLoggable(Level.WARNING);
+  }
+
+  public boolean isSevereLogged ()
+  {
+    return logger.isLoggable(Level.SEVERE);
+  }
+
+
+  public void log (Level l, String msg, Throwable th)
+  {
+    if (locationShown)
+    {
+      if      (l.intValue()>=Level.SEVERE.intValue()) logger.log(new LogSevereRecord(msg, th, 3));
+      else if (l.intValue()>=Level.WARNING.intValue()) logger.log(new LogWarningRecord(msg, th, 3));
+      else if (l.intValue()>=Level.INFO.intValue()) logger.log(new LogInfoRecord(msg, th, 3));
+      else if (l.intValue()>=Level.CONFIG.intValue()) logger.log(new LogConfigRecord(msg, th, 3));
+      else if (l.intValue()>=Level.FINE.intValue()) logger.log(new LogFineRecord(msg, th, 3));
+      else if (l.intValue()>=Level.FINER.intValue()) logger.log(new LogFinerRecord(msg, th, 3));
+      else if (l.intValue()>=Level.FINEST.intValue()) logger.log(new LogFinestRecord(msg, th, 3));
+    }
+    else
+    {
+      logger.log(l, msg, th);
+    }
+  }
+  
+  
+  public void log (Level l, String msg)
+  {
+    if (locationShown)
+    {
+      if      (l.intValue()>=Level.SEVERE.intValue()) logger.log(new LogSevereRecord(msg, 3));
+      else if (l.intValue()>=Level.WARNING.intValue()) logger.log(new LogWarningRecord(msg, 3));
+      else if (l.intValue()>=Level.INFO.intValue()) logger.log(new LogInfoRecord(msg, 3));
+      else if (l.intValue()>=Level.CONFIG.intValue()) logger.log(new LogConfigRecord(msg, 3));
+      else if (l.intValue()>=Level.FINE.intValue()) logger.log(new LogFineRecord(msg, 3));
+      else if (l.intValue()>=Level.FINER.intValue()) logger.log(new LogFinerRecord(msg, 3));
+      else if (l.intValue()>=Level.FINEST.intValue()) logger.log(new LogFinestRecord(msg, 3));
+    }
+    else
+    {
+      logger.log(l, msg);
+    }
+  }
+    
+  
+  public class SpecialLevel extends Level
+  {
+    public SpecialLevel (String name, int level)
+    {
+      super(name, level);
+    }
+  }
+
+  
+  public void log (LogRecord record)
+  {
+    logger.log(record);    
+  }
+  
+
+  public void finest (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogFinestRecord(msg, 3));
+    else
+      logger.finest(msg);
+  }
+
+  public void finest (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogFinestRecord(msg, th, 3));
+    else
+      logger.log(Level.FINEST, msg, th);
+  }
+
+  public void finer (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogFinerRecord(msg, 3));
+    else
+      logger.finer(msg);
+  }
+
+  public void finer (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogFinerRecord(msg, th, 3));
+    else
+      logger.log(Level.FINER, msg, th);
+  }
+
+  public void fine (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogFineRecord(msg, 3));
+    else
+      logger.fine(msg);
+  }
+
+  public void fine (String msg, int stackTraceDepth)
+  {
+    if (locationShown)
+      logger.log(new LogFineRecord(msg, 3, stackTraceDepth));
+    else
+      logger.fine(msg);
+  }
+  
+  public void fine (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogFineRecord(msg, th, 3));
+    else
+      logger.log(Level.FINE, msg, th);
+  }  
+
+  public void config (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogConfigRecord(msg, 3));
+    else
+      logger.config(msg);
+  }
+  
+  public void config (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogFineRecord(msg, th, 3));
+    else
+      logger.log(Level.CONFIG, msg, th);
+  }  
+  
+  public void info (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogInfoRecord(msg, 3));
+    else
+      logger.info(msg);
+  }
+
+  public void info (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogInfoRecord(msg, th, 3));
+    else
+      logger.log(Level.INFO, msg, th);
+  }
+  
+  public void warning (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogWarningRecord(msg, 3));
+    else
+      logger.warning(msg);
+  }
+
+  public void warning (Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogWarningRecord(null, th, 3));
+    else
+      logger.log(Level.WARNING, null, th);
+  }
+  
+  public void warning (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogWarningRecord(msg, th, 3));
+    else
+      logger.log(Level.WARNING, msg, th);
+  }
+  
+  public void severe (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogSevereRecord(msg, 3));
+    else
+      logger.severe(msg);
+  }
+
+  public void severe (Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogSevereRecord(null, th, 3));
+    else
+      logger.log(Level.SEVERE, null, th);
+  }
+  
+  public void severe (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogSevereRecord(msg, th, 3));
+    else
+      logger.log(Level.SEVERE, msg, th);
+  }
+
+  public void debug (String msg)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, msg, 3));
+    else
+      logger.log(new LogRecord(debugLevel, msg));
+  }
+
+  public void debug (String msg, int stackTraceDepth)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, msg, 3, stackTraceDepth));
+    else
+      logger.log(new LogRecord(debugLevel, msg));
+  }
+  
+  public void debug (Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, null, th, 3));
+    else
+    {
+      LogRecord r = new LogRecord(debugLevel, null);
+      r.setThrown(th);
+      logger.log(r);
+    }
+  }
+  
+  public void debug (Throwable th, int stackTraceDepth)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, null, 3, stackTraceDepth));
+    else
+      logger.log(new LogRecord(debugLevel, null));
+  }
+  
+  public void debug (String msg, Throwable th)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, msg, th, 3));
+    else
+    {
+      LogRecord r = new LogRecord(debugLevel, msg);
+      r.setThrown(th);
+      logger.log(r);
+    }
+  }
+  
+  public void debug (String msg, Throwable th, int stackTraceDepth)
+  {
+    if (locationShown)
+      logger.log(new LogDebugRecord(debugLevel, msg, th, 3, stackTraceDepth));
+    else
+    {
+      LogRecord r = new LogRecord(debugLevel, msg);
+      r.setThrown(th);
+      logger.log(r);
+    }
+  }
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/manpage/easyprogrammer.1 b/src/at/htlkaindorf/sx/EasyProgrammer/manpage/easyprogrammer.1
new file mode 100644 (file)
index 0000000..80fa2fe
--- /dev/null
@@ -0,0 +1,66 @@
+.TH easyprogrammer 1 "March 03, 2016" "" "easyprogrammer"
+
+.SH NAME
+easyprogrammer \- Terminal/Hexfile-Download Programm for Atmel Atmega microcontrollers with HTL Bootloader
+
+.SH SYNOPSIS
+.B easyprogrammer
+.RI [ options ]
+.br
+
+.SH DESCRIPTION
+Diese man-Page beschreibt die zu Verfügung stehenden Optionen der unter Java laufenden GUI-Applikation
+.B easyprogrammer
+Beim Start des Programmes stehen verschiedene Startoptionen zur Verfügung.
+.PP
+\fBeasyprogrammer\fP erlaubt den Reset des Zielsystems mittels einstellbarer Kommandosequenz, den Download eines uC-Programmes (in Form eines Intel Hex-File), sowie die Kommunikation mit dem Zielsystem mit Hilfe eines Terminals. 
+.PP
+In der Programmdatei (dem java-Archiv \fBeasyprogrammer.jar\fP) sind auch die Hex-Dateien der Bootloader enthalten.
+
+.SH OPTIONS
+.B
+.IP "-h  oder  --help"
+Alle verfügbaren Optionen werden ausgegeben.
+.B
+.IP "-v  oder  --version"
+Aktuelle Software Version wird ausgegeben.
+.B
+.IP "-b  oder  --batch"
+Easyprogrammer wird im Batch Modus (ohne GUI Interface) gestartet.
+.B
+.IP "-i  <interface-name>  oder  --interface <interface-name>"
+Gewünschtes Interface, zB  "-i /dev/ttyUSB0" oder "/dev/ttyUSB0:57600/8N1"
+.B
+.IP "-n  <name1,name2, ...> oder  --interface-names <name1,name2, ...>"
+Interface Namen die in der Auswahl bereitgestellt werden.
+.B
+.IP "-d  <directory-name> oder  --directory <directory-name>"
+Verzeichnis-Pfad zu den Hex-Programmdateien.
+.B
+.IP "-f  <filename>  oder  --hexfile <filename>"
+Name der Hex-Programmdatei. Kann auch mit vollstaendigem Dateipfad sein.
+.B
+.IP "-r oder  --noreset"
+Die Funktion "Reset Target vor Download" wird deaktiviert
+.B
+.IP "-C <reset-command>  oder  --resetcmd <reset-command>"
+Anstelle '@R' wird der angegebene String als Reset-Kommando verwendet.
+.B
+.IP "-R <reset-sequence>  oder  --resetseq <reset-sequence>"
+Anstelle '@rR<CR><LF>' werden nur die angegeben zeichen ohne Zeilenvorschub gesendet.
+.B
+.IP "-c  oder  --nocheck"
+Antwort des Zielsystems wird nach dem Download nicht überprüft.
+.B
+.IP "-t <uC>  oder  --target <uC>"
+Typ des µC angeben. Gültige Werte für <uC> sind: atmega8l, atmega16, atmega328p
+.B
+.IP "-p  <portnr> oder  --port <portnr>"
+easyprogrammer startet auch als Serverdienst mit dem angegeben Port.
+.B
+.IP "-w  <time in ms> oder  --wait <time in ms>"
+Zeit in Millisekunden die auf den Bootloader gewartet wird.
+.IP "-l  <loglevel> oder  --loglevel <loglevel>"
+loglevel: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST oder ALL
+.SH AUTHOR
+Manfred Steiner <sx@htl-kaindorf.ac.at>
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/DebugOutputStream.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/DebugOutputStream.java
new file mode 100644 (file)
index 0000000..722ad31
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+/**
+ *
+ * @author steiner
+ */
+public class DebugOutputStream extends FilterOutputStream
+{
+  ArrayList<int []> mem;
+  int [] page;
+  int pos;
+  
+  public DebugOutputStream(OutputStream out)
+  {
+    super(out);
+    mem = new ArrayList<int []>();
+    page = new int [8192];
+    pos = 0;
+  }
+
+
+  @Override
+  public void close() throws IOException
+  {
+    super.close();
+  }
+
+
+  @Override
+  public void flush() throws IOException
+  {
+    super.flush();
+  }
+
+
+  @Override
+  public void write(int b) throws IOException
+  {
+    super.write(b);
+    page[pos++] = b;
+    if (pos>=page.length)
+    {
+      mem.add(page);
+      page = new int [8192];
+      pos = 0;
+    }
+  }
+
+
+  @Override
+  public void write(byte[] b) throws IOException
+  {
+    super.write(b);
+/*
+    for (int i=0; i<b.length; i++)
+    {
+      page[pos++] = b[i];
+      if (pos>=page.length)
+      {
+        mem.add(page);
+        page = new int [8192];
+        pos = 0;
+      }
+    }
+    if (pos>132)
+      System.out.println("Error?");
+  */
+  }
+
+
+  @Override
+  public void write(byte[] b, int off, int len) throws IOException
+  {
+    super.write(b, off, len);
+
+    /*
+    for (int i=off; i<b.length && i<(off+len); i++)
+    {
+      page[pos++] = b[i];
+      if (pos>=page.length)
+      {
+        mem.add(page);
+        page = new int [8192];
+        pos = 0;
+      }
+    }
+     */
+
+  }
+
+  
+  public int length ()
+  {
+    return mem.size()*8129 + pos;
+  }
+
+  int elementAt (int index) throws IndexOutOfBoundsException
+  {
+    int p = index / 8192;
+    int i = index % 8192;
+
+    if (p<mem.size())
+      return mem.get(p)[i];
+
+    if (p==mem.size())
+      return page[i];
+
+    throw new IndexOutOfBoundsException();
+  }
+
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder(128);
+    sb.append(this.getClass().getCanonicalName());
+    sb.append("[");
+    sb.append("mem="); sb.append(mem);
+    sb.append(", page="); sb.append(page);
+    sb.append(", pos="); sb.append(pos);
+    sb.append("]");
+
+    for (int i=0; i<this.length(); i++)
+    {
+      if (i%16 == 0)
+        sb.append(String.format("\n %04X: ", i));
+      int x = this.elementAt(i);
+      if (x<-128 || x>127)
+        sb.append(" --");
+      else
+      {
+        if (x<0) x +=256;
+        sb.append(String.format(" %02X", x));
+      }
+      if (i%4==3)
+        sb.append(" ");
+      if (i%16==15)
+      {
+        sb.append("   ");
+        for (int j=i-15; j<=i; j++)
+        {
+          x = this.elementAt(j);
+          if (x<32 || x>126)
+            sb.append(".");
+          else
+            sb.append((char)x);
+          if (j%4==3)
+            sb.append(" ");
+        }
+      }
+    }
+    sb.append("\n");
+
+    return sb.toString();
+  }
+
+
+
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadFile.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadFile.java
new file mode 100644 (file)
index 0000000..34bc426
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.data.ProgramFile;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.util.Iterator;
+
+// Download protocol
+// starte Bootloader -> ..... kommt
+// sende "@m02@f128P" + <LF> -> Antwort: <CR><LF>f>
+// sende "Pxx<Byte 0><Byte 1> ... <Byte 127>" wobei xx = Pagenummer in hex
+// Antwort: "=<xx> <ChkSum> <Error> <Error-Code><CR><LF>f>" zB: =00 27 00 00<CR><LF>f>
+// Nun fuer alle Pages den Vorgang wiederholen
+// anschliessend "FFF" senden, dadurch wird der Bootloader beendet und die Applikation gestartet
+
+/**
+ *
+ * @author alle
+ */
+public class DownloadFile
+{
+
+  private static final Logger LOG = Logger.getLogger(DownloadFile.class.getName());
+  
+  private long startTime;
+  private boolean startCmdSent;
+  private boolean downloadDone;
+  private boolean noSystemResponseCheck;
+  private jssc.SerialPort serialPort;
+  private SerialPortInfo serialPortInfo;
+  private ProgramFile programFile;
+  private BufferedOutputStream outStream;
+  private BufferedInputStream inStream;
+  
+  
+  
+
+
+  public DownloadFile (SerialPortInfo serialPortInfo, ProgramFile programFile)
+  {
+    this.serialPortInfo = serialPortInfo;
+    this.programFile = programFile;
+  }
+
+  
+  public void open () throws Exception
+  {
+    jssc.SerialPort serialPort = new jssc.SerialPort(serialPortInfo.getName());
+    if (!serialPort.openPort())
+      throw new Exception("cannot open serial port " + serialPortInfo.getName());
+
+    try
+    {
+      serialPortInfo.setJSSCSerialPortParams(serialPort);
+    }
+    catch (Exception ex)
+    {
+      close(); 
+    }
+  }
+  
+  
+  public void close () throws Exception
+  {
+    if (serialPort != null && serialPort.isOpened())
+    {
+      try
+      {
+        if (!serialPort.closePort())
+          throw new Exception("serial port close error");
+      }
+      catch (Exception ex)
+      {
+        LOG.warning(ex);
+      }
+    }
+    serialPort = null;
+  }
+
+  
+  public void start ()
+  {
+    startTime = System.currentTimeMillis();
+  }
+  
+  private String getStatus (String status)
+  {
+    StringBuilder sb = new StringBuilder(status.length() + 16);
+    sb.append(String.format("  [%5dms] ", System.currentTimeMillis() - startTime));
+    for (int i=0; i<status.length(); i++)
+    {
+      char c = status.charAt(i);
+      switch (c)
+      {
+        case '\n': sb.append("\\n"); break;
+        case '\r': sb.append("\\r"); break;
+        default:
+          sb.append(c>=32 && c<127 ? c : '.');
+      }
+      
+    }
+    return sb.toString();
+  }
+
+  
+  private char getPrintableChar(int value)
+  {
+    if (value<32 || value>'~') return ('.');
+    return (char)value;
+  }
+  
+  
+  public void waitOnBootloader (int ms, boolean sendCmdStart) throws Exception
+  {
+    int len=0;
+    StringBuilder response = new StringBuilder(256);
+    startCmdSent = false;
+    
+    if (serialPort == null || inStream==null || outStream==null)
+      throw new RuntimeException ("waitOnBootloader Problem");
+    System.out.println(getStatus("wait on Bootloader response "));  
+    
+    long timeout = System.nanoTime() + ((long)ms)*1000000;
+    
+    //setReceiveTimeOut(100);    
+    while (inStream.available()>0)
+      inStream.read();
+
+    while (System.nanoTime()<timeout)
+    {
+      try 
+      {
+        int c = inStream.read();
+        if (c>=0) 
+        {
+          response.append((char)c);
+          System.out.print(getPrintableChar(c));
+          if (++len==80)
+          {
+            System.out.print("\r");
+            len = 0;
+          }
+        }
+        
+        long t0 = System.nanoTime();
+        if (c<0 || ((char)c)!='.')
+          continue;
+        c = inStream.read();
+        long t1 = System.nanoTime();
+        if (c<0 || ((char)c)!='.')
+          continue;
+        long dt = (t1-t0)/1000000;
+        if (dt>30 && dt<80)
+        {
+          if (sendCmdStart)
+          {
+            //outStream.write(programFile.getBootloaderStartCmd().getBytes());
+            outStream.write('@');
+            outStream.flush();
+            Thread.sleep(100);
+            c = -1;
+            while(inStream.available()>0)
+            {
+              c = inStream.read();
+              if (c=='@') break;
+              c = -1;
+            }
+            if (c!='@')
+              throw new Exception("error on sending @");
+            startCmdSent = true;
+          }
+          if (len>0) System.out.println("");
+          int i = response.toString().indexOf("Bootloader Version ");
+          int j = response.toString().indexOf("]");
+          if (i<0 || j<0 || (j-i)<40 || (j-i)>50)
+            System.out.println(getStatus("Bootloader detected"));
+          else
+          {
+            String version = response.substring(i, j+1);
+            System.out.println(getStatus(version + " detected"));
+          }
+          return;
+        }
+      }
+      catch (Exception ex)
+      {
+        break;        
+      }
+    }
+    if (len>0) System.out.println("");
+    System.out.println(getStatus("No Bootloader detected"));
+    throw new Exception("Bootloader not detected");
+  }
+  
+  public void resetTarget (String resetCmd) throws Exception
+  {
+    System.out.println(getStatus("Reset Target with '" + resetCmd + "'"));
+    outStream.write(resetCmd.getBytes());
+    //outStream.write('\r');
+    //outStream.write('\n');
+    outStream.flush();
+  }
+  
+  private void sendAndCheckCommand (String cmd, String check, int timeoutMillis) throws Exception
+  {
+    Thread.sleep(10);
+    while (inStream.available()>0)
+      inStream.read();
+    
+    outStream.write(cmd.getBytes());
+    outStream.flush();
+    //System.out.println("send '" + cmd + "'");
+    long timeout = System.nanoTime() + timeoutMillis*1000000;
+    StringBuilder sb = new StringBuilder(cmd.length()+16);
+    
+    if (check==null)
+    {
+      Thread.sleep(timeoutMillis);
+      return;
+    }  
+    
+    while (System.nanoTime() < timeout)
+    {
+      while (inStream.available()>0)
+      {
+        int c = inStream.read();
+        if (c>=0 && c<=255) sb.append((char)c);
+        if (sb.toString().endsWith(check))
+          return;
+      }
+      Thread.sleep(1);
+    }
+    
+//    System.out.print("response does not match ");
+//    for (int i=0; i<sb.length(); i++)
+//    {
+//      if (sb.charAt(i)>= ' ' && sb.charAt(i)<'.')
+//        System.out.print((char)sb.charAt(i));
+//      else
+//        System.out.print("<" + (int)sb.charAt(i) + ">");
+//    }  
+//    System.out.println("");
+    throw new Exception("response does not match");
+  }
+  
+  
+  public void download (boolean noSystemResponseCheck) throws Exception
+  {
+    this.noSystemResponseCheck = noSystemResponseCheck;
+    downloadDone = false;
+    programFile.setBootloaderMode(2);
+    
+    try
+    {
+      if (startCmdSent==false)
+      {
+        String cmd = programFile.getBootloaderStartCmd() + "P\n";
+        sendAndCheckCommand(cmd, "f>", 200); 
+        startCmdSent = true; 
+      }
+      else
+      {
+        String cmd = programFile.getBootloaderStartCmd().substring(1) + "P\n";
+        sendAndCheckCommand(cmd, "f>", 200);
+      }
+      
+      int pages = programFile.getMemoryPages();
+      System.out.println(getStatus(pages + " Pages werden geladen"));
+      int attempt = 1;
+      Object page = null;
+
+      // Bug in Bootloader, first response is wrong
+      // Bugfix, write first page without check, repeat later in loop
+        
+      System.out.print(getStatus("Download: "));
+      
+      for (Iterator<Object> it = programFile.iterator(); it.hasNext(); )
+      {
+        if (attempt==1)
+          page = it.next();
+        int pagenr;
+        //Thread.sleep(70);
+
+        try
+        {
+          switch(programFile.getBootloaderMode())
+          {
+            case 0: pagenr = writeAndCheckPage((String) page); break;  // character without checksum
+            case 1: pagenr = writeAndCheckPage((String) page); break;  // character with checksum
+            case 2: pagenr = writeAndCheckPage((byte []) page); break; // binary without checksum
+            case 3: pagenr = writeAndCheckPage((byte []) page); break; // binary with checksum
+            default:
+              throw new Exception("Unknown Bootloader-mode");
+          }
+          //gui.stateChanged(new ChangeEvent((pagenr*100)/pages));
+          attempt = 1;
+          System.out.print(".");
+        }
+        catch (Exception ex)
+        {
+          ex.printStackTrace(System.err);
+          System.out.print("E");
+          if (ex instanceof InterruptedException)
+            throw ex;
+          if (attempt>5)
+            throw ex;
+          attempt++;
+        }
+      }
+      downloadDone = true;
+    }
+    catch (Exception ex)
+    {
+      //if ((ex instanceof InterruptedException) == false)
+      //  gui.stateChanged(new ChangeEvent("Error:" + ex.getMessage()));
+      throw ex;
+      
+    }
+    finally
+    {
+      if (downloadDone)
+      {
+        System.out.println(" -> sucessfully done");
+        System.out.println(getStatus("Stop Download and start application"));
+      }
+      else
+      {
+        System.out.println(" -> fails");
+        System.out.println(getStatus("Stop Download and start application. Maybe will not work!"));
+      }
+      try
+      {
+        endBootloader();
+        if (!noSystemResponseCheck)
+          System.out.println(getStatus("Antwort des Zielsystems ok"));
+      }
+      catch (Exception ex)
+      {
+        System.out.println(getStatus(ex.getMessage()));
+      }
+    }   
+  }
+  
+
+  private void endBootloader () throws Exception
+  {
+    try
+    {
+      if (noSystemResponseCheck)
+        sendAndCheckCommand("FFF", null, 100);
+      else  
+        sendAndCheckCommand("FFF", ">", 100);
+    }
+    catch (Exception ex)
+    {
+      //System.out.println(ex.getMessage());
+      if (downloadDone)
+        throw new Exception("Download ok, System liefert keine Antwort");
+      else
+        throw new Exception("Error on Bootloader end command");
+    }
+
+  }
+
+  
+  
+  private int writeAndCheckPage (String s) throws Exception
+  {
+    StringBuilder pageNr = new StringBuilder(2);
+
+    pageNr.append((char)s.charAt(1));
+    pageNr.append((char)s.charAt(2));
+
+    Thread.sleep(50);
+    return Integer.valueOf(pageNr.toString(), 16);
+  }
+  
+  
+  private int writeAndCheckPage (byte [] b) throws Exception
+  {
+    StringBuilder sb = new StringBuilder(16);
+    int pos = 0;
+
+    StringBuilder pageNr = new StringBuilder(2);
+    pageNr.append((char)b[1]);
+    pageNr.append((char)b[2]);
+    int page = Integer.valueOf(pageNr.toString(), 16);
+    
+    String str = null;
+    
+    try
+    {
+      outStream.write(b);
+      outStream.flush();
+
+      //Thread.sleep(100);
+      long start = System.currentTimeMillis();
+      str = readResponseString("=?? ?? ?? ??\r\nf>", 500);
+     
+      //System.out.print("receive: " + lenInBuffer + " Bytes");
+      //System.out.println(" " + bytesToString(inputBytes, 0, pos, true));
+
+      if (str == null || str.length()==0)
+        throw new Exception("Bootloader Error (no response)");
+      else if (str.charAt(0)!='=' || str.charAt(3)!=' ' || str.charAt(6)!=' ' || str.charAt(9)!=' ' ||
+               str.charAt(12)!=13 || str.charAt(13)!=10 || str.charAt(14)!='f' || str.charAt(15)!='>')
+        throw new Exception("Bootloader Error (unexpected response)");
+      else
+      {
+        try
+        {
+          int recpage = parseValue(str, "=XX ?? ?? ????f>");
+          int chk = parseValue(str, "=?? XX ?? ????f>");
+          int errpos = parseValue(str, "=?? ?? XX ????f>");
+          int errcode = parseValue(str, "=?? ?? ?? XX??f>");
+          int chksum = 0;
+          for (int i=3; i<b.length; i++)
+            chksum = (chksum + this.toUnsignedByte(b[i])) % 256;
+          //System.out.println("ok, page=" + page + ", chk=" + chk + ", chksum=" + chksum + ", errcode=" + errcode + ", errpos=" + errpos);
+          if (recpage != page)
+            throw new Exception("Page Error (expected=" + page + "  received=" + recpage + ")");
+          if (chksum != chk)
+            throw new Exception("Checksum Error (expected=" + chksum + "  received=" + chk + ")");
+          if (errcode != 0)
+            throw new Exception("Bootloader Error (code=" + errcode + " on position " + errpos + ")");
+        }
+        catch (Exception ex)
+        {
+          throw new Exception("Download Error (unexpected response)");
+        }
+      }
+    }
+    catch (Exception ex)
+    {
+      System.out.println("");
+      System.out.println("response " + str.length() + " Bytes ");
+      byte [] ba = str.getBytes();
+      for (byte x : ba)
+        System.out.print(String.format("%02x ", x));
+      System.out.print("  ");
+      for (byte x : ba)
+        System.out.print((char)(x>=32 && x<127 ? x : '.'));
+      System.out.println("");
+              
+      //ex.printStackTrace(System.err);
+      throw ex;
+    }
+
+    //System.out.println("page " + page + " ok");
+
+    return page;
+  }
+  
+  private int parseValue (String str, String filter) throws Exception
+  {
+    int i;
+    int value = 0;
+    boolean error = false;
+
+    if (filter.length() != str.length())
+      throw new Exception("Parse error, wrong length");
+
+    for (i=0; i<str.length() && error==false; i++)
+    {
+      char c = str.charAt(i);
+      switch (filter.charAt(i))
+      {
+        case 'X':
+          c = Character.toLowerCase(c);
+          if (c >= '0' && c <= '9')
+            value = value*16+ c - '0';
+          else if (c >= 'a' && c <= 'f')
+            value = value*16+ c - 'a' + 10;
+          else
+            error = true;
+            break; //no hex digit
+
+        case '?':
+          break;
+
+        default:
+          if (str.charAt(i) != filter.charAt(i))
+            error = true;
+          break;
+      }
+    }
+
+    if (error)
+      throw new Exception("Parse error on Position " + i);
+
+    return value;
+  }
+
+  
+  private int toUnsignedByte (byte b)
+  {
+    return b<0 ? b+256 : b;
+  }
+
+  
+  private String readResponseString (String pattern, int timeoutMillis) throws Exception
+  {
+    //System.out.println(System.currentTimeMillis() + ":  readResponseString '" + pattern + "'   timeout=" + timeoutMillis);
+
+    StringBuilder sb = new StringBuilder (256);    
+    long timeout = System.nanoTime() + timeoutMillis*1000000;
+    
+    try
+    {
+      while (System.nanoTime()<timeout)
+      {
+        while (inStream.available()>0 && sb.length()<pattern.length())
+        {
+          int b = inStream.read();
+          if (b<0 || b>255) throw new Exception("Wrong char");
+          sb.append((char)b);
+        }
+        
+        if (sb.length()==pattern.length())
+        {
+          for (int i=0; i<sb.length(); i++) 
+          {
+            char c = pattern.charAt(i);
+            if (c!='?' && c!=sb.charAt(i))
+              throw new Exception("Pattern mismatch");
+          }
+          return sb.toString();
+        }
+      }
+      throw new Exception("Timeout");
+    }
+    catch (Exception ex)
+    {
+//      System.out.print("Error on Response (" + ex.getMessage() + ")");
+//      if (sb.length()==0)
+//        System.out.println(" - no bytes received");
+//      else
+//      {
+//        System.out.print("  " + sb.length() + " Bytes received: ");
+//        byte [] ba = sb.toString().getBytes();  
+//        for (int i=0; i<ba.length; i++)
+//        {
+//          System.out.print("<" + String.format("%02x", ba[i]) + "> ");
+//        }
+//        System.out.println("");
+//      }
+      throw ex;
+    }
+  }
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadProtocol.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/DownloadProtocol.java
new file mode 100644 (file)
index 0000000..7e9170d
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.data.ProgramFile;
+import at.htlkaindorf.sx.EasyProgrammer.gui.TerminalArea;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.IOException;
+import java.util.Iterator;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author steiner
+ */
+public final class DownloadProtocol extends ResetProtocol
+{
+  private static final Logger LOG = Logger.getLogger(DownloadProtocol.class.getName());
+
+  private ChangeListener gui;
+  private int recentPortSpeed;
+  
+  public DownloadProtocol (SerialInterface serialInterface, TerminalArea terminalArea)
+  {
+    super(serialInterface, terminalArea);
+    recentPortSpeed = -1;
+  }
+
+
+  @Override
+  public void dataAvailable ()
+  {
+    super.dataAvailable(); //To change body of generated methods, choose Tools | Templates.
+  }
+
+
+  
+  
+  @Override
+  public int read() throws Exception, IOException, NullPointerException
+  {
+    return super.read();
+    /*
+    int b = super.read();
+    if (b>=0)
+    {
+      System.out.print("DP read: ");
+      if (b>=32 && b<128)
+        System.out.print((char) b);
+      else
+        System.out.print(" ");
+      System.out.println("  " + b);
+    }
+    return b;
+     *
+     */
+  }
+
+
+  @Override
+  public void write(int b) throws Exception
+  {
+    /*
+    System.out.print("DP write:         ");
+    if (b>=32 && b<128)
+      System.out.print((char) b);
+    else
+      System.out.print(" ");
+    System.out.println("  " + b);
+     * 
+     */
+
+    super.write(b);
+  }
+
+
+
+
+  @SuppressWarnings("SleepWhileHoldingLock")
+  public void download (ProgramFile file, ChangeListener gui) throws Exception
+  {
+    this.gui = gui;
+    
+    int pages =file.getMemoryPages();
+    gui.stateChanged(new ChangeEvent("Bootloader detektiert, " + pages + " Pages werden geladen"));
+    LOG.info(String.format("flashing %d pages", pages));
+    try
+    {
+      String cmd = file.getBootloaderStartCmd();
+      startBootloader(cmd);
+      //System.out.println("'" + file.getBootloaderStartCmd() + "' written and checked");
+      int attempt = 1;
+      Object page = null;
+
+      for (Iterator<Object> it = file.iterator(); it.hasNext(); )
+      {
+        //System.out.println("download page (attempt " + attempt + ")");
+        if (attempt==1)
+          page = it.next();
+        int pagenr;
+        
+        try
+        {
+          switch(file.getBootloaderMode())
+          {
+            case 0: pagenr = writeAndCheckPage((String) page); break;  // character without checksum
+            case 1: pagenr = writeAndCheckPage((String) page); break;  // character with checksum
+            case 2: pagenr = writeAndCheckPage((byte []) page); break; // binary without checksum
+            case 3: pagenr = writeAndCheckPage((byte []) page); break; // binary with checksum
+            default:
+              throw new Exception("Unknown Bootloader-mode");
+          }
+          gui.stateChanged(new ChangeEvent((pagenr*100)/pages));
+          attempt = 1;
+        }
+        catch (IllegalStateException ex)
+        {
+          throw ex;
+        }
+        catch (Exception ex)
+        {
+          if (ex instanceof InterruptedException)
+            throw ex;
+          if (attempt>5)
+            throw ex;
+          attempt++;
+        }
+      }
+      if (file.getCpu().getFlashSize()/file.getCpu().getPageSize()>256)
+        endBootloader("FFFF");
+      else
+        endBootloader("FFF");
+    }
+    catch (Exception ex)
+    {
+      if ((ex instanceof InterruptedException) == false)
+        gui.stateChanged(new ChangeEvent("Error:" + ex.getMessage()));
+      LOG.warning(ex);
+      try
+      {
+        if (file.getCpu().getFlashSize()/file.getCpu().getPageSize()>256)
+          endBootloader("FFFF");
+        else
+          endBootloader("FFF");
+        throw ex;
+      }
+      catch (Exception e)
+      {
+        e.addSuppressed(ex);
+        throw e;
+      }
+    }
+    finally
+    {
+      this.disconnect();
+    }
+  }
+
+
+  private int parseValue (String str, String filter) throws Exception
+  {
+    int i;
+    int value = 0;
+    boolean error = false;
+
+    if (filter.length() != str.length())
+      throw new Exception("Parse error, wrong length");
+
+    for (i=0; i<str.length() && error==false; i++)
+    {
+      char c = str.charAt(i);
+      switch (filter.charAt(i))
+      {
+        case 'X':
+          c = Character.toLowerCase(c);
+          if (c >= '0' && c <= '9')
+            value = value*16+ c - '0';
+          else if (c >= 'a' && c <= 'f')
+            value = value*16+ c - 'a' + 10;
+          else
+            error = true;
+            break; //no hex digit
+
+        case '?':
+          break;
+
+        default:
+          if (str.charAt(i) != filter.charAt(i))
+            error = true;
+          break;
+      }
+    }
+
+    if (error)
+      throw new Exception(String.format("Parse error in '%s' on Position %d", str, i));
+    return value;
+  }
+
+
+  private int writeAndCheckPage (String s) throws Exception
+  {
+    StringBuilder pageNr = new StringBuilder(2);
+
+    pageNr.append((char)s.charAt(1));
+    pageNr.append((char)s.charAt(2));
+
+    Thread.sleep(50);
+    return Integer.valueOf(pageNr.toString(), 16);
+  }
+
+
+  private int writeAndCheckPage (byte [] b) throws Exception
+  {
+    StringBuilder sb = new StringBuilder(16);
+    int pos = 0;
+
+    int n = (int)(Math.log(b.length)/Math.log(2));
+    int headerLength = b.length - (int)Math.pow(2, n);
+    
+    StringBuilder pageNr = new StringBuilder(headerLength-1);
+    for (int i=1; i<headerLength; i++)
+      pageNr.append((char)b[i]);
+    int page = Integer.valueOf(pageNr.toString(), 16);
+
+    try
+    {
+      flush();
+      if (LOG.isFineLogged())
+        LOG.fine(String.format("writing flash page %s", pageNr));
+      write(b); // write always whole buffer, otherwise problems in virtualized systems (loss of data)
+      long start = System.currentTimeMillis();
+      if (LOG.isFinestLogged())
+        LOG.finest(String.format("done, waiting for response on flash page %s", pageNr));
+      long startTimeMillis = System.currentTimeMillis();
+      String str;
+      try
+      {
+        str = readResponseString("f>", 500);
+        if (str==null)
+          throw new Exception("readResponseString 'f>' fails");
+        long dt = System.currentTimeMillis() - startTimeMillis;
+        if (dt>100)
+          LOG.warning(String.format("unexpected delay in response (%dms)", dt));
+        else if (LOG.isFinerLogged())
+          LOG.finer(String.format("detect proper response in %dms", dt));
+          
+      }
+      catch (Exception ex)
+      {
+        long dt = System.currentTimeMillis() - startTimeMillis;
+        LOG.warning(String.format("waiting %dms, no valid response detected", dt));
+        throw new IllegalStateException("no valid response");
+      }
+     
+      //System.out.println(" " + bytesToString(inputBytes, 0, pos, true));
+
+      if (str.charAt(0)=='='
+          && str.charAt(headerLength)==' '
+          && str.charAt(headerLength+3)==' '
+          && str.charAt(headerLength+6)==' '
+          && str.charAt(headerLength+9)==13
+          && str.charAt(headerLength+10)==10
+          && str.charAt(headerLength+11)=='f'
+          && str.charAt(headerLength+12)=='>')
+      {
+        if (LOG.isFinerLogged())
+          LOG.finer(String.format("response '%s' received for flash page %s", str, pageNr));
+        try
+        {
+          StringBuilder fsb = new StringBuilder("=");
+          for (int i=0; i<headerLength-1; i++)
+            fsb.append("X");
+          int recpage = parseValue(str, fsb.toString() + " ?? ?? ????f>");
+
+          fsb.delete(1, fsb.length());
+          for (int i=0; i<headerLength-1; i++)
+            fsb.append("?");
+          
+          int chk = parseValue(str, fsb.toString() + " XX ?? ????f>");
+          int errpos = parseValue(str, fsb.toString() + " ?? XX ????f>");
+          int errcode = parseValue(str, fsb.toString() + " ?? ?? XX??f>");
+          int chksum = 0;
+          
+          for (int i=headerLength; i<b.length; i++)
+            chksum = (chksum + this.toUnsignedByte(b[i])) % 256;
+          //System.out.println("ok, page=" + page + ", chk=" + chk + ", chksum=" + chksum + ", errcode=" + errcode + ", errpos=" + errpos);
+          if (recpage != page)
+            throw new Exception("Page Error (expected=" + page + "  received=" + recpage + ")");
+          if (chksum != chk)
+            throw new Exception("Checksum Error (expected=" + chksum + "  received=" + chk + ")");
+          if (errcode != 0)
+            throw new Exception("Bootloader Error (code=" + errcode + " on position " + errpos + ")");
+        }
+        catch (Exception ex)
+        {
+          LOG.warning(ex);
+          throw new Exception("Download Error (unexpected response)", ex);
+        }
+      }
+      else if (str.length()==0)
+        throw new Exception("Bootloader Error (no response)");
+      else
+        throw new Exception(String.format("Bootloader Error (unexpected response %s for page %s)", str, pageNr));
+    }
+    catch (Exception ex)
+    {
+      throw ex;
+    }
+
+    //System.out.println("page " + page + " ok");
+
+    return page;
+  }
+
+  private void startBootloader (String cmd) throws Exception
+  {
+    byte [] response = new byte[4];
+    int pos;
+    boolean error;
+
+    flush();
+    write('@');
+    String str = readResponseString("@", 200);
+
+    if (str == null || str.endsWith("@") == false)
+      throw new Exception("Bootloader entry with '@' failed");
+
+    //System.out.println("@ detected");
+
+    StringBuilder sb = new StringBuilder(16);
+    int ucRegUBRR0L = -1;
+    for (int i=1; i<cmd.length(); i++)
+    {
+      response[0] = (byte)cmd.charAt(i);
+      //System.out.println("write " + cmd.charAt(i) + "  sb= '" + sb.toString() + "'");
+      try { writeAndCheckResponse((byte) cmd.charAt(i), response, 0, 1); }
+      catch (Exception ex)
+      {
+        throw new Exception("unexpected response while download-start");
+      }
+
+      sb.append(cmd.charAt(i));
+      if (sb.length()==4 && sb.toString().startsWith("@s"))
+      {
+        System.out.println("switch speed to " + sb);
+        ucRegUBRR0L = Integer.valueOf(sb.substring(2), 16);
+      }
+
+      if (cmd.charAt(i) == '@')
+        sb.replace(0, sb.length(), "@");
+    }
+
+    if (ucRegUBRR0L>0)
+    {
+      write(10);
+      this.recentPortSpeed = this.setSerialPortSpeed(1000000/(ucRegUBRR0L+1));
+      Thread.sleep(50);
+    }
+    else
+    {
+      response[0] = 13; response[1] = 10; response[2] = 'f'; response[3] = '>';
+      try { writeAndCheckResponse((byte)10, response, 0, 4); }
+      catch (Exception ex)
+      {
+        throw new Exception("unexpected response after download-start");
+      }
+    }
+
+    //System.out.println("Init done  " + this.bytesToString(this.inputBytes, 0, 4, true));
+  }
+
+  private void endBootloader (String endCmd) throws Exception
+  {
+    int pos;
+    boolean downloadOK = false;
+    
+    flush();
+    try
+    {
+      write(endCmd);
+      if (recentPortSpeed >= 0)
+      {
+        Thread.sleep(100);
+        this.setSerialPortSpeed(recentPortSpeed);
+        recentPortSpeed = -1;
+      }
+      String str = readResponseString("X", 300);
+
+      if (str==null)
+        throw new Exception("Error on Bootloader end command");
+
+      downloadOK = true;
+      // check now response of System
+      //str = this.readResponseString(">", 200);
+      //if (str.contains("Systemmonitor"))
+      //  terminalArea.append(str + "\n\r>");
+      terminalArea.append("\n\r");
+
+      //if (str.contains(">")) System.out.println("Download fertig");
+    }
+    catch (Exception ex)
+    {
+      //System.out.println(ex.getMessage());
+      if (downloadOK)
+        throw new Exception("Download ok, System liefert keine Antwort", ex);
+      else
+        throw ex;
+    }
+
+  }
+
+
+  @SuppressWarnings("CallToNativeMethodWhileLocked")
+  private void writeAndCheckResponse (byte send, byte [] response, int offset, int len) throws Exception
+  {
+    int pos = 0;
+
+    flush();
+    write(send);
+    String str = readResponseString(len, 200);
+    if (str != null && str.length() == len)
+      return;
+
+    throw new Exception("expect " + len + " Bytes, get " + this.available() + " Bytes");
+/*
+    try
+    {
+      
+      while (true)
+      {
+        synchronized (waitThread)
+        {
+          this.waitThread.wait(500);
+          if (lenInBuffer == pos)
+            throw new Exception("Timeout");
+          pos = lenInBuffer;
+          if (pos > len)
+          {
+            lenInBuffer = 0;
+            String t = this.bytesToString(inputBytes, offset, pos, true);
+            throw new Exception("expect " + len + " Bytes, get " + pos + " Bytes");
+          }
+          if (pos == len)
+          {
+            lenInBuffer = 0;
+            for (int i=0; i<len; i++)
+            {
+              //System.out.println("receive " + (char) inputBytes[i] + "(" + (int)inputBytes[i] + ")");
+              if (inputBytes[i] != response[offset+i])
+              {
+                StringBuilder sb = new StringBuilder(128);
+                sb.append("send ").append(send).append("(").append((int) send).append("), expect ");
+                for (int j=0; j<len; j++)
+                  sb.append(response[offset+j]);
+                sb.append("get ");
+                for (int j=0; j<pos; j++)
+                  sb.append(inputBytes[j]);
+                throw new Exception(sb.toString());
+              }
+            }
+            return;
+          }
+        } // synchronized
+
+      }
+    }
+    catch (IOException ex)
+    {
+      throw new Exception("write " + send + "(" + (int)send + ") - IOException " + ex.getMessage());
+    }
+ * */
+  }
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/Protocol.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/Protocol.java
new file mode 100644 (file)
index 0000000..517d715
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.IOException;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author Manfred Steiner
+ */
+public abstract class Protocol
+{
+
+  private static final Logger LOG = Logger.getLogger(Protocol.class.getName());
+
+  protected enum BufferTyp { NOBUFFER, FIFO, RINGBUFFER };
+
+  private boolean connected;
+  private SerialInterface serialInterface;
+  private ChangeListener gui;
+  private byte [] receiveBuffer;
+  private boolean receiveBufferFull;
+  private int receiveBufferFullCounter;
+  private int posBufRead;
+  private int posBufWrite;
+  private BufferTyp typ;
+  private boolean receiveData;
+  private final Thread waitThread;
+
+
+
+
+  public Protocol (SerialInterface serialInterface)
+  {
+    this.serialInterface = serialInterface;
+    this.waitThread = Thread.currentThread();
+    this.typ = BufferTyp.NOBUFFER;
+    this.receiveData = true;
+  }
+
+
+  public Protocol (SerialInterface serialInterface, int bufferSize, BufferTyp bufferTyp)
+  {
+    this.serialInterface = serialInterface;
+    this.waitThread = Thread.currentThread();
+    this.typ = bufferTyp;
+    this.receiveData = true;
+    if (bufferSize > 0)
+      this.receiveBuffer = new byte [bufferSize+1];
+  }
+
+
+  protected void setTyp(BufferTyp typ)
+  {
+    this.typ = typ;
+  }
+
+  
+  public void setChangeListener(ChangeListener changeListener)
+  {
+    this.gui = changeListener;
+  }
+
+
+  protected void flush ()
+  {
+    if (this.waitThread != null)
+      synchronized (this.waitThread)
+      {
+        this.posBufRead = 0;
+        this.posBufWrite = 0;
+      }
+  }
+
+
+
+  public boolean isBootloaderDetetcted ()
+  {
+    if (this.serialInterface != null)
+      return this.serialInterface.isBootloaderDetetcted();
+    return false;
+  }
+
+
+  public void waitOnBootLoaderDetected (long timeout) throws InterruptedException
+  {
+    if (this.waitThread == null)
+      return;
+    
+    long end;
+    synchronized (this.waitThread)
+    {
+      end = System.currentTimeMillis() + timeout;
+      do
+      {
+        if (isBootloaderDetetcted() == true)
+          break;
+        this.waitThread.wait(end - System.currentTimeMillis());
+      }
+      while (System.currentTimeMillis() < end);
+    }
+    //System.out.println("Bootloader detected (time=" + (System.currentTimeMillis() - end + timeout) + "ms)");
+  }
+
+  
+  protected int available ()
+  {
+    if (this.waitThread != null)
+    {
+      synchronized (this.waitThread)
+      {
+        if (this.posBufWrite >= this.posBufRead)
+          return this.posBufWrite -  this.posBufRead;
+        else
+          return this.posBufWrite + this.receiveBuffer.length - this.posBufRead;
+      }
+    }
+    throw new RuntimeException("available() only useable when buffer is used");
+  }
+
+  protected int waitOnResponse (int minBytes, long timeout) throws InterruptedException
+  {
+    if (this.waitThread == null)
+      throw new RuntimeException("waitOnResponse() only useable when buffer is used");
+
+    if (minBytes <= 0)
+      return 0;
+    
+    synchronized (this.waitThread)
+    {
+      for (;;)
+      {
+        int oldlen = (posBufWrite >= posBufRead) ? (posBufWrite - posBufRead)
+                                                 : (posBufWrite + receiveBuffer.length - posBufRead);
+        if (oldlen >= minBytes)
+          return oldlen;
+
+        this.waitThread.wait(timeout);
+        int newlen = (posBufWrite >= posBufRead) ? (posBufWrite - posBufRead)
+                                                 : (posBufWrite + receiveBuffer.length - posBufRead);
+        //System.out.println("newlen = " + newlen);
+        if (newlen == oldlen)
+          return newlen; // timeout
+      }
+    }
+  }
+
+
+  protected String readResponseString (int size, long timeout) throws InterruptedException
+  {
+    if (size>=0)
+      waitOnResponse(size, timeout);
+    return readResponseString(size);
+  }
+
+  protected int readResponseByte ()
+  {
+    int c = -1;
+    synchronized (this.waitThread)
+    {
+      if (this.posBufRead != this.posBufWrite)
+      {
+        c = (int) this.receiveBuffer[this.posBufRead++];
+        if (this.posBufRead >= receiveBuffer.length)
+        this.posBufRead = 0;
+        this.receiveBufferFull = false;
+      }
+    }
+    return c;
+  }
+
+  protected String readResponseString (int size)
+  {
+    if (this.waitThread == null)
+      throw new RuntimeException("getResponseString() only useable when buffer is used");
+
+    String str;
+    synchronized (this.waitThread)
+    {
+      if (this.available() <= 0)
+        str = null;
+      else
+      {
+        if (size<0)
+          size = this.available();
+        StringBuilder sb = new StringBuilder(size);
+        while (size>0)
+        {
+          int c = -1;
+          if (this.posBufRead != this.posBufWrite)
+          {
+            c = (int) this.receiveBuffer[this.posBufRead++];
+            if (this.posBufRead >= receiveBuffer.length)
+              this.posBufRead = 0;
+            this.receiveBufferFull = false;
+          }
+          if (c>=0)
+            sb.append((char) c);
+          size--;
+        }
+        str = sb.toString();
+        this.posBufRead = 0;
+        this.posBufWrite = 0;
+      }
+    }
+    return str;
+  }
+
+  protected int findPatternPosition (String pattern)
+  {
+    if (this.waitThread == null)
+      throw new RuntimeException("waitThread == null");
+
+    if (pattern == null || pattern.length() <= 0)
+      return -1;
+
+    int pos;
+    int i = 0;
+
+    synchronized (this.waitThread)
+    {
+      pos = this.posBufRead;
+      while (pos != this.posBufWrite && i< pattern.length())
+      {
+        if (this.receiveBuffer[pos] == pattern.charAt(i))
+        {
+          i++;
+        }
+        else
+        {
+          pos = pos - i;
+          if (pos < 0)
+            pos = pos + receiveBuffer.length;
+          i = 0;
+        }
+        pos++;
+        if (pos >= receiveBuffer.length)
+          pos = 0;
+      }
+    }
+    if (i>=pattern.length())
+    {
+      pos = pos - pattern.length();
+      if (pos < 0)
+        pos = pos + receiveBuffer.length;
+      return pos;
+    }
+    return -1;
+  }
+
+  protected String readResponseString (String pattern, long timeout) throws InterruptedException
+  {
+    if (this.waitThread == null)
+      throw new RuntimeException("waitThread == null");
+
+    int pos = -1;
+    long end = System.currentTimeMillis() + timeout;
+
+    do
+    {
+      synchronized (this.waitThread)
+      {
+        pos = findPatternPosition(pattern);
+        if (pos < 0)
+        {
+          serialInterface.addInputDetector(pattern, this.waitThread);
+          //LOG.debug(String.format("waiting for pattern '%s'", pattern), 4);
+          this.waitThread.wait(timeout);
+          StringBuilder sb = new StringBuilder();
+          try
+          {
+            for (int i=posBufRead; i!=posBufWrite; i++)
+            {
+              if (i>=receiveBuffer.length)
+                i = 0;
+              byte b = receiveBuffer[i];
+              char c = (char)b;
+              if (Character.isISOControl(c))
+                sb.append(String.format("<%02x>", b<0 ? b+256 : b));
+              else
+                sb.append(c);
+            }
+            //LOG.debug(String.format("bytes received, '%s' in buffer, continue checking pattern", sb.toString()));
+          }
+          catch (Exception ex)
+          {
+            LOG.warning(ex);
+          }
+        }
+      }
+    }
+    while (pos < 0 && System.currentTimeMillis() < end);
+
+    if (pos < 0)
+    {
+  // System.out.println("error " + this.available());
+      return null;
+    }
+      
+
+    int size = pos - this.posBufRead;
+    if (size < 0)
+      size = size + this.receiveBuffer.length;
+    size = size + pattern.length();
+    return readResponseString(size);
+  }
+
+  public void open (SerialInterface serialInterface)
+  {
+    this.serialInterface = serialInterface;
+    this.serialInterface.addProtocol(this);
+  }
+
+  public void close ()
+  {
+    this.serialInterface.removeProtocol(this);
+    this.serialInterface = null;
+  }
+
+
+  public boolean isReceiveData()
+  {
+    return receiveData;
+  }
+
+
+  public void setReceiveData(boolean receiveData)
+  {
+    this.receiveData = receiveData;
+  }
+
+
+  public void dataAvailable()
+  {
+    int b;
+    int free = 0;
+
+    //LOG.debug(String.format("Bytes received"));    
+    
+    if (receiveData == false || this.connected == false)
+      return;
+    
+    if (this.waitThread == null)
+      throw new RuntimeException("dataAvailable should be overridden");
+
+    switch (this.typ)
+    {
+      case FIFO:
+        do
+        {
+          if (free <= 0)
+          {
+            synchronized (waitThread)
+            {
+              free = free + posBufRead - posBufWrite - 1;
+              if (free < 0)
+                free = receiveBuffer.length;
+              if (free == 0)
+              {
+                this.receiveBufferFull = true;
+                this.receiveBufferFullCounter++;
+                waitThread.notify();
+                return;
+              }
+            }
+          }
+
+          b = -1;
+          try { b = read(); }
+          catch (Exception e) { e.printStackTrace(System.err); }
+          
+          if (b>=0 && b<255)
+          {
+            synchronized (waitThread)
+            {
+              receiveBuffer[posBufWrite++] = (byte) b;
+              if (posBufWrite >= receiveBuffer.length)
+                posBufWrite = 0;
+              free--;
+              //LOG.debug(String.format("Bytes received: %d free", free));
+              waitThread.notify();
+            }
+          }
+        }
+        while (b>=0 && b<=255);
+        break;
+
+        
+      case RINGBUFFER:
+        try
+        {
+          b = read();
+          while (b>=0 && b<=255)
+          {
+            char c = (b>=32 && b<127) ? (char)b : ' ';
+            //LOG.debug(String.format("Protocol: receive byte 0x%02x %c", b, c));
+            //System.out.println("receive " + (char) b);
+            synchronized (waitThread)
+            {
+              int end = posBufWrite + 1;
+              if (end >= receiveBuffer.length)
+                end = 0;
+              receiveBuffer[posBufWrite] = (byte)b;
+              posBufWrite = end;
+              waitThread.notify();
+              if (end == posBufRead)
+                posBufRead++;
+              if (posBufRead >= receiveBuffer.length)
+                posBufRead = 0;
+            }
+            b = read();
+          }
+        }
+        catch (Exception ex) { ex.printStackTrace(System.err); }
+
+    break;
+      
+      case NOBUFFER:
+        synchronized (waitThread)
+        {
+          try { this.serialInterface.read(this, null, 0, 0); } // remove all bytes from inputstream in SerialInterface
+          catch (Exception ex) { ex.printStackTrace(System.err); }
+          finally { waitThread.notify(); }
+        }
+        break;
+    }
+  }
+
+  protected void wasDisconnected()
+  {
+    this.connected = false;
+  }
+
+
+  protected void wasConnected()
+  {
+    this.connected = true;
+  }
+
+
+  protected void paused()
+  {
+    this.connected = false;
+  }
+
+
+  protected void continued()
+  {
+    this.connected = true;
+  }
+
+
+  public boolean isConnected()
+  {
+    return connected;
+  }
+
+  public void connect () throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+
+    this.serialInterface.addProtocol(this);
+  }
+
+  public void disconnect () throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+
+    this.serialInterface.removeProtocol(this);
+  }
+
+  public int setSerialPortSpeed (int baudrate) throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    
+    return serialInterface.setPortSpeed(baudrate);
+  }
+
+  public int availableOnInput () throws Exception, IOException
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    return serialInterface.availableOnInput();
+  }
+
+  public int read(byte[] b, int off, int len) throws Exception, IOException, NullPointerException
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    return this.serialInterface.read(this, b, off, len);
+  }
+
+  public int read() throws Exception, IOException, NullPointerException
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    return this.serialInterface.read(this);
+  }
+
+  public void write(int b) throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    this.serialInterface.write(this, b);
+  }
+
+  public void write(byte[] b) throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    this.serialInterface.write(this, b);
+  }
+
+  public void write(String s) throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    this.serialInterface.write(this, s);
+  }
+
+  public void write(byte[] b, int off, int len) throws Exception
+  {
+    if (this.serialInterface == null)
+      throw new Exception("Protocol: interface not open (serialInterface==null)");
+    this.serialInterface.write(this, b, off, len);
+  }
+
+  public int toUnsignedByte (byte b)
+  {
+    return b<0 ? b+256 : b;
+  }
+
+  public String bytesToString (byte [] b, int offset, int len, boolean withHex)
+  {
+    StringBuilder sb = new StringBuilder(32);
+
+    for (int i=0; i<len; i++)
+    {
+      int val = toUnsignedByte(b[offset+i]);
+      if (val<32 || val>127)
+        sb.append(".");
+      else
+        sb.append((char) val);
+    }
+    if (withHex)
+    {
+      sb.append("   ");
+      for (int i=0; i<len; i++)
+      {
+        int val = toUnsignedByte(b[offset+i]);
+        sb.append(String.format(" %02x", val));
+      }
+    }
+
+    return sb.toString();
+  }
+
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/ResetProtocol.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/ResetProtocol.java
new file mode 100644 (file)
index 0000000..ba47958
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.gui.TerminalArea;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author steiner
+ */
+public class ResetProtocol extends Protocol
+{
+
+  private static final Logger LOG = Logger.getLogger(ResetProtocol.class.getName());
+  
+  private String bootloaderVersion;
+  protected TerminalArea terminalArea;
+
+  public ResetProtocol (SerialInterface serialInterface, TerminalArea terminalArea)
+  {
+    //super(serialInterface, 128, Protocol.BufferTyp.RINGBUFFER);
+    super(serialInterface, 256, Protocol.BufferTyp.RINGBUFFER);
+    this.terminalArea = terminalArea;
+    this.open(serialInterface);
+  }
+
+
+  @Override
+  public void dataAvailable ()
+  {
+    super.dataAvailable(); //To change body of generated methods, choose Tools | Templates.
+  }
+
+  
+  
+
+  public void reset (ChangeListener gui, boolean stayInBootloader, String resetCmd) throws Exception
+  {
+    //new Exception("Test").printStackTrace(System.err);
+    this.setChangeListener(gui);
+    boolean isResetSequence = resetCmd.endsWith("\r\n");
+    if (isResetSequence)
+      resetCmd = resetCmd.substring(0, resetCmd.length()-2);
+    
+    if (isBootloaderDetetcted())
+    {
+      if (terminalArea != null)
+        terminalArea.append("\n\r");
+    }
+    else
+    {
+      String str = null;
+      int counter = 0;
+      boolean error;
+
+      do
+      {
+        counter++;
+        error = false;
+        gui.stateChanged(new ChangeEvent("Sende Reset-Kommando '" + resetCmd + 
+                                         (isResetSequence ? "\n\r" : "") +
+                                         "' (" + counter + ".Versuch)"));
+        if (isResetSequence) 
+        {
+          write("\r\n");
+        } 
+        Thread.sleep(25);
+        flush();
+        write(resetCmd.getBytes());
+        if (isResetSequence) 
+        {
+          write("\r\n");
+        } 
+        if (stayInBootloader == false)
+          gui.stateChanged(new ChangeEvent(25*counter));
+        waitOnBootLoaderDetected(500);
+        str = readResponseString(-1, 1);
+        if (str==null || str.contains("Bootloader")==false)
+        {
+          error = true;
+          // target system in download mode, waiting for transfer of 128 bytes??
+          for (int i=0; i<300; i++)
+            write('F');
+          str = readResponseString(">", 300);
+          if (str == null && counter >= 3)
+            throw new Exception("no or unexpected system response");
+        }
+      }
+      while (error);
+        
+      String [] msg = str.split("\r\n");
+      for (String s : msg)
+      {
+        if (terminalArea != null && s != null && s.contains("Bootloader"))
+        {
+          terminalArea.append("\n\r");
+          terminalArea.append(s);
+          terminalArea.append("\n\r");
+         }
+       }
+    }
+
+    if (stayInBootloader)
+      return;
+
+    gui.stateChanged(new ChangeEvent(50));
+
+    if (isBootloaderDetetcted())
+    {
+      gui.stateChanged(new ChangeEvent("Bootloader aktiv, sende @g Kommando"));
+      write("@g\n");
+      gui.stateChanged(new ChangeEvent(75));
+      String str = readResponseString("@g", 200);
+      gui.stateChanged(new ChangeEvent(100));
+      terminalArea.append("\n\r");
+      flush(); 
+      
+      if (str == null || !str.contains("@g"))
+      {
+        LOG.warning("missing proper response on reset sequence");
+        throw new Exception("reset sequence fails");
+      }
+      
+      LOG.info("Reset sequence success.");
+      return;
+    }
+  }
+
+
+}
+
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialInterface.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialInterface.java
new file mode 100644 (file)
index 0000000..0550a5c
--- /dev/null
@@ -0,0 +1,872 @@
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+// for package gnu.io in linux:
+//   apt-get install librxtx-java
+//   Netbeans: Source Package - Properties - Libraries - Add JAR/Folder 
+//     /usr/share/java/RXTXcomm.jar
+
+
+//import gnu.io.*;
+import at.htlkaindorf.sx.EasyProgrammer.data.ByteFifo;
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import jssc.SerialPort;
+import jssc.SerialPortEvent;
+import jssc.SerialPortException;
+
+/**
+ * Zugriff auf die serielle Schnittstelle.</BR>
+ * @author Manfred Steiner
+ */
+public final class SerialInterface 
+{
+  private static final Logger LOG = Logger.getLogger(SerialInterface.class.getName());
+  
+  public static Map<String, String> getLinuxPortProperties (String portName)
+  {
+    String os = System.getProperty("os.name").toLowerCase();
+    Map<String, String> props = new HashMap<String, String>();
+    if (!os.contains("linux"))
+      return props;
+
+    try
+    {
+      // portName has the format /dev/ttyUSB0
+      String dev = portName.split("/")[2];
+      File sysfsNode = new File("/sys/bus/usb-serial/devices/" + dev);
+
+      // resolve the symbolic link and store the resulting components in an array
+      String[] sysfsPath = sysfsNode.getCanonicalPath().split("/");
+
+      // walk the tree to the root
+      for (int i = sysfsPath.length - 2; i > 0; i--)
+      {
+        String curPath = "/";
+        for (int j = 1; j <= i; j++)
+        {
+          curPath += sysfsPath[j] + "/";
+        }
+
+        // look for specific attributes
+        String[] attribs =
+        {
+          "idProduct", "idVendor", "manufacturer", "product", "serial"
+        };
+        for (int j = 0; j < attribs.length; j++)
+        {
+          try
+          {
+            Scanner in = new Scanner(new FileReader(curPath + attribs[j]));
+            // we treat the values just as strings
+            props.put(attribs[j], in.next());
+          }
+          catch (Exception e)
+          {
+            // ignore the attribute
+          }
+        }
+
+        // stop once we have at least one attribute
+        if (props.size() > 0)
+        {
+          break;
+        }
+
+      }
+    }
+    catch (Exception e)
+    {
+      // nothing to do, return what we have so far
+    }
+
+    return props;
+  }
+  
+  private SerialPort port;
+  private int baudRate;
+  private int dataBits;
+  private int stopBits;
+  private int parity;
+  private SerialInputStream inputStream;
+  private SerialPortEventListener serialPortEventListener;
+  private ArrayList<SerialPortInfo> interfaceNameList;
+  private ArrayList<SerialPortInfo> availInterfaceList;
+  private ArrayList<Protocol> protocolList;
+  private int totalBytesRead;
+  //private boolean outputBufferEmpty;
+  private int dotCounter;
+  private long lastDotTime;
+
+  private ArrayList <Character> history;
+  private Thread receiveThread;
+  private final ByteFifo receiveFifo = new ByteFifo(1024);
+  private Monitor monitor = null; //new Monitor(65536);
+  
+
+
+  public SerialInterface () throws Exception
+  {
+    interfaceNameList = new ArrayList<>();
+    availInterfaceList = new ArrayList<>();
+    protocolList = new ArrayList <Protocol>();
+    serialPortEventListener = new SerialPortEventListener();
+    //outputBufferEmpty = true;
+    history = new ArrayList <Character>();
+    updateInterfaces(); // can cause an Exception if DLL not available
+  }
+
+  public void printMonitor ()
+  {
+    if (monitor != null)
+      monitor.print(System.out);
+  }
+  
+  
+  synchronized public void addProtocol (Protocol protocol)
+  {
+    if (protocolList.contains(protocol))
+      protocolList.remove(protocol);
+
+    LOG.fine("Adding protocol " + protocol.getClass().getSimpleName());
+    
+    if (protocolList.size()>0)
+      protocolList.get(0).paused();
+    protocolList.add(0, protocol);
+    if (this.isConnected())
+      protocol.wasConnected();
+  }
+
+  synchronized public void removeProtocol (Protocol protocol)
+  {
+    protocolList.remove(protocol);
+    LOG.fine("removing protocol " + protocol.getClass().getSimpleName());
+    
+    try
+    {
+      if (this.inputStream != null)
+      {
+        while (this.inputStream.available()>0)
+          this.inputStream.read(null);
+      }
+    }
+    catch (IOException ex)
+    {
+      ex.printStackTrace(System.err);
+    }
+
+    if (protocolList.size()>0)
+    {
+      protocolList.get(0).continued();
+      LOG.fine("switch back to protocol " + protocolList.get(0).getClass().getSimpleName());
+    }
+  }
+
+  /*
+  synchronized private void setOutputBufferEmpty (boolean value)
+  {
+    this.outputBufferEmpty = value;
+  }
+   * 
+   */
+
+  public int availableOnInput () throws Exception,IOException
+  {
+    if (this.inputStream == null)
+      throw new Exception("SerialInterface: inputStream==null");
+    return this.inputStream.available();
+  }
+
+
+
+//  public ArrayList<SerialPortInfo> getAvailInterfaceList()
+//  {
+//    return availInterfaceList;
+//  }
+
+
+  public ArrayList<SerialPortInfo> getInterfaceNameList()
+  {
+    return interfaceNameList;
+  }
+
+
+  public boolean isInterfaceAvailable (SerialPortInfo name)
+  {
+    return this.availInterfaceList.contains(name);
+  }
+
+
+  public boolean isConnected ()
+  {
+    if (this.inputStream != null && this.port != null && this.port.isOpened())
+      return true;
+
+    return false;
+  }
+
+
+  public void updateInterfaces() throws Exception
+  {
+    interfaceNameList = new ArrayList<SerialPortInfo>();
+    SerialPortInfoFactory.refresh(false);
+    String [] ports = jssc.SerialPortList.getPortNames();
+    for (String name : ports)
+      interfaceNameList.add(SerialPortInfoFactory.getSerialPortInfo(name));
+    
+//    LOG.debug("updateInterfaces");
+//    System.out.print("    interfaceNameList:");
+//    for (SerialPortInfo pi : interfaceNameList)
+//      System.out.print(" " + pi.toString());
+//    System.out.println();
+  }
+
+  
+  public void checkInterfaces() throws Exception
+  {
+    availInterfaceList.addAll(interfaceNameList);
+//    LOG.debug("checkInterfaces");
+//    System.out.print("    availInterfaceList:");
+//    for (SerialPortInfo pi : availInterfaceList)
+//      System.out.print(" " + pi.toString());
+//    System.out.println();
+
+    
+//    CommPortIdentifier portID;
+//    updateInterfaces(); // can throw an Exception if library not available
+//    availInterfaceList = new ArrayList<String>();
+//    SerialPort sp;
+//    
+//    for (String name : interfaceNameList )
+//    {
+//      try
+//      {
+//        portID = CommPortIdentifier.getPortIdentifier(name);
+//        if (portID.getPortType() != CommPortIdentifier.PORT_SERIAL)
+//          throw new RuntimeException("port list has a none serial port member");
+//        else
+//        {
+//          if (port != null && port.getName().contains(name))
+//            this.availInterfaceList.add(name);
+//          else
+//          {
+//            sp = (SerialPort) portID.open("EasyProgrammer", 500);
+//            sp.close();
+//            sp = null;
+//            this.availInterfaceList.add(name);
+//          }
+//        }
+//      }
+//      catch (NoSuchPortException ex)
+//      {
+//      }
+//      catch (PortInUseException ex)
+//      {
+//      }
+//    }
+  }
+
+  public int setPortSpeed (int baudRate) throws Exception
+  {
+    if (port == null)
+      throw new Exception("port not open");
+
+    if (baudRate != this.baudRate && port != null)
+      port.setParams(baudRate, dataBits, stopBits, parity);
+
+    return baudRate;
+//    port.closePort();
+//    CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier("COM1");
+//    port = (SerialPort) portID.open("EasyProgrammer", 1000);
+//    port.setSerialPortParams(baudrate, databits, stopbits, parity);
+//    this.inputStream = port.getInputStream();
+//    this.outputStream = port.getOutputStream();
+//    try
+//      {
+//        port.addEventListener(serialPortEventListener);
+//        //System.out.println("EventListener erfolgreich etabliert");
+//        port.notifyOnDataAvailable(true);
+//        port.notifyOnOutputEmpty(true);
+//      }
+//      catch (TooManyListenersException e)
+//      {
+//        System.out.println("TooManyListenersException für Serialport");
+//      }
+//    System.out.println("baudrate set to " + baudrate);
+//    return speed;
+  }
+
+  public void connect (SerialPortInfo serialPortInfo) throws IOException
+  {
+    if (port != null)
+      throw new RuntimeException("Connect ... but interface is already connected");
+    
+    totalBytesRead = 0;
+    
+    try
+    {
+      port = new jssc.SerialPort(serialPortInfo.getName());
+      if (!port.openPort())
+        throw new Exception("result of openPort() is false");
+    }
+    catch (Exception ex)
+    {
+      port = null;
+      throw new IOException("cannot open port " + serialPortInfo.getName());
+    }
+
+    try
+    {
+      serialPortInfo.setJSSCSerialPortParams(port);
+      inputStream = new SerialInputStream(port);
+      for (Protocol protocol : protocolList)
+        protocol.wasConnected();
+      
+      receiveThread = new Thread(new DataAvailableThread());
+      receiveThread.start();
+      port.addEventListener(serialPortEventListener);
+    }
+    catch (Exception ex)
+    {
+      IOException ioex = new IOException(ex);
+      ioex.printStackTrace(System.err);
+      try
+      {
+        if (!port.closePort())
+          throw new SerialPortException(port.getPortName(), "closePort", "");
+        throw ioex;
+      }
+      catch (SerialPortException e)
+      {
+        e.addSuppressed(ex);
+        ioex = new IOException(e);
+      }
+      port = null;
+      inputStream = null;
+      throw ioex;
+    }
+  }
+
+  
+  public void disconnect()
+  {
+    if (port == null)
+      throw new IllegalStateException("Disconnect ... but interface is not connected");
+
+    for (Protocol protocol : this.protocolList)
+      protocol.wasDisconnected();
+
+    try
+    {
+      if (!port.closePort())
+        throw new SerialPortException(port.getPortName(), "closePort", "closePort return value false");
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace(System.err);
+    }
+    finally
+    {
+      inputStream = null;
+      port = null;
+      totalBytesRead = 0;
+      if (receiveThread != null)
+        receiveThread.interrupt();
+      receiveThread = null;
+    }
+
+  }
+
+
+  private void detectBootloader (int b)
+  {
+    if ((char)b != '.')
+    {
+      this.dotCounter = 0;
+      this.lastDotTime = 0;
+      return;
+    }
+    if (this.lastDotTime==0)
+    {
+      this.dotCounter = 0;
+      this.lastDotTime = System.nanoTime();
+    }
+    else
+    {
+      long time = System.nanoTime();
+      long dt = Math.abs((time-this.lastDotTime)/1048576);
+      if (dt>=35 && dt<=55)
+        this.dotCounter++;
+      else
+        this.dotCounter=0;
+      this.lastDotTime = System.nanoTime();
+    }
+  }
+
+  public boolean isBootloaderDetetcted ()
+  {
+    long dt = 0;
+
+    if (this.lastDotTime != 0)
+    {
+      long time = System.nanoTime();
+      dt = Math.abs((time-this.lastDotTime)/1048576);
+      if (dt<=55 && this.dotCounter > 2)
+        return true;
+    }
+    if (dt>55)
+      this.dotCounter = 0;
+
+    return false;
+  }
+
+  private void checkProtocol (Object source)
+  {
+    if (!(source instanceof Protocol))
+      System.out.println("ERROR");
+    else if (((Protocol)source) != protocolList.get(0))
+      System.out.println("Wrong Protocol");
+  }
+  
+  
+  public int read (Object source, byte[] b, int off, int len) throws Exception, IOException, NullPointerException
+  {
+    checkProtocol(source);
+    if (inputStream == null)
+      throw new Exception("SerialInterface: inputStream==null");
+    if (b==null || len<=0)
+    {
+      while(inputStream.read(source) >= 0);
+      return 0;
+    }
+    int rv = 0;
+    for (int i=0; len>0; i++, len--)
+    {
+      int x = inputStream.read(source);
+      if (x<0)
+        return rv;
+      b[i] = (byte) x;
+      rv++;
+    }
+    return inputStream.read(b, off, len);
+  }
+
+  public int read (Object source)  throws Exception, IOException
+  {
+    int b;
+
+    if (inputStream == null)
+      throw new Exception("SerialInterface: inputStream==null");
+    if (inputStream.available()>0)
+      b = inputStream.read(source);
+    else
+      b = -1;
+
+    if (b>=0)
+    {
+      detectBootloader(b);
+/*
+      history.add((char)b);
+      if (b==':')
+      {
+        String s = "";
+        for (int i=0; i<history.size(); i++)
+        {
+          Character c = history.get(i);
+          System.out.print(String.format(" %02x", (int)c));
+          if (Character.isLetterOrDigit(c))
+            s = s + c;
+          else
+            s = s + ".";
+          if (i % 16 == 0)
+          {
+            System.out.println("  " + s);
+            s = "";
+          }
+        }
+        System.out.println("");
+      }
+ * 
+ */
+    }
+    return b;
+  }
+
+  public SerialPort getPort()
+  {
+    return port;
+  }
+
+  public void write (Object source, char c)
+  {
+    if (port==null || !port.isOpened())
+      return;
+    try
+    {
+      if (!port.writeByte((byte)c))
+        throw new IOException();
+      if (monitor != null)
+        monitor.addWriteByte(source, (byte)c);
+    }
+    catch (Exception ex)
+    {
+      LOG.warning(ex);
+    }
+  }
+
+  public void write(Object source, int b) throws Exception, IOException
+  {
+    if (port==null || !port.isOpened())
+      return;
+    try
+    {
+      if (!port.writeByte((byte)b))
+        throw new IOException();
+      if (monitor != null)
+        monitor.addWriteByte(source, (byte)b);
+    }
+    catch (Exception ex)
+    {
+      LOG.warning(ex);
+    }
+  }
+
+  public void write(Object source, byte[] ba) throws Exception, IOException
+  {
+    if (port==null || !port.isOpened())
+      return;
+    try
+    {
+      if (!port.writeBytes(ba))
+        throw new IOException();
+      if (monitor != null)
+      {
+        for (byte b : ba)
+        monitor.addWriteByte(source, b);
+      }
+    }
+    catch (Exception ex)
+    {
+      LOG.warning(ex);
+    }
+  }
+
+  public void write(Object source, byte[] ba, int off, int len) throws Exception, IOException
+  {
+    write(source, Arrays.copyOfRange(ba, off, off+len));
+  }
+
+  public void write (Object source, String s) throws Exception
+  {
+    write(source, s.getBytes());
+  }
+
+  
+
+  public void write (Object source, Object obj) throws Exception
+  {
+    if (obj instanceof String)
+    {
+      write (source, (String) obj);
+    }
+    else if(obj instanceof byte[])
+    {
+      try
+      {
+        write (source, (byte []) obj);  
+      }
+      catch (Exception e)
+      {
+        e.printStackTrace(System.err);
+        throw new RuntimeException(e.getMessage());
+      }
+    }
+    else
+      throw new RuntimeException("Not supported object type");
+  }
+
+  
+  public DebugOutputStream getDebugOutputStream ()
+  {
+    //if (this.outputStream != null && this.outputStream instanceof DebugOutputStream)
+    //  return (DebugOutputStream) this.outputStream;
+    return null;
+  }
+
+
+  public Monitor getMonitor ()
+  {
+    return monitor;
+  }
+
+  private class InputNotification
+  {
+    private final Object toNotifyObject;
+    private final String pattern;
+    private int i;
+
+    public InputNotification (String pattern, Object toNotifyObject)
+    {
+      this.toNotifyObject = toNotifyObject;
+      this.pattern = pattern;
+    }
+    
+    private void put (char b)
+    {
+      if (pattern.charAt(i) == b)
+        i++;
+      else
+        i = 0;
+      if (i>=pattern.length())
+      {
+        i = 0;
+        if (toNotifyObject != null)
+        {
+          synchronized (toNotifyObject)
+          {
+            toNotifyObject.notify();
+          }
+        }
+      }  
+    }
+    
+  }
+  
+  private final AtomicReference<InputNotification> inputNotification = new AtomicReference<>();
+  
+  public void addInputDetector (String pattern, Object toNotify)
+  {
+    inputNotification.set(new InputNotification(pattern, toNotify));
+  }
+
+  
+  private class DataAvailableThread implements Runnable
+  {
+
+    @Override
+    public void run ()
+    {
+      LOG.finer("Start of DataAvailableThread");
+      try
+      {
+        synchronized (receiveFifo)
+        {
+          while (!Thread.interrupted())
+          {
+            int n = receiveFifo.available();
+            if (protocolList.size()>0 && n>0)
+            {
+              LOG.finest(String.format("%d bytes available in receive FIFO", n));
+              protocolList.get(0).dataAvailable();
+            }
+            try
+            {
+              receiveFifo.wait();
+            }
+            catch (InterruptedException ex)
+            {
+              break;
+            }
+          }
+        }
+      }
+      finally
+      {
+        LOG.finer("End of DataAvailableThread");
+      }
+    }
+    
+  }
+  
+  /**
+ *
+ * @author steiner
+ */
+  public class SerialPortEventListener implements jssc.SerialPortEventListener
+  {
+    @Override
+    public void serialEvent (SerialPortEvent spe)
+    {
+      if (spe.isRXCHAR())
+      {
+        try
+        {
+          byte [] ba = port.readBytes();
+          receiveFifo.push(ba);
+          synchronized (receiveFifo)
+          {
+            receiveFifo.notify();
+          }
+        }
+        catch (Exception ex)
+        {
+          LOG.warning(ex);
+        }
+      }
+    }
+  }
+  
+  private class SerialInputStream extends InputStream
+  {
+    private final SerialPort port;
+    
+    public SerialInputStream (SerialPort port)
+    {
+      this.port = port;
+    }
+
+    @Override
+    public int available () throws IOException
+    {
+      try
+      {
+        //return port.getInputBufferBytesCount();
+        return receiveFifo.available();
+      }
+      catch (Exception ex)
+      {
+        throw new IOException(ex);
+      }
+    }
+    
+    
+    public int read (Object source) throws IOException
+    {
+      if (receiveFifo.available()<=0)
+        return -1;
+
+      int b = receiveFifo.pop();
+      if (b>=0)
+      {
+        if (monitor != null)
+          monitor.addReadByte(source, b);
+      }
+
+      return b;
+    }
+    
+    @Override
+    public int read () throws IOException
+    {
+      IOException ex = new IOException("wrong method");
+      ex.printStackTrace(System.out);
+      return read((Object)null);
+    }
+  }
+
+    
+  public class Monitor
+  {
+    private final long [] wTimeStamp;
+    private final long [] rTimeStamp;
+    private final Object [] wSource;
+    private final Object [] rSource;
+    private int wIndex;
+    private int rIndex;
+    private final byte [] w;
+    private final byte [] r;
+
+
+    public Monitor (int size)
+    {
+      wTimeStamp = new long [size];
+      rTimeStamp = new long [size];
+      wSource = new Object [size];
+      rSource = new Object [size];
+      w = new byte [size];
+      r = new byte [size];
+    }
+    
+    public synchronized void addWriteByte (Object source, int b)
+    {
+      //LOG.debug(String.format("writing %02x %c", b, (b>=32 && b<127) ? (char)b : ' '), 5);
+      if (wIndex<w.length)
+      {
+        wTimeStamp[wIndex] = System.currentTimeMillis();
+        wSource[wIndex] = source;
+        w[wIndex++] = (byte)(b>=128 ? b-256 : b);
+      }
+    }
+
+    public synchronized void addWriteByte (Object source, byte b)
+    {
+      //LOG.debug(String.format("writing %02x %c", b<0 ? b+256: b, (b>=32 && b<127) ? (char)b : ' '), 5);
+      if (wIndex<w.length)
+      {
+        wTimeStamp[wIndex] = System.currentTimeMillis();
+        wSource[wIndex] = source;
+        w[wIndex++] = b;
+      }
+    }
+
+    public synchronized void addReadByte (Object source, int b)
+    {
+      if (rIndex<r.length)
+      {
+        rTimeStamp[rIndex] = System.currentTimeMillis();
+        rSource[rIndex] = source;
+        r[rIndex++] = (byte)(b>=128 ? b-256 : b);
+      }
+    }
+
+    public synchronized void addReadByte (Object source, byte b)
+    {
+      if (rIndex<r.length)
+      {
+        rTimeStamp[rIndex] = System.currentTimeMillis();
+        rSource[rIndex] = source;
+        r[rIndex++] = b;
+      }
+    }
+
+    public void print (PrintStream s)
+    {
+      int ri=0, wi=0;
+      long tStart = 0;
+      if (wIndex>0) tStart = wTimeStamp[0];
+      if (rIndex>0) tStart = Math.min(tStart, rTimeStamp[0]);
+              
+      while (true)
+      {
+        if (ri>=rIndex && wi>=wIndex)
+          return;
+        
+        long wts = wi<wIndex ? wTimeStamp[wi] : Long.MAX_VALUE;
+        long rts = ri<rIndex ? rTimeStamp[ri] : Long.MAX_VALUE;
+        
+        if (rts<wts)
+        {
+          long dt = rts-tStart;
+          s.append(String.format("%6dms: ", dt));
+          int b = r[ri]<0 ? ((int)r[ri])+256 : ((int)r[ri]);
+          char c = (b>=32 && b<127) ? (char)b : ' ';
+          s.append(String.format("%c  %02x  ", c, b));
+          if (rSource[ri]!=null)
+            s.append(String.format("%35s", rSource[ri].getClass().getSimpleName()));
+          s.println();
+          ri++;
+        }
+        else
+        {
+          long dt = wts-tStart;
+          s.append(String.format("%6dms: ", dt));
+          int b = w[wi]<0 ? ((int)w[wi])+256 : ((int)w[wi]);
+          char c = (b>=32 && b<127) ? (char)b : ' ';
+          s.append(String.format("             %c  %02x        ", c, b));
+          if (wSource[wi]!=null)
+            s.append(String.format("%s", wSource[wi].getClass().getSimpleName()));
+          s.println();
+          wi++;
+        }
+      }
+    }
+    
+  }
+  
+  
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfo.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfo.java
new file mode 100644 (file)
index 0000000..4b67236
--- /dev/null
@@ -0,0 +1,28 @@
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+
+/**
+ *
+ * @author steiner
+ */
+public abstract class SerialPortInfo  implements Comparable
+{
+  public abstract String getName ();
+  public abstract String getPID ();
+  public abstract String getVID ();
+  public abstract String getManufacturer ();
+  public abstract String getSerialNumber ();
+  public abstract String getProductName ();
+  public abstract String [] getSupportedBaudrates();
+  public abstract String [] getSupportedStopBits();
+  public abstract String [] getSupportedDatabits();
+  public abstract String [] getSupportedParityModes();
+  public abstract int getBaudrateIndex();
+  public abstract int getStopBitIndex();
+  public abstract int getDatabitIndex();
+  public abstract int getParityModeIndex();
+  public abstract String getConfigString ();
+  public abstract void setConfiguration (String config) throws IllegalArgumentException;
+  public abstract void setConfiguration (String baudRate, String dataBits, String parityMode, String stopBits) throws IllegalArgumentException;
+  public abstract boolean setJSSCSerialPortParams (jssc.SerialPort port) throws jssc.SerialPortException;
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfoFactory.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/SerialPortInfoFactory.java
new file mode 100644 (file)
index 0000000..a55c980
--- /dev/null
@@ -0,0 +1,573 @@
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.logging.Logger;
+import java.io.File;
+import java.io.FileReader;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.TreeMap;
+import jssc.SerialPortList;
+
+
+/**
+ *
+ * @author steiner
+ */
+public class SerialPortInfoFactory
+{
+  private static final Logger LOG = Logger.getLogger(SerialPortInfoFactory.class.getName());
+  private static final String[] ATTRIBUTES = { "idProduct", "idVendor", "manufacturer", "product", "serial" };
+
+  private final static LinkedHashMap<String,Integer> jsscBaudrates = new LinkedHashMap<>();
+  private final static LinkedHashMap<String,Integer> jsscDatabits  = new LinkedHashMap<>();   
+  private final static LinkedHashMap<String,Integer> jsscStopBits  = new LinkedHashMap<>();
+  private final static LinkedHashMap<String,Integer> jsscParityModes = new LinkedHashMap<>();
+  
+  private final static String [] jsscSupportedBaudrates;
+  private final static String [] jsscSupportedDatabits;
+  private final static String [] jsscSupportedStopBits;
+  private final static String [] jsscSupportedParityModes;
+  
+  static
+  {
+    jsscBaudrates.put(   "110", jssc.SerialPort.BAUDRATE_110);
+    jsscBaudrates.put(   "300", jssc.SerialPort.BAUDRATE_300);
+    jsscBaudrates.put(   "600", jssc.SerialPort.BAUDRATE_600);
+    jsscBaudrates.put(  "1200", jssc.SerialPort.BAUDRATE_1200);
+    jsscBaudrates.put(  "4800", jssc.SerialPort.BAUDRATE_4800);
+    jsscBaudrates.put(  "9600", jssc.SerialPort.BAUDRATE_9600);
+    jsscBaudrates.put( "14400", jssc.SerialPort.BAUDRATE_14400);
+    jsscBaudrates.put( "19200", jssc.SerialPort.BAUDRATE_19200);
+    jsscBaudrates.put( "38400", jssc.SerialPort.BAUDRATE_38400);
+    jsscBaudrates.put( "57600", jssc.SerialPort.BAUDRATE_57600);
+    jsscBaudrates.put("115200", jssc.SerialPort.BAUDRATE_115200);
+    jsscBaudrates.put("128000", jssc.SerialPort.BAUDRATE_128000);
+    jsscBaudrates.put("256000", jssc.SerialPort.BAUDRATE_256000);
+    
+    jsscDatabits.put("5", jssc.SerialPort.DATABITS_5);
+    jsscDatabits.put("6", jssc.SerialPort.DATABITS_6);
+    jsscDatabits.put("7", jssc.SerialPort.DATABITS_7);
+    jsscDatabits.put("8", jssc.SerialPort.DATABITS_8);
+    
+    jsscStopBits.put(  "1", jssc.SerialPort.STOPBITS_1);
+    jsscStopBits.put("1.5", jssc.SerialPort.STOPBITS_1_5);
+    jsscStopBits.put(  "2", jssc.SerialPort.STOPBITS_2);
+    
+    jsscParityModes.put("N", jssc.SerialPort.PARITY_NONE);
+    jsscParityModes.put("E", jssc.SerialPort.PARITY_EVEN);
+    jsscParityModes.put("O", jssc.SerialPort.PARITY_ODD);
+    jsscParityModes.put("S", jssc.SerialPort.PARITY_SPACE);
+    jsscParityModes.put("M", jssc.SerialPort.PARITY_MARK);
+    
+    jsscSupportedBaudrates = jsscBaudrates.keySet().toArray(new String[0]);
+    jsscSupportedDatabits = jsscDatabits.keySet().toArray(new String[0]);
+    jsscSupportedStopBits = jsscStopBits.keySet().toArray(new String[0]);
+    jsscSupportedParityModes = jsscParityModes.keySet().toArray(new String[0]);
+    
+  }
+  
+  
+  private static SerialPortInfoFactory instance;
+
+//  public static SerialPortName getSerialPortName (String name, Map<String, String> properties)
+//  {
+//    if (instance == null)
+//      instance = new SerialPortNameFactory();
+//    return instance.findSerialPortName(name, properties);
+//  }
+
+  public static SerialPortInfo getSerialPortInfo (String name)
+  {
+    if (instance == null)
+      instance = new SerialPortInfoFactory();
+    SerialPortInfo rv = instance.findSerialPortInfo(name);
+    //LOG.debug(String.format("getSerialPortName(%s)->%d", name, rv.hashCode()));
+    return rv;
+  }
+
+  public static SerialPortInfo getSerialPortInfo (String name, String config)
+  {
+    if (instance == null)
+      instance = new SerialPortInfoFactory();
+    SerialPortInfo rv = instance.findSerialPortInfo(name, config);
+    //LOG.debug(String.format("getSerialPortInfo(%s,%s)->%d", name, config, rv.hashCode()));
+    return rv;
+  }
+  
+  public static SerialPortInfo getSerialPortInfo (String name, String baudRate, String dataBits, String parityMode, String stopBits)
+  {
+    if (instance == null)
+      instance = new SerialPortInfoFactory();
+    SerialPortInfo rv = instance.findSerialPortInfo(name, baudRate, dataBits, parityMode, stopBits);
+    return rv;
+  }
+
+  public static void refresh (boolean allowRemovement)
+  {
+    if (instance == null)
+      instance = new SerialPortInfoFactory();
+    instance.refreshPortInfoMap(allowRemovement);
+  }
+
+  
+  public static void updateSerialPortProperties (String portName, Map<String,String> properties)
+  {
+    String os = System.getProperty("os.name").toLowerCase();
+    if (!os.contains("linux"))
+    {
+      properties.clear();
+      return;
+    }
+
+    try
+    {
+      // portName has the format /dev/ttyUSB0
+      String dev = portName.split("/")[2];
+      File sysfsNode = new File("/sys/bus/usb-serial/devices/" + dev);
+
+      // resolve the symbolic link and store the resulting components in an array
+      String[] sysfsPath = sysfsNode.getCanonicalPath().split("/");
+
+      // walk the tree to the root
+      for (int i = sysfsPath.length - 2; i > 0; i--)
+      {
+        String curPath = "/";
+        for (int j = 1; j <= i; j++)
+        {
+          curPath += sysfsPath[j] + "/";
+        }
+
+        // look for specific attributes
+        for (String att : ATTRIBUTES)
+        {
+          File f = new File(curPath + att);
+          if (!f.canRead())
+          {
+            properties.remove(att);
+            continue;
+          }
+          try
+          {
+            Scanner in = new Scanner(new FileReader(f));
+            // we treat the values just as strings
+            String value = in.next();
+            if (!value.equals(properties.get(att)))
+              properties.put(att, value);
+          }
+          catch (Exception e)
+          {
+            // ignore the attribute
+          }
+        }
+
+        // stop once we have at least one attribute
+        if (!properties.isEmpty())
+          break;
+
+      }
+    }
+    catch (Exception e)
+    {
+      // nothing to do, return what we have so far
+    }
+  }  
+
+
+  
+
+  
+  
+  private final HashMap<String, SerialPortInfo> map = new HashMap<>();
+
+
+  private SerialPortInfoFactory ()
+  {
+  }
+
+  public void refreshPortInfoMap (boolean allowRemovement)
+  {
+    List<SerialPortInfo> avail = new LinkedList<>();
+    String [] ports = jssc.SerialPortList.getPortNames();
+    synchronized (this)
+    {
+      for (String port : ports)
+      {
+        SerialPortInfo pi;
+        if (map.containsKey(port))
+          pi = map.get(port);
+        else
+          pi = new JSSCSerialPortInfo(port);
+        if (pi instanceof JSSCSerialPortInfo)
+          ((JSSCSerialPortInfo)pi).refreshProperties();
+        avail.add(pi);
+      }
+      for (String n : map.keySet())
+      {
+        SerialPortInfo pi = map.get(n);
+        if (!avail.contains(pi))
+        {
+          if (allowRemovement)
+            map.remove(pi);
+          else
+            if (pi instanceof JSSCSerialPortInfo)
+              ((JSSCSerialPortInfo)pi).removeProperties();
+        }
+      }
+    }
+  }
+  
+  private SerialPortInfo findSerialPortInfo (String name)
+  {
+    SerialPortInfo rv;
+
+    if (map.containsKey(name))
+      rv = map.get(name);
+    else
+    {
+      rv = new JSSCSerialPortInfo(name);
+      map.put(name, rv);
+    }
+    return rv;
+  }
+
+
+  private SerialPortInfo findSerialPortInfo (String name, String config)
+  {
+    SerialPortInfo rv;
+
+    if (map.containsKey(name))
+    {
+      rv = map.get(name);
+      rv.setConfiguration(config);
+    }
+    else
+    {
+      rv = new JSSCSerialPortInfo(name, config);
+      map.put(name, rv);
+    }
+    return rv;
+  }
+
+
+  private SerialPortInfo findSerialPortInfo (String name, String baudRate, String dataBits, String parityMode, String stopBits)
+  {
+    SerialPortInfo rv;
+
+    if (map.containsKey(name))
+    {
+      rv = map.get(name);
+      rv.setConfiguration(baudRate, dataBits, parityMode, stopBits);
+    }
+    else
+    {
+      rv = new JSSCSerialPortInfo(name);
+      rv.setConfiguration(baudRate, dataBits, parityMode, stopBits);
+      map.put(name, rv);
+    }
+    return rv;
+  }
+  
+
+  public class JSSCSerialPortInfo extends SerialPortInfo
+  {
+    private final String name;
+    private final Map<String, String> properties;
+    private int baudRate;
+    private int dataBits;
+    private int parity;
+    private int stopBits;
+    private String cachedConfigString;
+
+
+    private JSSCSerialPortInfo (String name)
+    {
+      this.name = name;
+      baudRate = jssc.SerialPort.BAUDRATE_57600;
+      dataBits = jssc.SerialPort.DATABITS_8;
+      parity = jssc.SerialPort.PARITY_NONE;
+      stopBits = jssc.SerialPort.STOPBITS_1;
+      properties = new HashMap<>();
+      updateSerialPortProperties(name, properties);
+    }
+
+
+    private JSSCSerialPortInfo (String name, String config)
+    {
+      this(name);
+      setConfiguration(config);
+    }
+
+
+    public void updateProperties ()
+    {
+      updateSerialPortProperties(name, properties);
+    }
+
+
+    @Override
+    public String getName ()
+    {
+      return name;
+    }
+
+
+    @Override
+    public String getPID ()
+    {
+      return properties.get("idProduct");
+    }
+
+    @Override
+    public String getVID ()
+    {
+      return properties.get("idVendor");
+    }
+    
+    @Override
+    public String getManufacturer ()
+    {
+      return properties.get("manufacturer");
+    }
+    
+    @Override
+    public String getSerialNumber ()
+    {
+      return properties.get("serial");
+    }
+
+    @Override
+    public String getProductName ()
+    {
+      return properties.get("product");
+    }
+
+    private String findKey (Map<String,Integer> m, int value) throws IllegalArgumentException
+    {
+      for (String k : m.keySet())
+      {
+        if (m.get(k) == value)
+          return k;
+      }
+      throw new IllegalArgumentException(String.format("Key not found for value %d", value));
+    }
+    
+    @Override
+    public String getConfigString ()
+    {
+      if (cachedConfigString==null)
+      {
+        try
+        {
+          String b = findKey(jsscBaudrates, baudRate);
+          String d = findKey(jsscDatabits, dataBits);
+          String p = findKey(jsscParityModes, parity);
+          String s = findKey(jsscStopBits, stopBits);
+          cachedConfigString = String.format("%s/%s%s%s", b, d, p, s);
+        }
+        catch (Exception ex)
+        {
+          LOG.warning(ex);
+          cachedConfigString="?/???";
+        }
+      }
+      return cachedConfigString;
+    }
+    
+    
+    @Override
+    public void setConfiguration (String shortConfig) throws IllegalArgumentException
+    {
+      try
+      {
+        int b, d, p, s;
+  
+        if (!shortConfig.contains("/"))
+        {
+          b = jsscBaudrates.get(shortConfig);
+          d = jssc.SerialPort.DATABITS_8;
+          p = jssc.SerialPort.PARITY_NONE;
+          s = jssc.SerialPort.STOPBITS_1;
+        }
+        else
+        {
+          String [] str = shortConfig.split("/");
+          b = jsscBaudrates.get(str[0]);
+          d = jsscDatabits.get(str[1].substring(0,1));
+          p = jsscParityModes.get(str[1].substring(1,2));
+          s = jsscStopBits.get(str[1].substring(2));
+        }
+        
+        synchronized (this)
+        {
+          if (b!=baudRate || d!=dataBits || parity!=p || stopBits!=s)
+          {
+            cachedConfigString = null;
+            baudRate = b;
+            dataBits = d;
+            parity = p;
+            stopBits = s;
+          }
+        }
+      }
+      catch (Exception ex)
+      {
+        throw new IllegalArgumentException(String.format("Unvalid serial configuration '%s'", shortConfig), ex);
+      }
+    }
+    
+   
+
+    @Override
+    public void setConfiguration (String baudRate, String dataBits, String parityMode, String stopBits) throws IllegalArgumentException
+    {
+      try
+      {
+        int b = jsscBaudrates.get(baudRate);
+        int d = jsscDatabits.get(dataBits);
+        int p = jsscParityModes.get(parityMode);
+        int s = jsscStopBits.get(stopBits);
+        
+        synchronized (this)
+        {
+          cachedConfigString = null;
+          this.baudRate = b;
+          this.dataBits = d;
+          this.parity = p;
+          this.stopBits = s;
+        }
+      }
+      catch (Exception ex)
+      {
+        throw new IllegalArgumentException("Unvalid serial configuration", ex);
+      }
+    }
+    
+    
+    @Override
+    public String[] getSupportedBaudrates ()
+    {
+      return jsscSupportedBaudrates;
+    }
+
+
+    @Override
+    public String[] getSupportedStopBits ()
+    {
+      return jsscSupportedStopBits;
+    }
+
+
+    @Override
+    public String[] getSupportedDatabits ()
+    {
+      return jsscSupportedDatabits;
+    }
+
+
+    @Override
+    public String[] getSupportedParityModes ()
+    {
+      return jsscSupportedParityModes;
+    }
+
+    
+    @Override
+    public boolean setJSSCSerialPortParams (jssc.SerialPort port) throws jssc.SerialPortException
+    {
+      return port.setParams(baudRate, dataBits, stopBits, parity);
+    }
+
+
+    @Override
+    public int getBaudrateIndex ()
+    {
+      for (int i=0; i<jsscSupportedBaudrates.length; i++)
+      {
+        if (jsscBaudrates.get(jsscSupportedBaudrates[i]) == baudRate)
+          return i;
+      }
+      return -1;
+    }
+
+
+    @Override
+    public int getStopBitIndex ()
+    {
+      for (int i=0; i<jsscSupportedStopBits.length; i++)
+      {
+        if (jsscStopBits.get(jsscSupportedStopBits[i]) == stopBits)
+          return i;
+      }
+      return -1;
+    }
+
+
+    @Override
+    public int getDatabitIndex ()
+    {
+      for (int i=0; i<jsscSupportedDatabits.length; i++)
+      {
+        if (jsscDatabits.get(jsscSupportedDatabits[i]) == dataBits)
+          return i;
+      }
+      return -1;
+    }
+
+
+    @Override
+    public int getParityModeIndex ()
+    {
+      for (int i=0; i<jsscSupportedParityModes.length; i++)
+      {
+        if (jsscParityModes.get(jsscSupportedParityModes[i]) == parity)
+          return i;
+      }
+      return -1;
+    }
+  
+    
+    
+    @Override
+    public String toString ()
+    {
+      String n = getProductName();
+      if (n != null && !n.isEmpty())
+        return String.format("%s (%s)", name, n);
+      else
+        return name;
+    }
+
+
+    @Override
+    public int compareTo (Object o)
+    {
+      if (o==null)
+        throw new NullPointerException();
+      if (!(o instanceof SerialPortInfo))
+        throw new IllegalArgumentException("wrong class or interface");
+      return this.getName().compareTo(((SerialPortInfo)o).getName());
+    }
+
+
+    private void refreshProperties ()
+    {
+      properties.clear();
+      updateSerialPortProperties(name, properties);
+      cachedConfigString = null;
+    }
+
+
+    private void removeProperties ()
+    {
+      properties.clear();
+      cachedConfigString = null;
+    }
+
+  }
+}
+  
+
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/serial/TerminalProtocol.java b/src/at/htlkaindorf/sx/EasyProgrammer/serial/TerminalProtocol.java
new file mode 100644 (file)
index 0000000..8b5a623
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.serial;
+
+import at.htlkaindorf.sx.EasyProgrammer.gui.TerminalArea;
+import java.io.IOException;
+
+/**
+ *
+ * @author steiner
+ */
+public class TerminalProtocol extends Protocol
+{
+  private TerminalArea terminalArea;
+
+  private long totalBytesRead;
+  private long tempBytesRead;
+  private boolean connected;
+
+
+
+  public TerminalProtocol (TerminalArea terminalArea, SerialInterface serialInterface)
+  {
+    super(serialInterface);
+    this.terminalArea = terminalArea;
+    this.open(serialInterface);
+  }
+
+
+  public void execCommand (String command)
+  {
+    System.out.println(command);
+  }
+
+
+  @Override
+  public void paused()
+  {
+    //System.out.println("Terminal paused");
+    this.connected = false;
+  }
+
+
+  @Override
+  public void continued()
+  {
+    //System.out.println("Terminal continued");
+    dataAvailable();
+    this.connected = true;
+  }
+
+
+  @Override
+  public void dataAvailable()
+  {
+    try
+    {
+      int b;
+      byte[] data = new byte[128];
+      int num;
+
+      b = read();
+      while (b>=0 && b<=255)
+      {
+        terminalArea.append((char)b);
+        totalBytesRead++;
+        if ((totalBytesRead - tempBytesRead)>400 && availableOnInput()>500)
+        {
+          System.err.println("Serial: " + totalBytesRead + " Bytes empfangen  avail=" + availableOnInput());
+          tempBytesRead = totalBytesRead;
+        }
+        b = read();
+      }
+    }
+    catch (IOException ex)
+    {
+      System.out.println("TerminalProtocol: Fehler beim Lesen empfangener Daten");
+      ex.printStackTrace(System.err);
+    }
+    catch (Exception ex)
+    {
+      System.out.println("TerminalProtocol: Fehler beim Lesen empfangener Daten");
+      ex.printStackTrace(System.err);
+    }
+  }
+
+
+  @Override
+  public void wasDisconnected()
+  {
+    this.connected = false;
+  }
+
+
+  @Override
+  public void wasConnected()
+  {
+    this.connected = true;
+  }
+
+
+  @Override
+  public boolean isConnected()
+  {
+    return this.connected;
+  }
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/server/IDEServer.java b/src/at/htlkaindorf/sx/EasyProgrammer/server/IDEServer.java
new file mode 100644 (file)
index 0000000..94a1a95
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.server;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PipedReader;
+import java.io.PipedWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author steiner
+ */
+public class IDEServer
+{
+  private ServerSocket serverSocket;
+  private int port;
+  private Socket socket;
+
+  public IDEServer (int port) throws IOException
+  {
+    this.port = port;
+    this.serverSocket = new ServerSocket (port);
+    System.out.println("IDEServer auf port " + port + " gestartet");
+  }
+
+  public String getRequest () throws IOException
+  {
+    if (this.serverSocket == null)
+      throw new IOException("Server not running");
+
+    if (this.socket != null)
+      throw new IOException("Request pending");
+
+    socket = this.serverSocket.accept();
+    final BufferedReader reader = new BufferedReader (new InputStreamReader(socket.getInputStream()));
+    final String request = reader.readLine();
+    return request;
+  }
+
+  public void send (String answer) throws IOException
+  {
+    if (this.socket == null)
+      throw new IOException("Cannot send answer becaus no request pending");
+
+    final BufferedWriter writer = new BufferedWriter (new OutputStreamWriter(socket.getOutputStream()));
+    writer.write(answer); writer.newLine(); writer.flush();
+    this.socket = null;
+  }
+
+  public void stop () throws Exception
+  {
+    if (this.serverSocket == null)
+      throw new Exception("Server not running");
+
+    this.serverSocket.close();
+    System.out.println("IDEServer beendet");
+  }
+
+}
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleClient.java b/src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleClient.java
new file mode 100644 (file)
index 0000000..d79fdb6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.server;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.InetAddress;
+import java.net.Socket;
+
+/**
+ *
+ * @author steiner
+ */
+public class SimpleClient
+{
+
+  public static String sendRequestAndReceiveAnswer(String host, int port, String request) throws Exception
+  {
+    Socket socket = null;
+    try
+    {
+      final InetAddress address = InetAddress.getByName(host);
+      socket = new Socket(address, port);
+      final BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+      final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+
+      // sende Anfrage
+      writer.write(request);
+      writer.newLine();
+      writer.flush();
+      System.out.println("Client (Codeblocks): Befehl an den Server gesendet, warte auf Antwort...");
+      return reader.readLine();
+    }
+    catch (Exception e)
+    {
+    }
+    finally
+    {
+      if (socket != null)
+      {
+        socket.close();
+      }
+      socket = null;
+    }
+
+    return null;
+  }
+
+
+  public static void main (String[] args)
+  {
+    try
+    {
+      String antwort = sendRequestAndReceiveAnswer("localhost", 4711, "connect");
+      System.out.println("Antwort vom Server: " + antwort);
+      Thread.sleep(2000);
+      antwort = sendRequestAndReceiveAnswer("localhost", 4711, "download");
+      System.out.println("Antwort vom Server: " + antwort);
+      Thread.sleep(5000);
+      antwort = sendRequestAndReceiveAnswer("localhost", 4711, "download");
+      System.out.println("Antwort vom Server: " + antwort);
+
+    }
+    catch (Exception e)
+    {
+      e.printStackTrace(System.err);
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleServer.java b/src/at/htlkaindorf/sx/EasyProgrammer/server/SimpleServer.java
new file mode 100644 (file)
index 0000000..dfc2e52
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package at.htlkaindorf.sx.EasyProgrammer.server;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PipedReader;
+import java.io.PipedWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serverapplikation für eine Server/client Anwendung.
+ * @author steiner
+ * Verwendet wird die Klasse ServerSocket, der Konstruktor mit dem port
+ * und die Methode accept, die wartet bis ein client eine Verbindugn aufgenommen
+ * hat
+ */
+public class SimpleServer
+{
+  private ServerSocket serverSocket;
+  private int port;
+  private SimpleServerThread thread = null;
+  private PipedWriter outPipe;
+  private BufferedReader inPipeReader;
+  private PipedReader inPipe;
+
+  private class HandleRequestThread extends Thread
+  {
+    Socket socket;
+
+
+    public HandleRequestThread(Socket socket)
+    {
+      this.socket = socket;
+    }
+
+    @Override
+    public void run()
+    {
+      System.out.println("HandleRequest: Thread gestartet");
+      try
+      {
+        final BufferedReader reader = new BufferedReader (new InputStreamReader(socket.getInputStream()));
+        final BufferedWriter writer = new BufferedWriter (new OutputStreamWriter(socket.getOutputStream()));
+        final String anfrage = reader.readLine();
+        writer.write(createAnswer(anfrage)); writer.newLine(); writer.flush();
+      }
+      catch (Exception e)
+      {
+      }
+      System.out.println("HandleRequest: Thread beendet");
+    }
+  }
+
+
+  private class SimpleServerThread extends Thread
+  {
+    @Override
+    public void run()
+    {
+      System.out.println("Server: Thread gestartet");
+      while (!isInterrupted())
+      {
+        try
+        {
+          handleRequest();
+        }
+        catch (Exception e)
+        {
+        }
+      }
+      System.out.println("Server: Thread beendet");
+    }
+  }
+  
+  public SimpleServer(int port, PipedWriter outPipe, PipedReader inPipe) throws IOException
+  {
+    this.port = port;
+    this.outPipe = outPipe;
+    this.inPipe = inPipe;
+    this.inPipeReader = new BufferedReader(inPipe);
+  }
+
+  public void start() throws IOException
+  {
+    if (thread==null)
+    {
+      serverSocket = new ServerSocket (port);
+      thread = new SimpleServerThread();
+      thread.start();
+    }
+    else
+      throw new IOException("Es läuft bereits ein Server-Thread (nur ein Thread erlaubt)");
+  }
+
+  public void stop() throws IOException
+  {
+    if (thread != null)
+    {
+      thread.interrupt();
+      serverSocket.close();
+      serverSocket = null;
+    }
+    else
+      throw new IOException("Stop eines Servers der nicht gestartet wurde nicht möglich");
+  }
+
+  public String createAnswer (String request)
+  {
+    System.out.println("Server: Request bekommen: " + request);
+    try
+    {
+      this.outPipe.write(request); this.outPipe.write(10);
+      System.out.println("Server: Request über pipe gesendet " + outPipe);
+      System.out.println("Server: Warte auf Antwort... von " + inPipe);
+      String answer = this.inPipeReader.readLine();
+      System.out.println("Server: Antwort: " + answer);
+      return answer;
+    }
+    catch (IOException ex)
+    {
+      ex.printStackTrace(System.err);
+    }
+
+    return null;
+  }
+
+  public void handleRequest()
+  {
+    try
+    {
+      final Socket socket = this.serverSocket.accept();
+      if (socket != null)
+      {
+        new HandleRequestThread(socket).start();
+      }
+    }
+    catch (IOException ex)
+    {
+      ex.printStackTrace(System.err);
+    }
+  }
+
+  public static void main(String[] args)
+  {
+    try
+    {
+      // Ports bis 1024 sind reserviert, bei Linux sogar root Rechte nötig
+      // der eigene Rechner ist immer 127.0.0.1 oder localhost
+      PipedReader inPipeS2C = new PipedReader();
+      PipedWriter outPipeS2C = new PipedWriter(inPipeS2C);
+      PipedReader inPipeC2S = new PipedReader();
+      PipedWriter outPipeC2S = new PipedWriter(inPipeC2S);
+
+      System.out.println("main: S2C: " + outPipeS2C + " -> " + inPipeS2C);
+      System.out.println("main: C2S: " + inPipeC2S + " <- " + outPipeC2S);
+
+      SimpleServer server = new SimpleServer(4711, outPipeS2C, inPipeC2S);
+      server.start();
+      Thread.sleep(5000);
+      final BufferedReader reader = new BufferedReader(inPipeS2C);
+      System.out.println("main: Warte auf Daten von " + inPipeS2C);
+      String request = reader.readLine();
+      System.out.println("main: Befehl bekommen: " + request);
+      outPipeC2S.write("Ha Ha Ha"); outPipeC2S.write(10);
+      System.out.println("main: Antwort gesendet über pipe " + outPipeC2S);
+      Thread.sleep(10000);
+      System.out.println("main: stoppe Server");
+      server.stop();
+      //server.testComm();
+    }
+    catch (IOException e)
+    {
+      e.printStackTrace(System.err);
+    }
+    catch (InterruptedException e)
+    {
+      e.printStackTrace(System.err);
+    }
+
+  }
+
+
+}