From e0441a9224f7e30c9867622508bbf1c67eeff6bb Mon Sep 17 00:00:00 2001 From: crocsg <34553036+crocsg@users.noreply.github.com> Date: Sun, 20 May 2018 15:19:32 +0200 Subject: [PATCH] Tools for NatBraille embossing --- NatBrailleTools/BrailleLogger/.classpath | 6 + NatBrailleTools/BrailleLogger/.project | 17 ++ .../.settings/org.eclipse.jdt.core.prefs | 12 + .../org.eclipse.ltk.core.refactoring.prefs | 2 + .../bin/Braille2GcodeEncoder.class | Bin 0 -> 5408 bytes .../bin/Braille6GcodeEncoding.class | Bin 0 -> 1689 bytes .../BrailleLogger/bin/BrailleGcodeDot.class | Bin 0 -> 876 bytes .../bin/BrailleGcodeEncoding.class | Bin 0 -> 283 bytes .../BrailleLogger/bin/BrailleLogger.class | Bin 0 -> 801 bytes .../BrailleLogger/bin/GCodeGenerator.class | Bin 0 -> 1839 bytes .../src/Braille2GcodeEncoder.java | 220 ++++++++++++++++++ .../src/Braille6GcodeEncoding.java | 141 +++++++++++ .../BrailleLogger/src/BrailleGcodeDot.java | 52 +++++ .../src/BrailleGcodeEncoding.java | 18 ++ .../BrailleLogger/src/BrailleLogger.java | 71 ++++++ .../BrailleLogger/src/GCodeGenerator.java | 67 ++++++ .../simpleJavaGrblStreamer/.classpath | 26 +++ .../simpleJavaGrblStreamer/.project | 23 ++ .../org.eclipse.core.resources.prefs | 3 + .../.settings/org.eclipse.jdt.core.prefs | 5 + .../simpleJavaGrblStreamer/LICENSE | 21 ++ .../simpleJavaGrblStreamer/README.md | 9 + .../simpleJavaGrblStreamer/pom.xml | 37 +++ .../SimpleJavaGrblStreamer.java | 171 ++++++++++++++ ...eJavaGrblStreamer$GrblSerialListener.class | Bin 0 -> 2585 bytes ...pleJavaGrblStreamer$GrblSerialSender.class | Bin 0 -> 4076 bytes .../SimpleJavaGrblStreamer.class | Bin 0 -> 3518 bytes 27 files changed, 901 insertions(+) create mode 100644 NatBrailleTools/BrailleLogger/.classpath create mode 100644 NatBrailleTools/BrailleLogger/.project create mode 100644 NatBrailleTools/BrailleLogger/.settings/org.eclipse.jdt.core.prefs create mode 100644 NatBrailleTools/BrailleLogger/.settings/org.eclipse.ltk.core.refactoring.prefs create mode 100644 NatBrailleTools/BrailleLogger/bin/Braille2GcodeEncoder.class create mode 100644 NatBrailleTools/BrailleLogger/bin/Braille6GcodeEncoding.class create mode 100644 NatBrailleTools/BrailleLogger/bin/BrailleGcodeDot.class create mode 100644 NatBrailleTools/BrailleLogger/bin/BrailleGcodeEncoding.class create mode 100644 NatBrailleTools/BrailleLogger/bin/BrailleLogger.class create mode 100644 NatBrailleTools/BrailleLogger/bin/GCodeGenerator.class create mode 100644 NatBrailleTools/BrailleLogger/src/Braille2GcodeEncoder.java create mode 100644 NatBrailleTools/BrailleLogger/src/Braille6GcodeEncoding.java create mode 100644 NatBrailleTools/BrailleLogger/src/BrailleGcodeDot.java create mode 100644 NatBrailleTools/BrailleLogger/src/BrailleGcodeEncoding.java create mode 100644 NatBrailleTools/BrailleLogger/src/BrailleLogger.java create mode 100644 NatBrailleTools/BrailleLogger/src/GCodeGenerator.java create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/.classpath create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/.project create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.core.resources.prefs create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.jdt.core.prefs create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/LICENSE create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/README.md create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/pom.xml create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/src/main/java/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer.java create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/target/classes/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer$GrblSerialListener.class create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/target/classes/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer$GrblSerialSender.class create mode 100644 NatBrailleTools/simpleJavaGrblStreamer/target/classes/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer.class diff --git a/NatBrailleTools/BrailleLogger/.classpath b/NatBrailleTools/BrailleLogger/.classpath new file mode 100644 index 0000000..5bc4564 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/NatBrailleTools/BrailleLogger/.project b/NatBrailleTools/BrailleLogger/.project new file mode 100644 index 0000000..75c6405 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/.project @@ -0,0 +1,17 @@ + + + BrailleLogger + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/NatBrailleTools/BrailleLogger/.settings/org.eclipse.jdt.core.prefs b/NatBrailleTools/BrailleLogger/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ef8a789 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/NatBrailleTools/BrailleLogger/.settings/org.eclipse.ltk.core.refactoring.prefs b/NatBrailleTools/BrailleLogger/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100644 index 0000000..b196c64 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/NatBrailleTools/BrailleLogger/bin/Braille2GcodeEncoder.class b/NatBrailleTools/BrailleLogger/bin/Braille2GcodeEncoder.class new file mode 100644 index 0000000000000000000000000000000000000000..cd03adbaedabdd0ee90daa7e95d80dd5c5141808 GIT binary patch literal 5408 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 literal 0 HcmV?d00001 diff --git a/NatBrailleTools/BrailleLogger/bin/Braille6GcodeEncoding.class b/NatBrailleTools/BrailleLogger/bin/Braille6GcodeEncoding.class new file mode 100644 index 0000000000000000000000000000000000000000..5c97c4e2646da831b1ce2ee2e2ca645bc62da0e7 GIT binary patch literal 1689 zcmchXOK%e~6orqQw0V%ykWyO8%jKCAXe5MKkg5`dQYwXlXsLu)ITMq(n%I%Y)2d4Z z3)t~*kU)YxKMHYYlD=SyREe?}kME4{IoI}Q|M>ak8-P2Q%V3CM;-MAF_vO7M&$Q&C zrdH{825E-khS(HUU+8xAS#v{rjv>`D)Rta123c{^BjaieX>H9G16yVots5OUq20Rh zLzyBsG8)#t(s7Vt7@1dExdjp|SJo-FPTm=uVi?==T(s8MEXEo8@KReD7=Kf?xM#XO zy$>jX=Lp14H38wQS>O=+!aNp37x-5ymVwIhol>`5E>3@i@VwWV8mVYbT0 z>kuvXKeouDh=~G5afZMtH}>{w)mfsZ7VYI&gM3%QZd2MdLEA&PG>j+wbzxN$4?d<{ zM+FR%J0uH8w~G{T+=Z?$&g<) zq4nfr711`Gcv|NoRtef=y5Mv`%+N7?qNEkp>uhImi(x$B24N^XRY5>#uhCHsFaz2U zy3SIV#xO>xS3(9^`kIR_Ipirmu`ezlP5(x5lG-sEahEa~z4KpDd{rua#_8{I-Xygn z@t*>ws9)%h!ddbG_0Qovsb7f4Uffk0qPVYgDM6{7s5FDir1xhnR}vK7CMsMzMB#dZ X!p8)K6w2{DDww4=aGRcJm2Un52Y1o< literal 0 HcmV?d00001 diff --git a/NatBrailleTools/BrailleLogger/bin/BrailleGcodeDot.class b/NatBrailleTools/BrailleLogger/bin/BrailleGcodeDot.class new file mode 100644 index 0000000000000000000000000000000000000000..1241679657996b22a009862fa4875dde9e44cb00 GIT binary patch literal 876 zcmZ`$VNcUg6g{u&HmH>`m{W%+7-PDDOy#4757uCoENY@zLiVXE4L(v=QwqPz51L3w z_}~xlM-k3_tyKr6$-VF1ci%bZp8mQx{|VqZ9@b$gG+w2Fj^pS}nCwTdldKL~Vev3H z3Hos`J?Oui97bWLPzi%nLHRs=Nsbh(@j#(=5M{pfD_)m3woikK36OnVIXnnTNx8gH@kdF;{y(;C?k@3yd|>Y@)%ln-5?SO;&UT%Z&1P$G~&C zw{i;iJ3AKSwZjawNPNp6v`t+r5CmN$32}=PSB12{l~B2m&b31B;O-S68>eW`3RxxH z{r?CNPecg4F0i&uEsmVw-YnE3*m!)cm<}oOP4>90SlanvN@!iBkkW|0B6iV%Mh1{2~5DwAexX}Y1UQM_6fIe>=>*63C@ zReV+TiuX?czkdMwXhtY0w8w#rwR(~IA3bwYjmsib6k1!_Q*6m)@yGX8r!1p|=E;Tv zrL4o$^G>1Do%E8+WzNRN?;+4JF*_b8)Ym3+#CgyPuXoOdS1lbl{`AK2U?jpQ)4clf z2ZeICw^XPVY>ksYjkV81s^`WEyxj8sR+ySiX)&Q|+^z)(8WBjKTlN*OLZ2Q`M(1<5^BQE|c0C}RoB z47ETi@je|7g*oBFm<%-n9rAd&?$I%XvTg)<_lg zS_237>Cknfj*QV}1rHd$d{RavI=&PmKh)!ijJcIs`4gil>-d%LxhLm>eyPNoG_>0I z^VHq9A=P@MvS^xf@Z~i~nOnY0{8Wv^85KA3JZ#`m)|baLlI9|x3|?QSCKSgqZ^4Z! zpJ)CV%I}mC<}l_-A`%BX44Zjji-+XkDJ5G-U|7oMh%K5!kuDjdMZ=)op|=87XwfBs zNAVUR2gJ%a_4X9y_7$q9Q`CRp_V=8$T^4 l-W4`Z8=F%+{QX}ka{+AU3WXf?^SFg4v}caCv5RML{{c3k!1@3H literal 0 HcmV?d00001 diff --git a/NatBrailleTools/BrailleLogger/bin/GCodeGenerator.class b/NatBrailleTools/BrailleLogger/bin/GCodeGenerator.class new file mode 100644 index 0000000000000000000000000000000000000000..6731139b2a41e70d13a87fa48a064e709fea49da GIT binary patch literal 1839 zcmah~Yf~C$7(FityKFaNFq#mnAvG7!%EjCWBxw>U*c4-0ERkNb!fH1IECZ_(|5f`1 zJ9VZ%AU~?p^THMo==8(Bw|&oZp7UIGKmPsaUjQ~?DDVi(7Pjn~SumSs+i>i*f*FCi z_r{5ls2k0r#O}d+v+4-=pIA-Hc_!eE#>xUS5~RV4fDRx00>PryG+!S#4$StRaZon} zLPfi3)XPTOl6&`X#`)Fikf3;xHA{=zc7v!Z(O7ZFUUJ%2^C+w0vVdOLOh@)LIaV|Q zU#Vr9H5FF`0)9m}!ori!aHT6o+$+_5RmK0H)$orgQ=`@HGjHjSFu zRc{5pp}?K!h>(65 zvs1Kbh#)3|xF)bL3URf^%F?&bb%YRH%&cEfN=r;P)<-qG+B0Xe+T@e*4C^BvQ1FP6-f z(W_IYF}f8iEBNx?Y)#rzQD8z=SEZLp4LN)zXZ`9ErbOSREB355R(!fdH6 z_KcIW9Th*bYj*BMN-0f_vJhD~5*fi+926TMFwcfwL`4V^hv>?b)f;Tuzus1aK8>dm|qNKmEt)fmGwXH*%_kTuXnN0 zMXIU<<@82TsHdKB_RuJuREcWfVLGfZ4_wj%Z3OpRJy>;1^LXXCX9#0a@_A(pi zm_Qh*5t5|=$+ZDV7Ej!0bm^c<7hj#@Y2^%GWPD-YT)d0t=g3t;`LOQ{+Zn&q8Ty(k z!~VNn?2tb64TrEl=I%;;k1|SF8H!(Ije&v!c!W8mDKdisvOV9PvAoFY`X*Q3p-i9T y>Md9N{on=mQK5}x7TNdsfrtXnWuO$^{BaPdVF~^;B$vevJfE7;U--s@cmDw9R7?8+ literal 0 HcmV?d00001 diff --git a/NatBrailleTools/BrailleLogger/src/Braille2GcodeEncoder.java b/NatBrailleTools/BrailleLogger/src/Braille2GcodeEncoder.java new file mode 100644 index 0000000..1c10dab --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/Braille2GcodeEncoder.java @@ -0,0 +1,220 @@ +import java.awt.Point; +import java.awt.geom.Point2D; +import java.util.ArrayList; + +import javax.swing.JOptionPane; + +/** + * + */ + +/** + * Braille encoder class + * @author crocsg + * + */ +public class Braille2GcodeEncoder { + + private GCodeGenerator generator = new GCodeGenerator (); + private int page_num= 0; + private int char_cnt_line = 0; + + private BrailleGcodeEncoding encoder; + + private float position_x; + private float position_y; + + private ArrayList pagedot; + private ArrayList> linedot; + private String bufline = ""; + private String pagegcode = ""; + + private final float Braille_cell_width = 2.3f; + private final float Braille_cell_height = 2.3f; + private final float Braille_cell_padding = 6.1f; + private final float Braille_line_padding = 10f; + private boolean pageAvailable = false; + private boolean newpage=true; + + /** + * @return the pageAvailable + */ + public boolean isPageAvailable() { + return pageAvailable; + } + + + + /** + * @return the pagegcode + */ + public String getPagegcode() { + return pagegcode; + } + + + + /** + * Constructor + */ + private Braille2GcodeEncoder() { + + } + + /** + * Constructor + * @param encoder Braille Encoding + */ + public Braille2GcodeEncoder(BrailleGcodeEncoding encoder) { + this.encoder = encoder; + } + + public void startPage () + { + pagedot = new ArrayList (); + position_y = 2;//TODO avoid magic + pageAvailable = false; + newpage = false; + pagegcode = ""; + startLine (); + + + } + + public void endPage () + { + if ( ! pagedot.isEmpty()) + { + pagegcode = generator.Header(); + + for (Point2D.Float p: pagedot) + { + pagegcode += generator.moveTo(p.getX(),p.getY()); + pagegcode += generator.printDot(); + } + pagegcode += generator.Footer(); + + + pageAvailable = true; + + int n = JOptionPane.showConfirmDialog( + null, + "Page " + (page_num+1) + " chargez le papier quand l'embosseuse est disponible", + "BrailleRapSP Embosseuse Braille", + JOptionPane.OK_CANCEL_OPTION); + if (n == JOptionPane.CANCEL_OPTION) + { + // cancel print + System.exit(0); + + } + + page_num++; + } + } + + public void startLine () + { + linedot = new ArrayList > (); + for (int i =0; i < encoder.getNline(); i++ ) + { + linedot.add(new ArrayList()); + } + + position_x = 0; //TODO avoid magic + bufline = ""; + } + + private Point2D.Float getDotAbsolutePosition(Point p) + { + Point2D.Float absolute = new Point2D.Float(); + absolute.x = position_x + (float) p.x * Braille_cell_width; + absolute.y = position_y + (float) p.y * Braille_cell_height; + + return absolute; + } + + private void nextCellPosition () + { + this.position_x += Braille_cell_padding; + } + + private void nextLinePosition () + { + this.position_y += Braille_line_padding; + } + private void endLine () + { + ArrayList dots; + + // compute braille dots on line + for (int i =0; i < bufline.length(); i++) + { + dots = encoder.GetCharacterDots(bufline.charAt(i)); + if (dots != null) + { + for (int d= 0; d < dots.size (); d++) + { + int x = dots.get(d).x; + int y = dots.get(d).y; + + linedot.get(y).add(getDotAbsolutePosition(dots.get(d))); + } + + nextCellPosition (); + } + + } + + // store braille absolute dot on page + for (int l = 0; l < linedot.size(); l++) + { + pagedot.addAll(linedot.get(l)); + } + + nextLinePosition(); + } + + private void addCharToBuffer (char a) + { + bufline += a; + } + + public void Open () + { + startPage (); + } + public void processChar (char a) + { + if (a == '\n') + { + endLine (); + startLine (); + } + else if (a == 0x0c) + endPage (); + + else + { + if (newpage) + startPage(); + addCharToBuffer (a); + } + + } + + public void Close () + { + endLine (); + endPage (); + } + + + + public void requestNewPage() { + newpage = true; + pageAvailable = false; + startPage (); + } + +} diff --git a/NatBrailleTools/BrailleLogger/src/Braille6GcodeEncoding.java b/NatBrailleTools/BrailleLogger/src/Braille6GcodeEncoding.java new file mode 100644 index 0000000..e457315 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/Braille6GcodeEncoding.java @@ -0,0 +1,141 @@ +import java.awt.Point; +import java.util.ArrayList; + +/** + * + */ + +/** + * @author lenovo + * + */ +public class Braille6GcodeEncoding implements BrailleGodeEncoding { + private static final BrailleGcodeDot[] dot = new BrailleGcodeDot[] { + new BrailleGcodeDot('a', new int[] {1}), + new BrailleGcodeDot('b', new int[] {1,2}), + new BrailleGcodeDot('c', new int[] {1,4}), + + + + new BrailleGcodeDot('d', new int[]{1,4,5}), + new BrailleGcodeDot('e', new int[] {1,5}), + new BrailleGcodeDot('f', new int[]{1,2,4}), + new BrailleGcodeDot('g', new int[]{1,2,4,5}), + new BrailleGcodeDot('h', new int[]{1,2,5}), + new BrailleGcodeDot('i', new int[]{2,4}), + new BrailleGcodeDot('j', new int[]{2,4,5}), + new BrailleGcodeDot('k', new int[]{1,3}), + new BrailleGcodeDot('l', new int[]{1,2,3}), + new BrailleGcodeDot('m', new int[]{1,3,4}), + new BrailleGcodeDot('n', new int[]{1,3,4,5}), + new BrailleGcodeDot('o', new int[]{1,3,5}), + new BrailleGcodeDot('p', new int[]{1,2,3,4}), + new BrailleGcodeDot('q', new int[]{1,2,3,4,5}), + new BrailleGcodeDot('r', new int[]{1,2,3,5}), + new BrailleGcodeDot('s', new int[]{2,3,4}), + new BrailleGcodeDot('t', new int[]{2,3,4,5}), + new BrailleGcodeDot('u', new int[]{1,3,6}), + new BrailleGcodeDot('v', new int[]{1,2,3,6}), + new BrailleGcodeDot('w', new int[]{2,4,5,6}), + new BrailleGcodeDot('x', new int[]{1,3,4,6}), + new BrailleGcodeDot('y', new int[]{1,3,4,5,6}), + new BrailleGcodeDot('z', new int[]{1,3,5,6}), + + new BrailleGcodeDot(' ', new int[]{}), + new BrailleGcodeDot('.', new int[]{2,5,6}), + new BrailleGcodeDot(',', new int[]{2}), + new BrailleGcodeDot('?', new int[]{2,6}), + new BrailleGcodeDot(';', new int[]{2,3}), + new BrailleGcodeDot(',', new int[]{2,4}), + new BrailleGcodeDot('!', new int[]{2,3,5}), + new BrailleGcodeDot('(', new int[]{2,3,6}), + new BrailleGcodeDot(')', new int[]{3,5,6}), + new BrailleGcodeDot('\'', new int[]{3}), + new BrailleGcodeDot('-', new int[]{3,6}), + new BrailleGcodeDot('/', new int[]{3,4}), + new BrailleGcodeDot('*', new int[]{3,5}), + new BrailleGcodeDot('+', new int[]{2,3,5}), + new BrailleGcodeDot('=', new int[]{2,3,5,6}), + new BrailleGcodeDot('0', new int[]{3, 4, 5, 6}), + new BrailleGcodeDot('1', new int[]{1, 6}), + new BrailleGcodeDot('2', new int[]{1, 2, 6}), + new BrailleGcodeDot('3', new int[]{1, 4, 6}), + new BrailleGcodeDot('4', new int[]{1, 4, 5, 6}), + new BrailleGcodeDot('5', new int[]{1, 5, 6}), + new BrailleGcodeDot('6', new int[]{1, 2, 4, 6}), + new BrailleGcodeDot('7', new int[]{1, 2, 4, 5, 6}), + new BrailleGcodeDot('8', new int[]{1, 2, 5, 6}), + new BrailleGcodeDot('9', new int[]{2, 4, 6}), + + new BrailleGcodeDot('à', new int[]{1, 2, 3,5, 6}), + new BrailleGcodeDot('â', new int[]{1, 6}), + new BrailleGcodeDot('ç', new int[]{1,2, 3, 4, 6}), + new BrailleGcodeDot('è', new int[]{2, 3, 4, 6}), + new BrailleGcodeDot('é', new int[]{1, 2, 3, 4, 5, 6}), + new BrailleGcodeDot('ê', new int[]{1, 2, 6}), + new BrailleGcodeDot('ë', new int[]{1, 2, 4, 6}), + new BrailleGcodeDot('î', new int[]{1, 4, 6}), + new BrailleGcodeDot('ï', new int[]{1,2, 4, 5, 6}), + new BrailleGcodeDot('ù', new int[]{2, 3, 4, 5, 6}), + new BrailleGcodeDot('û', new int[]{1, 5, 6}), + new BrailleGcodeDot('ü', new int[]{1, 2, 5, 6}), + + new BrailleGcodeDot('¨', new int[]{1, 3}), // Majuscule NatBraille + new BrailleGcodeDot('`', new int[]{3, 4, 5, 6}) // Chiffres NatBraille + + }; + + private final int nrow = 2; // number of row in braille encoding + private final int nline = 3; // number of line in braille encoding + + + + + public Braille6GcodeEncoding() { + super(); + // TODO Auto-generated constructor stub + } + + /* (non-Javadoc) + * @see BrailleGodeEncoding#GetCharacterDots(char) + */ + @Override + public ArrayList GetCharacterDots(char a) { + //TODO make this fast + + for (int i =0; i < dot.length;i++) + { + if (dot[i].getCar() == a) + { + ArrayList Braille = new ArrayList(); + for (int d = 0; d < dot[i].getPos().length; d++) + { + int x = dot[i].getPos()[d] <= nline ? 0 : 1; + int y = dot[i].getPos()[d] <= nline ? dot[i].getPos()[d] - 1 : dot[i].getPos()[d] - 1 - nline; + + Braille.add(new Point(x,y)); + } + + return Braille; + } + } + return null; + } + + /* (non-Javadoc) + * @see BrailleGodeEncoding#getNRow() + */ + @Override + public int getNRow() { + return nrow; + } + + /* (non-Javadoc) + * @see BrailleGodeEncoding#getNline() + */ + @Override + public int getNline() { + return nline; + } + +} diff --git a/NatBrailleTools/BrailleLogger/src/BrailleGcodeDot.java b/NatBrailleTools/BrailleLogger/src/BrailleGcodeDot.java new file mode 100644 index 0000000..94012a5 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/BrailleGcodeDot.java @@ -0,0 +1,52 @@ + + +/** + * + */ + +/** + * @author lenovo + * + */ +public class BrailleGcodeDot { + + + private char car; + + public char getCar() { + return car; + } + public void setCar(char car) { + this.car = car; + } + + private int[] pos; + + public int[] getPos() { + return pos; + } + public void setPos(int[] pos) { + this.pos = pos; + } + + + /** + * + */ + public BrailleGcodeDot() { + // TODO Auto-generated constructor stub + } + /** + * @param car + * @param position + */ + public BrailleGcodeDot(char car, int[] position) { + this.car = car; + this.pos = position; + } + + public BrailleGcodeDot(char car) { + this.car = car; + + } +} diff --git a/NatBrailleTools/BrailleLogger/src/BrailleGcodeEncoding.java b/NatBrailleTools/BrailleLogger/src/BrailleGcodeEncoding.java new file mode 100644 index 0000000..f10c434 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/BrailleGcodeEncoding.java @@ -0,0 +1,18 @@ +import java.awt.Point; +import java.util.ArrayList; + +/** + * + */ + +/** + * @author lenovo + * + */ +public interface BrailleGcodeEncoding { + + public ArrayList GetCharacterDots (char a); + public int getNRow (); + public int getNline (); + +} diff --git a/NatBrailleTools/BrailleLogger/src/BrailleLogger.java b/NatBrailleTools/BrailleLogger/src/BrailleLogger.java new file mode 100644 index 0000000..6de2fb3 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/BrailleLogger.java @@ -0,0 +1,71 @@ +import java.awt.geom.Point2D; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Main program + */ + +/** + * @author lenovo + * + */ +public class BrailleLogger { + + + ArrayList braillepoints = new ArrayList (); + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + System.out.println ("; BrailleRapSP GCODE generator"); + int arg = 0; + for (String s: args) + { + System.out.println(";" + arg); + System.out.println(";" + s); + } + + if (args[0] != null) + { + FileReader fr; + Braille2GcodeEncoder encoder = new Braille2GcodeEncoder(new Braille6GcodeEncoding()); + try { + fr = new FileReader(args[0]); + + int i; + while ((i=fr.read()) != -1) + { + encoder.processChar((char) i); + if (encoder.isPageAvailable()) + { + System.out.println(encoder.getPagegcode()); + encoder.requestNewPage (); + } + } + + encoder.Close (); + if (encoder.isPageAvailable()) + { + System.out.println(encoder.getPagegcode()); + + } + fr.close(); + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + } + } + +} diff --git a/NatBrailleTools/BrailleLogger/src/GCodeGenerator.java b/NatBrailleTools/BrailleLogger/src/GCodeGenerator.java new file mode 100644 index 0000000..944f910 --- /dev/null +++ b/NatBrailleTools/BrailleLogger/src/GCodeGenerator.java @@ -0,0 +1,67 @@ +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +/** + * + */ + +/** + * @author lenovo + * + */ +public class GCodeGenerator { + + + public String Home () + { + return ("G28 X\nG28 Y\n"); + } + public String Speed() + { + return ("G1 F8000\n"); + } + + public String Position() + { + return ("G90\n"); + } + + public String Motoroff () + { + return "M84\n"; + } + + public String Header () + { + String gcode = ""; + gcode = Home (); + gcode += Speed (); + + return gcode; + } + + public String Footer () + { + // TODO avoid magic + String gcode = "G1 X10.00 Y600.00\n"; // eject page + gcode += Motoroff (); + + return gcode; + } + + public String moveTo(double x, double y) + { + DecimalFormatSymbols sym= new DecimalFormatSymbols (); + sym.setDecimalSeparator('.'); + DecimalFormat decimalFormat = new DecimalFormat("##0.000", sym); + + String gcode = "G1 X" + decimalFormat.format(x) + " Y" + decimalFormat.format(y) + "\n"; + return gcode; + } + + public String printDot() { + + return ("M3 S1\nM3 S0\n"); + + } +} diff --git a/NatBrailleTools/simpleJavaGrblStreamer/.classpath b/NatBrailleTools/simpleJavaGrblStreamer/.classpath new file mode 100644 index 0000000..fd7ad7f --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/.classpath @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NatBrailleTools/simpleJavaGrblStreamer/.project b/NatBrailleTools/simpleJavaGrblStreamer/.project new file mode 100644 index 0000000..1ff8812 --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/.project @@ -0,0 +1,23 @@ + + + simpleJavaGrblStreamer + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.core.resources.prefs b/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..e9441bb --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding/=UTF-8 diff --git a/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.jdt.core.prefs b/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..60105c1 --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/NatBrailleTools/simpleJavaGrblStreamer/LICENSE b/NatBrailleTools/simpleJavaGrblStreamer/LICENSE new file mode 100644 index 0000000..3ffdaba --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Will Winder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NatBrailleTools/simpleJavaGrblStreamer/README.md b/NatBrailleTools/simpleJavaGrblStreamer/README.md new file mode 100644 index 0000000..a26b741 --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/README.md @@ -0,0 +1,9 @@ +# simpleJavaGrblStreamer + +A minimal Java application to stream a file to GRBL as quickly as possible. + +Uses a blocking queue to send events from the serial event thread to the main thread which is sending the file. + +Build with "mvn compile assembly:single" + +Run with "java -jar " diff --git a/NatBrailleTools/simpleJavaGrblStreamer/pom.xml b/NatBrailleTools/simpleJavaGrblStreamer/pom.xml new file mode 100644 index 0000000..9da9675 --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + com.willwinder.sjgs + simpleJavaGrblStreamer + 1.0-SNAPSHOT + jar + + + org.scream3r + jssc + 2.8.0 + + + + UTF-8 + 1.6 + 1.6 + + + + + maven-assembly-plugin + + + + com.willwinder.sjgs.simplejavagrblstreamer.SimpleJavaGrblStreamer + + + + jar-with-dependencies + + + + + + diff --git a/NatBrailleTools/simpleJavaGrblStreamer/src/main/java/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer.java b/NatBrailleTools/simpleJavaGrblStreamer/src/main/java/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer.java new file mode 100644 index 0000000..87bc5c8 --- /dev/null +++ b/NatBrailleTools/simpleJavaGrblStreamer/src/main/java/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer.java @@ -0,0 +1,171 @@ +package com.willwinder.sjgs.simplejavagrblstreamer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.LinkedList; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; +import jssc.SerialPort; +import jssc.SerialPortEvent; +import jssc.SerialPortEventListener; +import jssc.SerialPortException; + +/** + * + * @author wwinder + */ +public class SimpleJavaGrblStreamer { + static int GRBL_BUFFER_SIZE = 125; + + public static void main(String argv[]) throws SerialPortException, IOException, InterruptedException { + if (argv.length != 3 && argv.length != 2) { + System.out.println("Arguments: "); + return; + } + + String commPort = argv[0]; + Integer baud = Integer.parseInt(argv[1]); + InputStream file = null; + if (argv.length == 2) + file = System.in; + else { + file = new FileInputStream(argv[2]); + System.out.println("Streaming file " + argv[2]); + } + + System.out.println("Streaming to port <" + commPort + " : " + baud + ">"); + SimpleJavaGrblStreamer s = new SimpleJavaGrblStreamer(commPort, baud); + s.send(file); + + System.out.println("Done senting file."); + } + + String commPort = null; + Integer baud = null; + + private SimpleJavaGrblStreamer(String commPort, Integer baud) { + this.commPort = commPort; + this.baud = baud; + } + + private void send(InputStream f) throws SerialPortException, IOException, InterruptedException { + BlockingQueue commandComplete = new LinkedBlockingQueue(); + + SerialPort serialPort = new SerialPort(commPort); + serialPort.openPort(); + serialPort.setParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, true, true); + + Thread.sleep(5000); + + serialPort.addEventListener(new GrblSerialListener(serialPort, commandComplete)); + GrblSerialSender sender = new GrblSerialSender(f, serialPort, commandComplete, GRBL_BUFFER_SIZE); + sender.send(); + serialPort.closePort(); + } + + private static class GrblSerialListener implements SerialPortEventListener { + SerialPort serialPort = null; + BlockingQueue completedCommands; + StringBuilder inputBuffer; + private GrblSerialListener(SerialPort port, BlockingQueue completedCommands) { + this.serialPort = port; + this.completedCommands = completedCommands; + inputBuffer = new StringBuilder(); + } + + @Override + public void serialEvent(SerialPortEvent event) { + if(event.isRXCHAR() && event.getEventValue() > 0){ + try { + byte buffer[] = serialPort.readBytes(); + for (byte b: buffer) { + if (b == '\n') { + //System.out.println("Received command: " + inputBuffer.toString()); + if (inputBuffer.toString().startsWith("ok") || inputBuffer.toString().startsWith("error")) + completedCommands.add(1); + inputBuffer.setLength(0); + } else { + inputBuffer.append((char)b); + } + } + } + catch (SerialPortException ex) { + System.out.println(ex); + System.out.println("serialEvent"); + } + } + } + } + + private static class GrblSerialSender { + InputStream file = null; + SerialPort port = null; + Integer currentBufferSize = null; + Integer maxBufferSize = null; + + BlockingQueue completedCommands = null; + LinkedList activeCommandSizes; + + private GrblSerialSender(InputStream f, SerialPort sp, BlockingQueue completedCommands, Integer activeBufferSize) { + file = f; + port = sp; + maxBufferSize = activeBufferSize; + currentBufferSize = 0; + this.completedCommands = completedCommands; + activeCommandSizes = new LinkedList(); + } + + private void send() throws IOException { + // Java 8 + //try(Stream lines = Files.lines(Paths.get(file.getAbsolutePath()))){ + // lines.forEach(s -> sendLine(s)); + //} + + BufferedReader br = null; + try { + String sCurrentLine; + br = new BufferedReader(new InputStreamReader(file)); + while ((sCurrentLine = br.readLine()) != null) { + sendLine(sCurrentLine); + } + } finally { + if (br != null)br.close(); + } + } + + private void sendLine(String s) { + // Wait until there is room, if necessary. + while (maxBufferSize < (currentBufferSize + s.length() + 1)) { + try { + //System.out.println("waiting for room.... active command count: " + this.activeCommandSizes.size()); + + // Wait for a command to complete + completedCommands.take(); + currentBufferSize -= this.activeCommandSizes.removeFirst(); + } catch (InterruptedException ex) { + Logger.getLogger(SimpleJavaGrblStreamer.class.getName()).log(Level.SEVERE, null, ex); + return; + } + } + + try { + System.out.println("Sending command: " + s.trim()); + //System.out.printf("."); + this.port.writeString(s.trim() + "\n"); + int commandSize = s.length() + 1; + activeCommandSizes.add(commandSize); + currentBufferSize += commandSize; + } catch (SerialPortException ex) { + Logger.getLogger(SimpleJavaGrblStreamer.class.getName()).log(Level.SEVERE, null, ex); + return; + } + } + } +} diff --git a/NatBrailleTools/simpleJavaGrblStreamer/target/classes/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer$GrblSerialListener.class b/NatBrailleTools/simpleJavaGrblStreamer/target/classes/com/willwinder/sjgs/simplejavagrblstreamer/SimpleJavaGrblStreamer$GrblSerialListener.class new file mode 100644 index 0000000000000000000000000000000000000000..184e392b78a84d75ac222e76dfd2d20e2641d52b GIT binary patch literal 2585 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