From d33ebbfd2598acc682d26f5576a8f84c489558a9 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Mon, 26 Feb 2018 21:29:40 +0100 Subject: [PATCH] Updated zwave libs with upstream jserialcomm implementaion --- Hal.iml | 34 +- .../lib/netty-transport-jserialcomm-1.0.0.jar | Bin 0 -> 15547 bytes ...SNAPSHOT.jar => wzwave-0.0.4-SNAPSHOT.jar} | Bin 163818 -> 163426 bytes .../AbstractNettyChannelInitializer.java | 72 --- .../netty/NettyJSCChannelInitializer.java | 44 -- .../netty/NettyRxtxChannelInitializer.java | 45 -- .../netty/NettyZWaveController.java | 467 ------------------ .../channel/jsc/DefaultJSCChannelConfig.java | 224 --------- .../netty/channel/jsc/JSCChannelConfig.java | 233 --------- .../netty/channel/jsc/JSCChannelOption.java | 40 -- .../netty/channel/jsc/JSCDeviceAddress.java | 45 -- .../netty/channel/jsc/JSerialCommChannel.java | 181 ------- .../io/netty/channel/jsc/package-info.java | 20 - .../hal/plugin/zwave/HalZWaveController.java | 69 ++- .../plugin/zwave/HashMapPersistentStore.java | 81 +++ 15 files changed, 158 insertions(+), 1397 deletions(-) create mode 100644 plugins/zwave/lib/netty-transport-jserialcomm-1.0.0.jar rename plugins/zwave/lib/{wzwave-0.0.4-ziver-SNAPSHOT.jar => wzwave-0.0.4-SNAPSHOT.jar} (72%) delete mode 100755 plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/AbstractNettyChannelInitializer.java delete mode 100755 plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyJSCChannelInitializer.java delete mode 100755 plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyRxtxChannelInitializer.java delete mode 100755 plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyZWaveController.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/DefaultJSCChannelConfig.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/JSCChannelConfig.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/JSCChannelOption.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/JSCDeviceAddress.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/JSerialCommChannel.java delete mode 100755 plugins/zwave/src/io/netty/channel/jsc/package-info.java create mode 100644 plugins/zwave/src/se/hal/plugin/zwave/HashMapPersistentStore.java diff --git a/Hal.iml b/Hal.iml index 9a7d7c89..d6b3cb19 100755 --- a/Hal.iml +++ b/Hal.iml @@ -19,22 +19,6 @@ - - - - - - - - - - - - - - - - @@ -51,7 +35,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/plugins/zwave/lib/netty-transport-jserialcomm-1.0.0.jar b/plugins/zwave/lib/netty-transport-jserialcomm-1.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..c2bb9a899adbb01e29cd2b732790f204afc236c5 GIT binary patch literal 15547 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 literal 0 HcmV?d00001 diff --git a/plugins/zwave/lib/wzwave-0.0.4-ziver-SNAPSHOT.jar b/plugins/zwave/lib/wzwave-0.0.4-SNAPSHOT.jar similarity index 72% rename from plugins/zwave/lib/wzwave-0.0.4-ziver-SNAPSHOT.jar rename to plugins/zwave/lib/wzwave-0.0.4-SNAPSHOT.jar index b3d2e8d8b02058cb838404ac029ca85b6eb27d43..451faad9ab5a2b1097d21bd93ee38b5470416ec8 100644 GIT binary patch delta 28655 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

A0zrfNWoTb z70688R_xx(6iGupD~dU509vefbCjQ);0+h)*ff~r;(%XohM>W4_?(b5X%XAVGB$yI zS8CCA0yS!D+X5F#aK@=gn8(RPk#+(&=KGe00+0VEZ%s^@vqz*Fh4W*U3 zqI3N=f86M%#TOVYR1V&SeAJkPqoc;&F|)(IzD|Ya@Uw)#U(HvmhX(a`mJEc5a_!FJz7q{M^iPxH)%*f5J&td zRs!Cd>O%Gz@rgYeeCEu)?XSr=-8`W10u1z2JrvydIro}W9);QCvWEJzBWoi)kSk|D zK)Ia`HBG_o<9eEf@f{VZ)o=~;o`c^_waqI~X9|fAJ-K3k7{2UO zZ1%<7zS|tV-c*t?a$es>(?Q{Zu7lchKog;>WP9~7UgX)=Mb6xLL-Ps%(N(tnY>ZwP zH?+exlHNTa>vwWC_MtW@-SJff?Ak{rj6w7l88;#$gDZulr(Sak>PNewUyqVoR|%Pp z3S&!JEx{xek8FlmA8)KTzYdn@n65fVaTxO}932bfBP%KbOS!qYj8+zY{`fh)pP zQJi&bN~~C{=r#W2M-!nASaE2&RbXZqF{&=Tx3;~ORyKW27Pyl z0!-#^Sa+70@H0di7h4z~=z~12tKeovE&2_&EGB(GFi^9D{M!qC0Db*6+}b5;I@>Zz z%jfaI7@GOG0fKXbADNhJ8a5dW zswX0jUg)%V(tWUnhghKY4?0;qd7YI8psh8pqOl6!EMc#uyDTzp z>c%cB&28ofJ4K{XdBgCn&2l?D%7128aI-6m&f}Z zAtp6fc5a*-W<$0)kBW?@Ge;xTtA$V-B!Usd2g zKRK4J74A$mM}E8@p_;)PxQl}CaD!wyPVjLW*cYa8aLfBo{NVh}>sCbm;p z-AG#q;1hR9Apv|NT|n5m&PgAM-|4ZglwqLyO{MQv{Y5@<40))*r}020-d(}9GjgWk zURC|HiDeg@-4pNgWZLRBS5w4yD&NX1$WM9Pm?K8VVP6}?P6yn-T3K}Put%aazZB08 zE|`C9s`=)kURe>hF|v!kcM`3U;-q<-ARCuR z`Nmb^NLKZ7g4VKN52VcE?;31LOl$_}8RO3i>E7dFM{K|1MFuE6KBM3i5}$yDx)gS7 zJ7XpDP+g2XCp?&&^&fD;`6O*SB|E_j`FM%=ynyu=eOZ!v)ACMXD<-|b{sP9m1?h*N zA3BkmoV^IR!b_gHqIyQBKaKwkYFfj5;2ggyfk1YhlUnpnxhBLp-2Be8blgr!yxoOR z+tGIGlZw1OP%>4(h)p8pjn=-SobLyPE#S2^l&>LK**7M|$`l(C=@=6OS+1|nELl0m zTa#{rX7$8hiWsk)t`}d0lCb&6K7196o`VKKQCA6IHe!#>6whEPv+|jhPmeeDgwu;i zET(WPm#dw)TR_$kB01sUS zcgdR(<<w9k?`&j}HW@}dh_EhF=*?B0suKOYdx)Vw zx@$0arLWNumy5s&or`cg41n*iQ|tGA zBRwZAy-~*)NC6_71;G{+QW5jTWe9N-J{z<4;vBk;1sWd zR5jY>4A`L!Ah8^&DN9h>nIp>~rNPr8n!6U?E<$=wp;!qezJJQiyY{=f;f8I>HuFcvLd|dl6#Uys1T; zt8aXlC+rEU1>a7fiAMLwPE()^qCG}TcNm1SJ>Js!lXmqEp*hEf;It6F49{NyUdBYL zSJIWg=j^??T|blbeWUnTN4UF$Rw@ruP27`(hCnBr#tON}wsO({$AdPUt%KuOQpJO| zD@y%zUr5>(9b7JQ2x#@jFLJ(79S))2+n)|;O;E`(uca6hD8xP0nkJXQhxT&uIlmRc zd(t{32?gHzpEgVTYqn*B+mX#iZ>M@@IZ(&;t27c8UHt@{v-ZxCn9iD=}%&_w z-M$1*9$=>GpUmCb`VQ*dQ4JWG-8xL@x62FA^zP~o6A%mQP+usHMOGN}TO{j}l0A zQR8pCOdNPXn=8ui;ZOPVEoE~B5s0SuC%mzH-`@lA=OX1#Q1$)csPc7pW%QP)%SQcRD;t4Q4JtSK}4_ie^=of0|OAv;LjvXzdilSl|m-> zPDwX}KxrZcw|HMCz-)m(!gYp!?r-|R!QYqlp9RVYM1ufl0Muyfsjo_5z2RV*Bc`d$ z6qDKDCnqk5V7S<%sOUSw;M2sDafMNL7RPiLqkk$)j)ipcKL#9{S zysGAYNees61Z#*`*_m&#ntHlFT?R>?0N!4Al)=Q8Vz&sTG;*ZH23UV;x!@F`*MFam zW{VxOBoCLR1W;u~o8WU`bW+?oN+hW{t4k7K)U<}VW3^zLYq*o54^#*9Vh>Su6m1${ z(@>4mXK1_V_CD-}A|l{ux^DSHdttAcSzq0hF0N0pCUNHk8;)jYXU88fK2x0|bT)q4 zJ`v*~T=gOv!>Dyc+}QZR@wKx>#%yHt2V4@B!s@Lw9-wqP!t&&kv9%H(Z;vyl!wR`N zBO|=m7nV6~{EjX=qqXD$`>GCE&)S8*riU$OhRd{@Kl-ppfEoxj%Mg(YVW46=; z9QX>NRB?{0z7%YXBU}&5@r8+%6EKRic_RBBH=C)Hk>Hz7@DQ!4UxN2#3R2hPQl)cg z+n?haAOHr|x+>{(VHGVL5qMNvIErR+tJU3+*~~^&yw0)98LIqpXB`z+!}q*PJ6-i2 zeQ3%y#gR$2%#d+^)NB<>JX}S=#8W|shZBZ|Tfjjx;44(ydV|S}iiU)6A?NkZZ}yaZ z+z%Cn-(p81Y%D7-fvufr?I0~34sfh||>y*@yWmyvk27mh@mEwH70Z92IpWU*^3F#njEY#ROS zH*#CCWN0_s;Tw<8`dzeCqtn*e&61mAf^{u}LzCN8o}$I}gZ2sY(v&k7adK6hV%lA9 zlk07vX1V2o)d98o&GNImLM_kX3$tRYpe8^IG|j4!fuA7eKB13^)7gsG_8_;X0$`pa zkEuO4QW@F)rk~~8SQK;R-o$9`4>aU?CizysOXPfQySBsx1^MdE@aq)NI!xG)_F1)g zxyHZA;xm+iy8*v4Pc49dzI5Pn7 zE(z2ono-@u0V-0FH|(G{pz^SYIao*JoQ~=k&O3(Qf@;@4vm~--DlGdv}AAC zb5WXn$K1MOL^V5MM2+kI!9}aq3896!UOz+&&A1AIp3XTEG`12f7n_t(e0CCLp3Yek zb#sxEGQYoU&wnj%`zdNYCnSbsG_47Ew2NNjX>4|43%*F~d2ru*1Q!bEKUnI;eT@1s z#nrG}*>8!+_lu4jGBo>$cS%T66`x+3&RgzP$7#dpvM9~ba|J**wAc3L&ubSw; z*H3?6Oq2k2W;1&eH@6ZE1NB)EEJ4JuCA5M_zo(#bXt^pV(JMqr#yL?0q3+G$RSX<_ z1(3qml3wAfX_`DDYze|4D?sYbdLs@o8gYg~vai$mPv7(9l-JjTXJxRW;ejNP6$u7* zMe9K($QH%^M7E^fMDW$npx7W2%qzLecqM}Ag>pbpJ9SN$mGOADKP2i0e9a!@ls=>s zA8DL3*Piv|qyl|)3u3tT4)uM#UeDq>h$A2JdjEpCX2H6=vAQF@=KCWyYyvNTZ9$6+ zx!i9nn;7DZ4BF7*@;~ne{3=?>gC)DRRd>Y<`PTHdgQ{L_Sxco&>Mi|@pgtu;6p-@x zYEc44(6g#F9isyow10j2w00X>7{H_MqpgL@2d!iv$gk&fAXkYMX&pY;G;Db&$dtYH z61+XR%G>oRcQ_~DAX0Iii}Ny(%%|8)_S+ZYZaV0o%QXMul5eE)K@_gFwbTA<3gQHQ zF_;arT{|N`?iLS1>4!BT6Bq>sTf?~Z8-LUSYH0Fb2_Jt#qpgdGg)X7qB3PmRRtwnh`H-Dg5~C;kXsCVp5v z(`F#(RYiKG;hAbLz@U@}Z|-YqdNt4ZNI@SSu5uL^I9GOCI<)Rwu=|l5sc4wJf)48q zP`S@k_R0JM-%(jLtHD_9VWjk3GDV-e5a-7ZEVZ=BIpa6y`~fl2G2QCopUg+U`wlV1 zIW6Mb4U1oE=Njx_fIs99R2dEvVB{$qPY)BT%G!yDu+At?=#CE|#@+WBbUvecI|< zyY|StjJ4>{NQ)!!1&-CoJmfJ-z&f{InT!}D!C0RQ zUjmRM8n9qoc()^qiNJe|{&{phA)IVO|A9xC{HgW)51QcLV$MH@#(%bXDqxop1Pq{4 z58h8>eqPv$dW3+QC5W;b+(e~^RrUj1Hk>2~d>Sngj83PRB?V}1%+4~|Aq!TuJ)_nB zsh!SozRkEs7Z)S4k-27IVL|uIQBQBxwn?|WP49K`+r?xyFmuEl;?@5#`{BHOjQ0R= z&U^61*U4}D6_x}dP_p*OuoVMx=Mc~kNP>u6eI-WBynQ@i*opw8ZJk3T*6*Dd!xETB z3|km-4agZxz<$xG*o^2<39fqFafhC|G_Jv=Hq8ybGtB4>#qVI9z+WBas>0UqyJ$k- z_A$ZvGD2cSw{#kY*$^+hK)19V#_MfKRy%|o=FRQM*sryw5t;3RIBRpW9RYA*05HfL~sUVt5s z7RgC+Mq5Mk<0Z2pi5Af4e4lDIFE`2I5`}`esO?3Nvp`Il0=@!Cu^L`vbIA!(RRv|NLzq zJRnjC*XJ@H7B=H19~QL%2F0zjb~6!|q@MyIK)%O`;W057mEkcmIDx!eF)5O`2Gy=1 zgIJsvj=;d+Ggd+4a-=7;>DJ@`KjcKABXlrNskFGRcL+Myw;`n(WyH`X8SVV}*l==# zISOG*d{rV7Rkt69@PJ#di2HLcQ>n7$I>|ec-#-Itlu>Vwr*&v8VYqdi1WlW-N%0M; z2Na8h?E7!EVvrogRf5;?M?Of=I-%eNMLK5rLVRUbaq9G`{wbZBg?ai@B+UZz?)-B&II-{*5FgS9WEDJ#MG3(?$L+nwdcs){@ zZ^1Sxp0&zZ6NiYBa%Dlv2t#7F{z_sR6XzH&EghY$NGfAc#`WF{L^y@nmpo+Ovtvn1 zxM^vNzleVvZEcx@-NjzwV}aA9FulDbR)Sp>ncC}d!a4Ki4NF#;-wX<0tX7!cT>6Mz zjU*|yPam2>KLa@XQCV%*B%v%{2>Jgn13@lF=0Suy|h3fH;614-$u^)N;KgwPb@Gq(>Bn zUB~=faQkpCMv5$1)S!>)x(lf9kcNh2u_W8BBo8x$x~f#NjeCBMEY+Q@c&o?6bf80l zZHfXmWk5mk7EQ}=sx_E8uEY?Tf-`QukCG$wIJ(W}TSAGBTzRzV=i;IuMpqAw6Egf8 zkfJ8d13X}Qv-XW%=3R51TAp%M`kbjzJmeI`n9r+Z%GR)F(3nS$5tfr}L7?ZU}|6v|VuY zF)S^+g8Il__1s5p59zo7ZVN>6zNsa-JK5-&vMd03E=+F)MfkAEn4YbOrKdXONU01f zp%sg@#dq^7n&Req$@tO_TV|9gTqAD{85cA9){D{}aa_x-{N)dFLpKtX>Y=Ky1L+Bb zOgN}8cRH~%(xZ8_C*$QvMJ>RzBx|xRit-W1k)=<`bnN8p`#RT3qpU8~AIY=$hMuq$ zJ$eB`S)t$95|LH=ID@5@j_Vr>9W`hah^R8YQFM}pW;LMVwEsDAQ8&fMOAL?t4?=%H zX_G2$Zs8$Bh>oh^`TUtySWJievy3bWb!56N-Y}C8j%_Lx3g)D%gVvo+`KO{#Ybss7 z2K&rgnMSOaT9viZa-1j|^5!L&Ayr{|QIh*A z!2;gnu^9#@+fOpv*WZEh8Me|K5w;7KuWax(aY}ODgI5^nLPmDqmZ?M3rUNM25KUxJ z!ZX-qhSkx4gFJ1EWpTJy4n;rBbOJi~Y;TvYbGX|C@T3t6(usC-R(6snjx0ldRt)q3 zN+Z9n4c)`lQA50rAmYrC-X3IhSjzqa?T#*U*VnEiJ~pt@{pf|(aJ#xfOm$cuv!TdB zD-VYrB^GhTj4Yi6v42R{`{-1Ko&e+V6OBw^jMG$zC4~M3j97i^#JLQCr)Q$^6Oq5u zY|))(0!g2KX9x6^VB|eHII2VimJ>q8JGO2M)5k zT?AghN)vqJA4dk#OZXKVd495J+7)T?>vNHmQRKB@9{L^C!7z>IC+r&uo)s8%fWVba zZmBivXNLU=tND%?R*KbhL=(p>O#%&&kU5gDlj@e8b4;}Kl}o7lO!#RmG^AB?^bM7v zQAxCQ>D6=NBw^V=ZbxF1Ud1-*CA^%tl-bYxhp^xd)yU-esz>pc>E9xu_|SP8S3{4f z!NRInHr@(7R)=xInwM7eZ-jsXK(B*yd+>LSEA2~hY?N-I#`vm7J8!ixy^$Z6pI+jE zziVE3JrasZ)@EWkct|1Uoa~g=OZZ|A-n>;ue;*Pqzl8NR3=_WDf%aAnvojX9I3H1r zsheGCdK``(ne&U{U@%cq(325~#!I@FpwQloHc`r-Yq++?8diUt%7lY7FN zZ*%v#O@23iwi!?V*jZ{Sgj0S=ud+BW^mQ>`!_qBO@P`$CSNk%F!REDs07`lijkUUQs%=6ipf^<5p6TrHH%lHd1$$I4p z3w(OtN@TjOIhsv9n?_u7`##uETtw;!|q1ezc z*tudF;1cynOSJhWXJC=Kx?D<_aMh}kfN;Xr=oW?MsdR9Zh> zdqT-CO_{e`lZhoqZW&8cW$d!g-gjByx5R(1Qr=93NjYN7r8tA<{m zftaYBv8$96kW3zitCtBu(KV5U-R2un6d%)XY~IT+T+x82A3ud%ni|4OMJ{3^`g|V^ z?SBqO*GB=1i6CbuV;8QObU#i;oS*H2f33c~^7W@VOMToYJ9`6JFWnIbx67ARQ*I2~=(3B)eXW?k1U>^c-JCQq-x=<|i|Jn4VtBeX_3 zcpP(^5x1OBsI|@lZf!%D=q>b}?WB4~kB7|yqX{P$XA@6MEG0yaZ+t` z`7;TI04>Ffi|7pF~z7j@Ls$jPc}w%6ccbRGvQKc)`WzM21CwR#DP*WcjoYg*=GHg3Gn2LduYPosjX%W{sex7%O> z4K{#^#ojGXrq+{;-&kY?A6(?W9Y0R)(*=Z@W;d31wA9rIGc@Rpknt-D&m4T$u*TLS zxc=2|#1v_)@rf<{WP)nQJ%jlvW=B^yT`ahP#xjpnQPv>rEG=?~3TK};Q*FLcm?vb} znMxn}=@R;p+z-AB$tZ}N_TYvF%=v1%%G(Hl$`knzcd2>R1@DM+QP;z??O%23MX<*F z6Lu5j>Wy!W?&n5e`=P-oY-ix5qN*2*{|4;C>ISL^RT^q9m>_J$zJ2nj;>Fe5C`DpR z(=poa0a0-9v&4b;?d=Q!Dbm0X$cTzvP+K3G034|tqfqn=`XkPr<@HAT?o_D2^u`XL zuG-Zqe-#$tmjCdxeH(Fhtu*am;d5fKFVply(SzD=GL;wUZqOZCECCn`Hey9Nib&FT zSFq?;O-QJ-Q1A>9CMvxOuOqP5WVIZbIq-Y*8qZ{5nG{#H@nHE)^H!|=9*cS?A?D&6 zy*2xz^pzQ=v>BHunn}eb)IJKeNzJ)G`wui@96$E!UhxY9)a!^AOLjm|hF|e-;;;+z zLd|r!G4{Ig#wFH_1+OhO*%SEQzD~YZSd*6>6?Z6VN2XkNIBH=9?DHX$KJ*N+&p9g! zw%Jl)*Wek3vWl~?CQ^D9NAMx6pg1H;9J@IlIMCBhf6ZLMBU%n891Tej?;0n-3r@*J zlwj-_=j$(7-M}iFg}NY&nKg}>%!EcQS#Mm-ZEW*XyAc_W-rVl(5UEFELhP0E)N*3n zR(+}qF@|}-#$c1oCe$#^enw^C1^Qu8aJ8*Ra=*SG0R{XiZaB=3?r2^Fi`%Sv5{)#ZXc=%f&e_nCXF+O0P_4L z(p)!-G4Bh;@zx^BGCrZmhlZ7V_Jxc2N1bQWbXH*DE*fDFwG3! zpf+mn%iI-U{NvluWhx;_{hc2g#6v04n>-8=1zAAW=Mt3rQj`F$K4S)eyP&v-a9Ex! zJbnpJDq2$EQG`hk8l!vC#(XixOIaVCoP8N>!Qqn|*$|7&1I~!0>2N3Ybw6>Cq#gqu z7Bg`$)l6t^^DSR$4*|+3ro$-amNsV!&Yl(39uxa0HQm&Qr0Z3QCn9MXg|hLIjl|jd zlDG8ImF;O#?B3?%+HnQIvp;PpDxq2xw*&TPYeyvG8Sy-Nt=CT%#~$h!&6p}bG5jJ=%CF!Ev7#| z2W2QEDk$x7H9iLD7=Fh0uW{zrNq6lYlI?e8SLm-`MI0lt_vh9FkbHWUPi6|6i!!AD zjs!^adlb$S=psR0IPP+&`Is$c3qlkQ21$@BQZB?fT%bwq@h4ND*eyl?6(Uq?> zEl9)@|FKKWxFdN0s@!X=CuK^l&Nm^$WzHe@M&bBZlI*moDKBNeQp6s#MqJ>Zcp=wQxuB~q=W8I4<}`<|8|I_kS7 zhH60v`mwE4v@X#&6{=?MDN)9*=Wo&cYn1SqBA`U$>7G_*p^Rc#WNng~vSvA{1M)&{ z^u$6*eeg*Y&^>h|SJKqsATuZ$bI+TYKte{jN+fh9VfuvI>w9S=>jzXYw|cgz;q?uq zog$?m4zv}n3)COl=+pT`CIN}sj2TP%Sl?IBy3F0ayxV_)=nWbu>^FIZggP?8Zj5b+ zII{#SSu?rs8s;P_JfMnJ5$MupVQFb2_mK!gheMcn;uDM;YeBR)l zbvWP$qtd@Yk2&;g*^9&Tugk_tyzHEni3%j69n4jUZ#QNRFF^1$hL+lNr(fLhsmC)z z>;LG!7qv;di^FwC?6~N z6&-sVuyYq7Fg?)n)3uE_U2A=CS+oS(1p~g9FS;A_@va;{*v){>z*7g?P#0B*uOrTu zlc!Ph7i@u`O_eER5J?f&Hbh1=Zm+C2I^$rBEILpHtqrSr(;{Bh2?X8@|0u)YBPjbj z3+fQu4;2SfMC5k!BmBN4yk$u$bq0i`ZCai!fZsan?v-^y`9g`e$-w@%_>Z&Oz06|X z?lIYI2AOT;9)%aqupd(*T!ymh-f7}1Y0Zrc(=lOUD+pvQRA(QZJ7MQ39nhnyOp~x4 zu<^%n+T%hIYKn#?Usd{NPVs~55oI>j@nke1AXYEtY{P%3Gm$FXYa_y$TAWv6T$9wx z03^b@oh@PHZ77f*EnE+(LwTM$8jq7=tnS+xoX1j z(}bl8yKxqDnz-Av<=AIB%9(iT4${$LYPGQUPr=T)Bz}ay<=^y}Mly+lbJj|?vcTJ8 zv|-ueW!b7cddk3#I47rRBPiVxjQ^T}gQir-*uU+fv(n4Ak4{C*X4mA8 zHU5fq%Lp08Un5>~eSj=x)JtByf6m#Ev+pMybqA)<8?w6!*_ehGD(Ri!?j7p>$h0c5 z-|KFJL>bR?%ZKqfS|Ji)Sp)~(pdm_Ozy@PL97B>JW=@&>Oeuc}M3OFp<(o?@2N)S7 z2@(u(esgB@mF~NSGx15S_lv0a1J(;j-8*9~Y@*T%d-n!eG{=?956;NxjOOa3uj-WU zAVuwc;yp336E!Ok@+{Mdmk8+pDHRoQ*QxN<+7TFVho!*$5iI7=V+$P3(GOj5p$jsV z&2^b+6cg`sK!FFnJcZQG+5+l@4N#M&th(lduQXsa90QQLIyg{?_#O~tOCnFjuO5966;y^yiqsHbD50icICjTrhW z+53iJ0?4fYF1BPuby_!l`BOOjDE0&7Ksx+?J)9#8WK5UNg9J*?A%l zKb*^(6S~?ZmQXOc81_e&zUGaz%-FSWdgj*kBn-1KsQlS@F052an$6o*F*sSk83xq8 z1CqeK2Y8S?#*)|xfD5yPsApcxhpaq;3yz?&%LfHJTG=T{O zV#_NdxYs-IqUDbcPjK{qfG+<9eEey!09{DIDS(2e5U4F|oZ#DkAsMV}f9eGP8u6zG zzD0!(T>2gO(DDZ;AoUKaXxS44pLhqOv^0x=tNq2LXwSPKZ;7H}!~>qe&~1WF5>88|8IzXP@~+JYDVHQ1o` zuO!gR3Ie$W-2og0>i@yUFuupB&IKF^Xyo!AgoNti-!cEtmH&b`;CtU`z<+pKguK8l z|AwpF8{GA;u?5NC;=nQ+2)vfh0pN(R?=kv^*fJgl4tO`dML8N==^gFS@~6w;FW0{n zoPS;V*Oo*(2s}WOj*mOR0N(Ejxoi6CL3lPL1(dHrgz=}w5Z?$>pd^!e@|VyE)YmAg zOB!k{T7Ig>_*KLf~ zT0D76z$XZE@^6fLP4H}7WaD){ZmCZ}e8l{XU<~OAedz;OL+g%v?8Q>(Q!IQk4a{0E zTrS$)2YY!`18dnFGd*XZcf8waR$Ghb*I29AW)?ojseTPO#V&e)d#h9GS-kWR?%Em> zVtZ5+KF1b+h#GN<+7BqW0vCn}oq-Jtc8an5PJ;U6(wz_ywnPyia6DuNE)Y)x^;#Sq z5aE?2HDhZP2 z6vmj~pf@z8mCZ6R5Ex^nu(fQrtua4{c4$)N)lv>&swr3)USLW>WQlHUbaaT~Y+|pM z3a>EXa9EaFapXwmJuj&LD&R%yCnOt65$BMkXetFT$>1t1+Y8<=O&`v%Q4ZiEjF#ew z2i~)%ew&@hW{H&2r7)cvayC6lS5Y6^A6$6pU)aAHApAg2Gs(q;IP}3%DaRI$OA61g zkvMyn9%BK=(Zbqa;44L+8F#{L)+(MQL8bybI>%{fCQ5ciYErz@7TcFYbR;S(su_4+ zL2)a9CZ}bot#3P~zkjKP=Srtk`r`fl9ll@(_ku(5tiY$$05(;Vhf?Uh-I~)c*?H&y z8eb(gzg;mC1vO4)%Mu@-lAM)kud8d-Gi>)#U;(D#p<|h2$9bTMhV$F2i7-IR*A4u2V-w(5t=w#d?!xtWw`Cs6sz(j+|)zs zg-7?X9TR!r8ThyhH29OYE#o0N@4a6!loY9on4o35VqI@^da+2K7SNTg$EJ#)^2w6+ zY2syXaQNlB5TkH7fN@vhq1~VNC|d;;0dO|feF>T`5`8g`712P>j@Ue#j|61MOxE*> zV!D0Ut;q$IIy$z8-3;`G^OtTfVtqKFcuIm<_0|1p6a#kMXKzzf#x)0ob zzTDJ-M($ z-7+I@pQ}XWXzsB($KUE$JXGa&`aOIx=Cb;Jd%sgj8S1uUSvW82e4$gv79YkJD#l0oFTHFQOQ|6(Q3(*9~^+V#{N=p zf9OhQR;J&SwksfRmAv*#qxY-zg$MYxe)`E3A@1}@2B!j*mX}>9F~_XI8iq~bmP3+5 z6?J$v%8WUzWU5;4IZnV*7*2m2ne=>sx*@CKII*Gz3q;K}QBZ*}yw%&dGhk4ajdP2; zS4CUjGrm0x{vjh2+`Rb(f>B>(%o@2lVY_WSG8=fgeUbMCq4oO_>p?sJ~IvB6G@ z?z%@~eEzn#ZjAic%1rdT=rzd~vEpQ6+S^YAIMXTUXa`0eEor8M%f$?*{E%B43#GLm^GgX!FTIKpGejqd`BnScHy@8S4XNhJ$i4a2*|e&Z)4YX?|p)4pXG zmX%C&@RQku_$d#L(7&#UiRapmC_ zk0!5O>TU`6`kLE;%iw4ww8LFYMQt_P-XoG`Otkb+D^+A z3S3-_Wi!j7%aZy@vnkL|?&4nQ>s;s5YEP>b&HA9)a%an+mfTtD?k^96FPzeKqW3Ba zytWd1<(FUQo0RjFTP&9L9n^gBGh|gKrfCz%&YZEJ>jye#!v=RQV_QwrRk^c;nr6|S=1o(jCzXVq zyx;fPFTqzVzbkH#%TCEa=~FfElfj0Y@-N52Yh*hg^GFwxKc(M)E-8`RvgKGy@mpiw zvmvu<=ie-fa4K1?s@y$g!%!8~{nqWO1jSFf8*gJzi->j&5%Qt(tmdxMyKdJz(0QDb6V;bA95dw2_--(Wimc%-RCO1N z4Od>IP&R#jvs96OROb8ix`%xHH0}6g+YwQ(8Ra|VV{`ha)ne4|y2^94C!(DAY@U{& zoEFZ$Z!R8=KYa1f)YVh@{I>a$Xj_^-GfKZ3a~I|gzgKRjc6J+4%NPEKjn<=nay3R| z#6+>h)AO!Oi>-WN#}TCq*D)GFDRvH@(_iz8l&O(uhrVxGew_VuVuI%!y4#&>?_FI_riG^CmMWR>(HOi5asF*!He zsXW_$|K=D4(*}LxSiHYCl~pyjZ{&dk)w|*PtTiRaRNnU&T;8YfNL^ApK2G&szxJtW zQ`%=;xG?t1^oGoBkJP&JjqAJDA#|W;?WpMb?#KpA$iY~8OdWc{ZvEI$nRt^kGm`F8?avgw z!q{F)U0X#Rs`xN%&rS{*AFtbXi*y*w?BbaRXI}Ar@yu7A(-^cXHTV38 zI^}w@EFa4^e@m5F%WslSW0F#ggH}q8?a&>DZ(>(csjg-5oRCAXdnZwlS~X?ZI>-SB%$iQqBTnVG8bIHwdTL&@>_ zxjYp}orBDM*!DqltfgAe{xZrT^ta@P?Vr+DT)z*2lKeS6@2uKHekZZdnYs5JH^jp7 zTAhX3SeqA=q*!bjxWBFhD&J5|z5tmsMKCl3Qy9x6adLNu(!6n4XPKHl7%DNxGq7TO zZVG17zI4F(N*gccQBU7q>ekd1FY@nkp(RFRnDxHpAOe#F{ugmdWC54_W^K>rfDX}t2Q8fxKIV{~^+0Vkw|xJmK;W92Z7~8k)p8 z6cq8}+ni{jZ}@Bz_vr>*z}#@p9pPmTC=FY?s}k(kL?e6al>RH4|jH>x+u z;nbnV1;c@K-8W66yzT)ib1juG(;`GT3KAy-b#8x1PuVW@#)O(aIeXc;^@vM%yRD`h zx~Pv{Jt(OoZdI#;OKTu|AH~3{%x7f_gGV1o8P(H?&Ue_OLpTd&N|GHo+LuSZ!y~7E zlQHe4d{_-Q0OW^H?0THK#|9}IrIG{?RV?lW^ z!?v@;&5L7}o#e%5$4jKs&+@Bj^fk81sjws^Y`v9c zY-i45Gq+XgxSZyuVlSI$DcfqXWQEq$(##OJYh5 zxl&PoJTR|iYIee|kiLtJBhgUoIR_{0^XY?J$#PNbFTx9jU#4WruAVPDaqixJnwToP zD{h@n4wJRr^$Q46)}3jyKj3^DZZw`29T;dndN-|*@6p}nLZjX+-J$hq)t)I9D|Gz( zwHH^XR%j^I(sJm@y01?+!QuYtK__XR`poCk9ULMTFi7V279Py<87Eb_79M`X$ADsi zu3*yHuU4wxCguC?@6VnRS_;Wpu z=5_UIl^n{9O7pZ~W~KPr+Awy!$$$>6Jy(?RaW7NF4YJQPju8haZ;7*X4(B9>&@$(| zl}Wbe%nP~Vw#H|@_w=z7O$m|UQw84_;yLeRQWdC%{c`j%Df<}TFFjanb+*5^0;hHg7sC+*HdLr;z~*PD5bC64q8nadpu)TQg6sC&faqs?Vb1~M{dTSM*+3gSQ z{cpa$wmf$mR3M9;JEF+LRhY$YtN-BM*VWQbNv_n{sYk;%6%v>x0L;ShZBwE zT*}@lJCe_S;v6A6zbI5U^vmtIkR4_7-!KF6BCJp2etf3aRtl6p<07)Q+~F zP`3Eg@*{XmT+2o<{OUc)<%)1p%+v!TwS~)F&Uxg9q3Oe$p0<}l@*+ty4dCFqT>*xc zq%CKDmaN4x=+$m~x9d;08Pa9Yc6wc2Riah<jy`Gi8^Kt>X{v#~Q3#7Rjg5-_CE* zB2%xeLYh z9Wn3yirL;;vL|^pO8t3O3oV-HuORG{d1WH3klxt&th+&l!? zal@XPPR@5LgBOojRXclLwvLIEy<+0o6xZ=V&fT`-cIQgri9yzk#cN^c`4sOD!)cZQ zc{HjL@rMcx=bjEeKbhiVlwR8z_K*L*D=x0HW?!g7w!ZqG+9%{`&jfpiQ8&K`%@)Xb z*U<2#vXUn-Z_L$BJvQ*?TL;yKR=J|5lWR7|PbqSE@A08@=?hz)oWE7LUpRZ3jbnG$ z%3I%fwJSzlVajt`4)L;?X>;i1a1~75t@3f><@^s@^|tY2avcVCz2#+Q1^r#Q$vQD= z)_tqX;cA)8-jmi1&83YFn->!F2jEc3miND_U2>+lFyEfChgiiGl0LmzXu8kZv;81g zv-Zm->Gjy{QJT(YB3spXedlF(L*wxl<8H@yEQ*qx?^rwT9bRWwZjGoyKModk2=}Y6 ziI{sYT|RcTO}azg<0z)_g6ToKr~<2o*{(Y^ir#kBDKmkqq;@)9miTp@byo$l0YW`HsNsi^T)srV5tDvvDsPCrg6b?m8KeSDS8lbm{-!@ii zFIr(Y?@{ZM?7Gyuy;sXV2OCtWA3Nw&Ta!I#mvfn0J*4!HOYq(PqC3ip2R$AZr!1=jG zZS&birJ1IP9(k4L^%5Sj`$SEc8-r>trNM#ohIh+)ikr^#9%OTj$dfEJ4mcDoutzy! zw1&%uhW1@#v}r~19NDw!u!}s+pKhDUTZ(#xVNP>?&7MfRQ(W5e#SUYubn^2E+TE(g z-n7K+*2QVZmn%uWgOzp#(t%@&-`b*YRMP5;WEHzrohb9WYQ%EzSV{aZGOF;7%D{}t zb)I|kO7iloKELfmHt&_M=#AXZ5O;2h7fZX}nlo}?T)Oq8%qm*NcI^qTPmW6;SKcGdkzen!UG;cod@mlK>wz8KZbyT8P=@7@LNZGkq5+_>-XWxF0RQFRUR8VQ~s z{Sw_v=8Tq;OZu~pv=?XWl|@&o3NrseAG@xcv^;V>_Lo}Bu(rNWi$`Lg4p)R3Q=Wgx zl50=;7n?eC7$2`%+=lM*F6QWh*#RBhVsc@1jkVqVH2tckgZgGPkyO^B#^Wy1N?I&} zEwX#qUQ?@0>xK=%<_x|%-tu1R&J(KQd7&CI&Uvr*=HvvKb@hK#FbU78NS$>sMSnR_ zwKv~wM!pn1P-1vWV8m=$L20t~9Qa`Jw2VjIfjvzI4O4S*3CAVBIb~17zSA4`+BWmm z-hG_8zBCbMeE4mKX^2Bn84cy&71cXo-i~*)wbrxCXvkj;I4Zd79=Pjc3> zrX!zsp&F_QP?#QhnC{crBPKUxpd5(SKi9u7!90?z*L6ToBs7C+V$c3cZ^7c5a*`5~ zRc4Y^GW+++lYSEu)KV#bSl&1~_~nNGx@Bi-1#Nl7yM6sR#n~;ID^Zn<4@_%<)1`hJ zeBbiEwe&Efdqn&ey2tC+u8?2M)Ya^ikqq{OG8yw6P98n=FZAlQ?yXBcA6Gh>@Ct2b z>8WHi&vSJ!s_xZ;)NAvp74@;fA5z!gr}|4D7VDn=KK*Ilyy^MxM1{eJOO3)4Jih7= z1iz1+c+K!&pXs=>FXPDN*BfQwv?Cc*8xQU#@EIKIPS;V`*Qj(!C4b6Ic;P^ZNpM)F z;p~+K_d*r=v5YmU+pZ`c1H=6pQ&7Y*t-nMHX^5MX$m;n$@uzbsTu$byYFzzx>CJp6 zrNhG2OANF>qKqbV(l*q!hMu@Jud;XwM-5-`5Nv*{XS6nRc>SQxF#A8l@y0)WP0r<) zZm%fQl7*r}ao^2R;ytuX7eJ0qV1x0~+My>Lr8`HP}^14l6&k-=f@I@B8}OC$9!@cdSMrT z2gjmGsczEd9Vxt>)LihvK^V?_N4{(%+9f{xI|84Qtfv8LmPX z^uT^(lf{*kqK^W(%>!(HgMwH{{=Fjl--~WxS{>-H^3E6g5Z`SDWg)HHL?c2rtyW+7H}!zwO@J(UA~7RahRjDaT(G0h zj&Tr^q0Yjt`j9Li!X6n+@$E5SeLzM+qDaL45w6pR3~*;6zx06u5ED>9_|FxIJUCLI z0U(92?vRAAQl;XeWgh`)LO?NXBB{~vk^y9e1rgrP=12spgxw4wUw%YC!mBSdi9mW% z@Uj7<3I`cOOgL3kjesip3P2TYSQ^}YfjeQUMq1mHU|C~GCbLb97Jgs|(O?yjXMM$> z2u|rd_K=Wh5y}1v%NRqJSOwG{o|`KK!`J|!sX_$G)PrvrLq@ouTQmlCy#~9QKzsKR z1|2en;O8C5_2Yv86!+(wqqbpGeG`nf$IcZ z;;|RUm5wxbSpR9pUf+RtI?5c-LhSyfWiHt=!Dt{7YqKw?8BioaLLvS2JUtkLhNa#O--`mTr>IJ;F32IP?r?R3WY-s`M;)aoD0aV@Pg|tXz zp7f-J7cF+?!Zt!m^~vn_mLQUjxMQEU*w`m9kzGI!pumOTXBf+X+$$o4>*0|l5F-+Z zh(RtCVb81$poU$K;BE0y!HZoROfEXG4CoMuAt5OY*|*i!=l)3d)_?*P;UWBmk9MM5kX021}E~s zb(X*b$dJ3TWR14~dZ6Hb9#2c~! zb^+Hx0=pm=oxlOs5EFKwLewteQy?^Iz(bf=dzx!_GzSCWB*LB)*V_Vd#|n4EWeyjx zVAnOQTG9}sf(>|f5u4igaNy7eikStEE8+Jg>N+r^oXTJUf6}f1I4JR@92%wBL;wcPR6X1=5 zP+qnJ%05`s0TRW9l7$0kwRsC#<>2cMkOZ#vCDO|JVW*WTvo3(@-vHa~-7(AzqBIK( z-H>SL0iSkQ7~xT1e0;b%0%<>{0Ld8Zd#p>=0_l!HV0lUat|g9A=6S4J!KE$|SWENM zcDWs+0Mm}~Z|9{hX7(>=;bbD~j$>d)ZvvP?g1|58M2gvLU}ZWvLBjlh&wUXhq}EpE z*e@}n*@=jLr*hQW3M?>}KoltvF~A6e3cTNW$93w?V7Qjsp!E=3ZwPVVjBp!i%^-p6 zgCK6?#u-jBb|BFw>b>G$Hbtzp2tQ;eh9;B$=|L1W zItDRg@wlowTu~kI^xCHSgU5dQ&h#J4@e`@iEQrG+g;xI=0coJCsyVQqD6pRd5gVn@ zziddo9xFCHdK;xZkVWhnSV;~M;cJBn@M(f5Hu$CMj_E(U0!!LS5&%F&pDe# zB@j3Z1QIXa?E8uF)G(+3q=9qX@aw6;an)jETk#0|CszHX9G=q+;=)a`Z8xBRKJYu@ zWo*S6s0GB+oZJD;Uxk=P34=O8D!9gdX9#TwYDtX%wdoGAV_jw8oj()=>_-NMAxC5r zC5=CLN_dYNiV^nlz-zA&q$jfuG;alS?En!IwKk5a&I6bTiSdPiX_-YJn;k62`-q@! zx;Q8(QRK%$JK5%g#(~5dFfV0^pw-5IRM`!KXEG!F1W^T9P%93rJo*2I{ANzT)b9zg z;;i}A6WGGrl7I%v9R+bTGcQ1+KSDqQ6^}wVJ8|by{shYa9dNZWk#a8`3Gkp0k_#6* z*gXsPaUf8}l>h*WB3a>}ilM2~NWWZ=l87zX1E-N4`73<>vzc z_9y?A017TSaVYFShY{3P%-<++Uq}*b-^#6DrORO1CIbty36XMPrwN$QX((o-U{eIA zT%RwHI-L4902FU>5cF;22T(UJ5ToP>051^0`c+~87d)Qalqj9`X2bG|Bi!B_ygrrE3wjG z@S6P)c3w0Lk^aLAL~MZn#5rGD4Gub54c^}SR)JMXCSb>x8UaAo?%F>9T+W3R$o1Z_ z$`(w3!T&_tow`4GQuy+1u<{`Bjb$n;i-cSm=g$l3` zeE~s0oWeOZ;-KKAKQ42)K`PB%4t8B;On)ywCz=tcC`=9B{bLpIe(_AA07xAMniKCv zLm%UypiBTKwH^b}*`t^T z18a7F#5GrbK+zI88(F=!^=>3~fIiQG74jfac#uxu*fxS8cH9#kyU!P&hAl%O3HV3| z-onEEKRYylgcUHr!$cC$cxX)sgwJ0Ji*FQKYdpKCLv8N|U$_jnoM64x%ttDV3+;byq z4>VmA9u6}^K&+7IuRk~i+=!?n0K4M$pJq-N6iqN<4TH_DMaiFM*a20dfGWhZUL0nO zgcP#aK{dbw#2ZLgQp>E4NB=K+nKU~F1P4-lfz(*QpvD5%3zm=T1-Nn;@FCd{@doQ5 z`3@gGp&gC{3a3%+w9>(#?t(y4A=?*+1~BKBfHR4=s}8hS9#E3O4%bEPcr{;%{_jvbyo|H3Cav=?Ood=&&ganxSp25@}P8pnWf z9OT3DgEA0Kth*?YkhCT*TML0LVnAfj3u5V@B!m+y9~WHMqq!wvxGxS8hEK%e=NudT z^sOl{qEujK;(fc82o9Pa2Wnbm;vg<;I1^S*5HIQJqJQuL1mQd)hBP0-Z3C#{f%*#K zNQ)$F5f2g=M0LVf!dgVujocTglMMHer$f-5qnJn0N5&RTrLWF177RF>?Ss@|03jRfa{n>yP2n&+`0Vu4O Aod5s; delta 28822 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 E4~##G-T(jq diff --git a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/AbstractNettyChannelInitializer.java b/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/AbstractNettyChannelInitializer.java deleted file mode 100755 index 11f17bee..00000000 --- a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/AbstractNettyChannelInitializer.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013 Whizzo Software, LLC. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ -package com.whizzosoftware.wzwave.controller.netty; - -import com.whizzosoftware.wzwave.channel.*; -import com.whizzosoftware.wzwave.codec.ZWaveFrameDecoder; -import com.whizzosoftware.wzwave.codec.ZWaveFrameEncoder; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.jsc.JSerialCommChannel; -import io.netty.channel.oio.OioEventLoopGroup; - -import java.net.SocketAddress; - -/** - * A abstract initializer - * - * @author Ziver Koc - */ -abstract class AbstractNettyChannelInitializer extends ChannelInitializer { - - protected String serialPort; - private ZWaveChannelInboundHandler inboundHandler; - - protected Bootstrap bootstrap; - protected Channel channel; - - - public AbstractNettyChannelInitializer(String serialPort, ZWaveChannelListener listener) { - this.serialPort = serialPort; - this.inboundHandler = new ZWaveChannelInboundHandler(listener); - - bootstrap = new Bootstrap(); - bootstrap.group(new OioEventLoopGroup()); - bootstrap.handler(this); - } - - - - @Override - protected void initChannel(T channel) throws Exception { - this.channel = channel; - doInitChannel(channel); - - // Setup general channel handlers and coders - channel.pipeline().addLast("decoder", new ZWaveFrameDecoder()); - channel.pipeline().addLast("ack", new ACKInboundHandler()); - channel.pipeline().addLast("encoder", new ZWaveFrameEncoder()); - channel.pipeline().addLast("writeQueue", new FrameQueueHandler()); - channel.pipeline().addLast("transaction", new TransactionInboundHandler()); - channel.pipeline().addLast("handler", inboundHandler); - } - - - public Bootstrap getBootstrap() { - return bootstrap; - } - public Channel getChannel() { - return channel; - } - - - public abstract SocketAddress getSocketAddress(); - - protected abstract void doInitChannel(T channel) throws Exception; -} diff --git a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyJSCChannelInitializer.java b/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyJSCChannelInitializer.java deleted file mode 100755 index cbdb768f..00000000 --- a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyJSCChannelInitializer.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013 Whizzo Software, LLC. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ -package com.whizzosoftware.wzwave.controller.netty; - -import com.whizzosoftware.wzwave.channel.ZWaveChannelListener; -import io.netty.channel.jsc.JSCChannelConfig; -import io.netty.channel.jsc.JSCDeviceAddress; -import io.netty.channel.jsc.JSerialCommChannel; - - -/** - * A jSerialComm serial port initializer - * - * @author Ziver Koc - */ -public class NettyJSCChannelInitializer extends AbstractNettyChannelInitializer { - - - public NettyJSCChannelInitializer(String serialPort, ZWaveChannelListener listener) { - super(serialPort, listener); - - bootstrap.channel(JSerialCommChannel.class); - } - - @Override - protected void doInitChannel(JSerialCommChannel channel) throws Exception { - this.channel = channel; - channel.config().setBaudrate(115200); - channel.config().setDatabits(8); - channel.config().setParitybit(JSCChannelConfig.Paritybit.NONE); - channel.config().setStopbits(JSCChannelConfig.Stopbits.STOPBITS_1); - } - - - @Override - public JSCDeviceAddress getSocketAddress() { - return new JSCDeviceAddress(serialPort); - } -} diff --git a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyRxtxChannelInitializer.java b/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyRxtxChannelInitializer.java deleted file mode 100755 index 77959339..00000000 --- a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyRxtxChannelInitializer.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013 Whizzo Software, LLC. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ -package com.whizzosoftware.wzwave.controller.netty; - -import com.whizzosoftware.wzwave.channel.ZWaveChannelListener; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.oio.OioEventLoopGroup; -import io.netty.channel.rxtx.RxtxChannel; -import io.netty.channel.rxtx.RxtxChannelConfig; -import io.netty.channel.rxtx.RxtxDeviceAddress; - -/** - * A RxTx serial port initializer - * - * @author Ziver Koc - */ -public class NettyRxtxChannelInitializer extends AbstractNettyChannelInitializer { - - - public NettyRxtxChannelInitializer(String serialPort, ZWaveChannelListener listener) { - super(serialPort, listener); - - bootstrap.channel(RxtxChannel.class); - } - - @Override - protected void doInitChannel(RxtxChannel channel) throws Exception { - channel.config().setBaudrate(115200); - channel.config().setDatabits(RxtxChannelConfig.Databits.DATABITS_8); - channel.config().setParitybit(RxtxChannelConfig.Paritybit.NONE); - channel.config().setStopbits(RxtxChannelConfig.Stopbits.STOPBITS_1); - } - - - @Override - public RxtxDeviceAddress getSocketAddress() { - return new RxtxDeviceAddress(serialPort); - } -} diff --git a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyZWaveController.java b/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyZWaveController.java deleted file mode 100755 index 8305be1d..00000000 --- a/plugins/zwave/src/com/whizzosoftware/wzwave/controller/netty/NettyZWaveController.java +++ /dev/null @@ -1,467 +0,0 @@ -/* - ******************************************************************************* - * Copyright (c) 2013 Whizzo Software, LLC. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - ******************************************************************************* -*/ -package com.whizzosoftware.wzwave.controller.netty; - -import com.whizzosoftware.wzwave.channel.*; -import com.whizzosoftware.wzwave.channel.event.*; -import com.whizzosoftware.wzwave.commandclass.WakeUpCommandClass; -import com.whizzosoftware.wzwave.controller.ZWaveController; -import com.whizzosoftware.wzwave.controller.ZWaveControllerContext; -import com.whizzosoftware.wzwave.controller.ZWaveControllerListener; -import com.whizzosoftware.wzwave.frame.*; -import com.whizzosoftware.wzwave.node.*; -import com.whizzosoftware.wzwave.persist.PersistentStore; -import com.whizzosoftware.wzwave.persist.mapdb.MapDbPersistentStore; -import com.whizzosoftware.wzwave.util.ByteUtil; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.oio.OioEventLoopGroup; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.util.*; - -/** - * A Netty implementation of a ZWaveController. - * - * The pipeline looks like this: - * - * I/O Request via Channel or - * ChannelHandlerContext - * | - * +----------------------------------------------------------------+-------------------+ - * | ChannelPipeline | | - * | | | - * | +--------------------------------+ | | - * | | ZWaveChannelInboundHandler | | | - * | +---------------+----------------+ | | - * | /|\ | | - * | | | | - * | +---------------+----------------+ | | - * | | TransactionInboundHandler | | | - * | +---------------+----------------+ | | - * | /|\ | | - * | | \|/ | - * | +---------------+-------------------------------------------+--------------+ | - * | | FrameQueueHandler | | - * | +---------------+-------------------------------------------+--------------+ | - * | /|\ | | - * | | | | - * | +---------------+----------------+ | | - * | | ACKInboundHandler | | | - * | +---------------+----------------+ | | - * | /|\ | | - * | | | | - * | +---------------+----------------+ +-------------+--------------+ | - * | | ZWaveFrameDecoder | | ZWaveFrameEncoder | | - * | +---------------+----------------+ +-------------+--------------+ | - * | /|\ | | - * +--------------------+-------------------------------------------+-------------------+ - * | | \|/ | - * +--------------------+-------------------------------------------+-------------------+ - * | | | | - * | [ Socket.read() ] [ Socket.write() ] | - * +------------------------------------------------------------------------------------+ - * - * @author Dan Noguerol - */ -public class NettyZWaveController implements ZWaveController, ZWaveControllerContext, ZWaveControllerListener, ZWaveChannelListener, NodeListener { - private static final Logger logger = LoggerFactory.getLogger(NettyZWaveController.class); - - private String serialPort; - private PersistentStore store; - private AbstractNettyChannelInitializer serial; - private String libraryVersion; - private Integer homeId; - private Byte nodeId; - private ZWaveControllerListener listener; - private final List nodes = new ArrayList<>(); - private final Map nodeMap = new HashMap<>(); - - /** - * Constructor. - * - * @param serialPort the serial port the Z-Wave controller is accessible from - * @param dataDirectory a directory in which to store persistent data - */ - public NettyZWaveController(String serialPort, File dataDirectory) { - this(serialPort, new MapDbPersistentStore(dataDirectory)); - } - - /** - * Constructor. - * - * @param serialPort the serial port for Z-Wave controller is accessible from - * @param store the persistent store to use for storing/retrieving node information - */ - public NettyZWaveController(String serialPort, PersistentStore store) { - this.serialPort = serialPort; - this.store = store; - } - - /* - * ZWaveController methods - */ - - @Override - public void setListener(ZWaveControllerListener listener) { - this.listener = listener; - } - - public void start() { - if (serial == null) { - // Choose a available library - try{ - Class.forName("gnu.io.SerialPort"); // check if RxTx is available - logger.info("RxTx is available, using it as Serial port library"); - serial = new NettyRxtxChannelInitializer(serialPort, this); - } catch (ClassNotFoundException e) { - try { - Class.forName("com.fazecast.jSerialComm.SerialPort"); // check if jSerialComm is available - logger.info("jSerialComm is available, using it as Serial port library"); - serial = new NettyJSCChannelInitializer(serialPort, this); - } catch (ClassNotFoundException e1) { - throw new RuntimeException("Unable to find Rxtx or jSerialComm lib in classpath", e); - } - } - - // set up Netty bootstrap - Bootstrap bootstrap = serial.getBootstrap(); - bootstrap.connect(serial.getSocketAddress()).addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (future.isSuccess()) { - sendDataFrame(new Version()); - sendDataFrame(new MemoryGetId()); - sendDataFrame(new InitData()); - } else { - onZWaveConnectionFailure(future.cause()); - } - } - }); - } - } - - @Override - public void stop() { - - } - - @Override - public int getHomeId() { - return homeId; - } - - @Override - public byte getNodeId() { - return nodeId; - } - - @Override - public String getLibraryVersion() { - return libraryVersion; - } - - @Override - public Collection getNodes() { - return nodes; - } - - @Override - public ZWaveNode getNode(byte nodeId) { - return nodeMap.get(nodeId); - } - - public void sendDataFrame(DataFrame frame) { - serial.getChannel().write(new OutboundDataFrame(frame, true)); - } - - public void sendDataFrame(DataFrame frame, boolean isListeningNode) { - serial.getChannel().write(new OutboundDataFrame(frame, isListeningNode)); - } - - @Override - public void sendEvent(Object e) { - serial.getChannel().write(e); - } - - /* - * ZWaveControllerListener methods - */ - - @Override - public void onZWaveNodeAdded(ZWaveEndpoint node) { - if (listener != null) { - listener.onZWaveNodeAdded(node); - } - } - - @Override - public void onZWaveNodeUpdated(ZWaveEndpoint node) { - if (listener != null) { - listener.onZWaveNodeUpdated(node); - } - } - - @Override - public void onZWaveConnectionFailure(Throwable t) { - if (listener != null) { - listener.onZWaveConnectionFailure(t); - } else { - logger.error("Connection failure and no listener was set", t); - } - } - - @Override - public void onZWaveControllerInfo(String libraryVersion, Integer homeId, Byte nodeId) { - if (listener != null && libraryVersion != null && homeId != null && nodeId != null) { - listener.onZWaveControllerInfo(libraryVersion, homeId, nodeId); - } - } - - @Override - public void onZWaveInclusionStarted() { - if (listener != null) { - listener.onZWaveInclusionStarted(); - } - } - - @Override - public void onZWaveInclusion(NodeInfo nodeInfo, boolean success) { - try { - logger.trace("Inclusion of new node {}", ByteUtil.createString(nodeInfo.getNodeId())); - ZWaveNode node = ZWaveNodeFactory.createNode(nodeInfo, !nodeInfo.hasCommandClass(WakeUpCommandClass.ID), this); - logger.trace("Created new node [{}]: {}", node.getNodeId(), node); - addNode(node); - if (listener != null) { - listener.onZWaveInclusion(nodeInfo, success); - } - } catch (NodeCreationException e) { - logger.error("Unable to create node", e); - } - } - - @Override - public void onZWaveInclusionStopped() { - if (listener != null) { - listener.onZWaveInclusionStopped(); - } - } - - @Override - public void onZWaveExclusionStarted() { - if (listener != null) { - listener.onZWaveExclusionStarted(); - } - } - - @Override - public void onZWaveExclusion(NodeInfo nodeInfo, boolean success) { - if (listener != null) { - listener.onZWaveExclusion(nodeInfo, success); - } - } - - @Override - public void onZWaveExclusionStopped() { - if (listener != null) { - listener.onZWaveExclusionStopped(); - } - } - - /* - * ZWaveChannelListener methods - */ - - @Override - public void onLibraryInfo(String libraryVersion) { - this.libraryVersion = libraryVersion; - onZWaveControllerInfo(libraryVersion, homeId, nodeId); - } - - @Override - public void onControllerInfo(int homeId, byte nodeId) { - this.homeId = homeId; - this.nodeId = nodeId; - onZWaveControllerInfo(libraryVersion, homeId, nodeId); - } - - @Override - public void onNodeProtocolInfo(byte nodeId, NodeProtocolInfo npi) { - try { - logger.trace("Received protocol info for node {}", nodeId); - ZWaveNode node = store.getNode(nodeId, this); - if (node == null || !node.matchesNodeProtocolInfo(npi)) { - node = ZWaveNodeFactory.createNode( - new NodeInfo(nodeId, npi.getBasicDeviceClass(), npi.getGenericDeviceClass(), npi.getSpecificDeviceClass()), - npi.isListening(), - this - ); - logger.trace("Created new node: {}: {}", nodeId, node); - } else { - logger.debug("Node[{}] matches persistent node information; no need to interview", nodeId); - } - addNode(node); - } catch (NodeCreationException e) { - logger.error("Unable to create node", e); - } - } - - private void addNode(ZWaveNode node) { - ZWaveNode n = nodeMap.get(node.getNodeId()); - if (n != null) { - nodes.remove(n); - nodeMap.remove(node.getNodeId()); - } - nodes.add(node); - nodeMap.put(node.getNodeId(), node); - node.startInterview(this); - } - - @Override - public void onApplicationCommand(ApplicationCommand applicationCommand) { - ZWaveNode node = nodeMap.get(applicationCommand.getNodeId()); - if (node != null) { - node.onApplicationCommand(this, applicationCommand); - if (node.isStarted()) { - onZWaveNodeUpdated(node); - } - } else { - logger.error("Unable to find node: {}", nodeId); - } - } - - @Override - public void onApplicationUpdate(ApplicationUpdate applicationUpdate) { - Byte nodeId = applicationUpdate.getNodeId(); - - if (applicationUpdate.didInfoRequestFail()) { - logger.trace("UPDATE_STATE_NODE_INFO_REQ_FAILED received"); - } - - if (nodeId != null) { - ZWaveNode node = nodeMap.get(nodeId); - if (node != null) { - node.onApplicationUpdate(this, applicationUpdate); - if (node.isStarted()) { - onZWaveNodeUpdated(node); - } - } else { - logger.error("Unable to find node: {}", nodeId); - } - } else { - logger.error("Unable to determine node to route ApplicationUpdate to"); - } - } - - @Override - public void onTransactionStarted(TransactionStartedEvent evt) { - logger.trace("Detected start of new transaction: {}", evt.getId()); - serial.getChannel().write(evt); - } - - @Override - public void onTransactionComplete(TransactionCompletedEvent evt) { - logger.trace("Detected end of transaction: {}", evt.getId()); - if (evt instanceof SendDataTransactionCompletedEvent) { - ZWaveNode node = nodeMap.get(evt.getNodeId()); - if (node != null) { - node.onSendDataCallback(this, true); - } else { - logger.error("Unable to find node: {}", evt.getNodeId()); - } - } - serial.getChannel().write(evt); - } - - @Override - public void onTransactionFailed(TransactionFailedEvent evt) { - logger.trace("Detected transaction failure: {}", evt.getId()); - if (evt instanceof SendDataTransactionFailedEvent) { - ZWaveNode node = nodeMap.get(evt.getNodeId()); - if (node != null) { - node.onSendDataCallback(this, ((SendDataTransactionFailedEvent)evt).isTargetNodeACKReceived()); - } else { - logger.error("Unable to find node: {}", evt.getNodeId()); - } - } - serial.getChannel().write(evt); - } - - @Override - public void onAddNodeToNetwork(AddNodeToNetwork update) { - if (listener != null) { - switch (update.getStatus()) { - case AddNodeToNetwork.ADD_NODE_STATUS_LEARN_READY: - onZWaveInclusionStarted(); - break; - case AddNodeToNetwork.ADD_NODE_STATUS_DONE: - onZWaveInclusionStopped(); - break; - case AddNodeToNetwork.ADD_NODE_STATUS_ADDING_CONTROLLER: - case AddNodeToNetwork.ADD_NODE_STATUS_ADDING_SLAVE: - onZWaveInclusion(update.getNodeInfo(), true); - break; - case AddNodeToNetwork.ADD_NODE_STATUS_FAILED: - onZWaveInclusion(update.getNodeInfo(), false); - break; - default: - logger.debug("Received unexpected status from AddNodeToNetwork frame: {}", update.getStatus()); - } - } - } - - @Override - public void onRemoveNodeFromNetwork(RemoveNodeFromNetwork update) { - if (listener != null) { - switch (update.getStatus()) { - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_LEARN_READY: - onZWaveExclusionStarted(); - break; - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_DONE: - onZWaveExclusionStopped(); - break; - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_NODE_FOUND: - logger.debug("A node has been found that wants to be excluded: {}", ByteUtil.createString(update.getSource())); - break; - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_REMOVING_CONTROLLER: - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_REMOVING_SLAVE: - onZWaveExclusion(update.getNodeInfo(), true); - break; - case RemoveNodeFromNetwork.REMOVE_NODE_STATUS_FAILED: - onZWaveExclusion(update.getNodeInfo(), false); - break; - default: - logger.debug("Received unexpected status from RemoveNodeFromNetwork frame: {}", update.getStatus()); - } - } - } - - @Override - public void onSetDefault() { - logger.info("Z-Wave controller has been reset to factory default"); - } - - /* - * NodeListener methods - */ - - @Override - public void onNodeStarted(ZWaveNode node) { - // save the newly started node - logger.debug("Saving information for node {}", node.getNodeId()); - store.saveNode(node); - - // when a node moves to the "started" state, alert listeners that it's ready to be added - onZWaveNodeAdded(node); - } -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/DefaultJSCChannelConfig.java b/plugins/zwave/src/io/netty/channel/jsc/DefaultJSCChannelConfig.java deleted file mode 100755 index acc5693f..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/DefaultJSCChannelConfig.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.jsc; - -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelOption; -import io.netty.channel.DefaultChannelConfig; -import io.netty.channel.MessageSizeEstimator; -import io.netty.channel.RecvByteBufAllocator; - -import java.util.Map; - -import static io.netty.channel.jsc.JSCChannelOption.*; - -/** - * Default configuration class for jSerialComm device connections. - */ -final class DefaultJSCChannelConfig extends DefaultChannelConfig implements JSCChannelConfig { - - private volatile int baudrate = 115200; - private volatile boolean dtr; - private volatile boolean rts; - private volatile Stopbits stopbits = Stopbits.STOPBITS_1; - private volatile int databits = 8; - private volatile Paritybit paritybit = Paritybit.NONE; - private volatile int waitTime; - private volatile int readTimeout = 1000; - - DefaultJSCChannelConfig(JSerialCommChannel channel) { - super(channel); - } - - @Override - public Map, Object> getOptions() { - return getOptions(super.getOptions(), BAUD_RATE, DTR, RTS, STOP_BITS, DATA_BITS, PARITY_BIT, WAIT_TIME); - } - - @SuppressWarnings("unchecked") - @Override - public T getOption(ChannelOption option) { - if (option == BAUD_RATE) - return (T) Integer.valueOf(getBaudrate()); - else if (option == STOP_BITS) - return (T) getStopbits(); - else if (option == DATA_BITS) - return (T) Integer.valueOf(getDatabits()); - else if (option == PARITY_BIT) - return (T) getParitybit(); - else if (option == WAIT_TIME) - return (T) Integer.valueOf(getWaitTimeMillis()); - else if (option == READ_TIMEOUT) - return (T) Integer.valueOf(getReadTimeout()); - return super.getOption(option); - } - - @Override - public boolean setOption(ChannelOption option, T value) { - validate(option, value); - - if (option == BAUD_RATE) { - setBaudrate((Integer) value); - } else if (option == STOP_BITS) { - setStopbits((Stopbits) value); - } else if (option == DATA_BITS) { - setDatabits((Integer)value); - } else if (option == PARITY_BIT) { - setParitybit((Paritybit) value); - } else if (option == WAIT_TIME) { - setWaitTimeMillis((Integer) value); - } else if (option == READ_TIMEOUT) { - setReadTimeout((Integer) value); - } else { - return super.setOption(option, value); - } - return true; - } - - @Override - public JSCChannelConfig setBaudrate(final int baudrate) { - this.baudrate = baudrate; - return this; - } - - @Override - public JSCChannelConfig setStopbits(final Stopbits stopbits) { - this.stopbits = stopbits; - return this; - } - - @Override - public JSCChannelConfig setDatabits(final int databits) { - this.databits = databits; - return this; - } - - @Override - public JSCChannelConfig setParitybit(final Paritybit paritybit) { - this.paritybit = paritybit; - return this; - } - - @Override - public int getBaudrate() { - return baudrate; - } - - @Override - public Stopbits getStopbits() { - return stopbits; - } - - @Override - public int getDatabits() { - return databits; - } - - @Override - public Paritybit getParitybit() { - return paritybit; - } - - - @Override - public int getWaitTimeMillis() { - return waitTime; - } - - @Override - public JSCChannelConfig setWaitTimeMillis(final int waitTimeMillis) { - if (waitTimeMillis < 0) { - throw new IllegalArgumentException("Wait time must be >= 0"); - } - waitTime = waitTimeMillis; - return this; - } - - @Override - public JSCChannelConfig setReadTimeout(int readTimeout) { - if (readTimeout < 0) { - throw new IllegalArgumentException("readTime must be >= 0"); - } - this.readTimeout = readTimeout; - return this; - } - - @Override - public int getReadTimeout() { - return readTimeout; - } - - @Override - public JSCChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) { - super.setConnectTimeoutMillis(connectTimeoutMillis); - return this; - } - - @Override - @Deprecated - public JSCChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) { - super.setMaxMessagesPerRead(maxMessagesPerRead); - return this; - } - - @Override - public JSCChannelConfig setWriteSpinCount(int writeSpinCount) { - super.setWriteSpinCount(writeSpinCount); - return this; - } - - @Override - public JSCChannelConfig setAllocator(ByteBufAllocator allocator) { - super.setAllocator(allocator); - return this; - } - - @Override - public JSCChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { - super.setRecvByteBufAllocator(allocator); - return this; - } - - @Override - public JSCChannelConfig setAutoRead(boolean autoRead) { - super.setAutoRead(autoRead); - return this; - } - - @Override - public JSCChannelConfig setAutoClose(boolean autoClose) { - super.setAutoClose(autoClose); - return this; - } - - @Override - public JSCChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { - super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); - return this; - } - - @Override - public JSCChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { - super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); - return this; - } - - @Override - public JSCChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) { - super.setMessageSizeEstimator(estimator); - return this; - } -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/JSCChannelConfig.java b/plugins/zwave/src/io/netty/channel/jsc/JSCChannelConfig.java deleted file mode 100755 index fdf16726..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/JSCChannelConfig.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.jsc; - -import com.fazecast.jSerialComm.SerialPort; -import io.netty.buffer.ByteBufAllocator; -import io.netty.channel.ChannelConfig; -import io.netty.channel.MessageSizeEstimator; -import io.netty.channel.RecvByteBufAllocator; - -/** - * A configuration class for JSerialComm device connections. - * - *

Available options

- * - * In addition to the options provided by {@link ChannelConfig}, - * {@link DefaultJSCChannelConfig} allows the following options in the option map: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
NameAssociated setter method
{@link JSCChannelOption#BAUD_RATE}{@link #setBaudrate(int)}
{@link JSCChannelOption#STOP_BITS}{@link #setStopbits(Stopbits)}
{@link JSCChannelOption#DATA_BITS}{@link #setDatabits(int)}
{@link JSCChannelOption#PARITY_BIT}{@link #setParitybit(Paritybit)}
{@link JSCChannelOption#WAIT_TIME}{@link #setWaitTimeMillis(int)}
- */ -public interface JSCChannelConfig extends ChannelConfig { - enum Stopbits { - /** - * 1 stop bit will be sent at the end of every character - */ - STOPBITS_1(SerialPort.ONE_STOP_BIT), - /** - * 2 stop bits will be sent at the end of every character - */ - STOPBITS_2(SerialPort.TWO_STOP_BITS), - /** - * 1.5 stop bits will be sent at the end of every character - */ - STOPBITS_1_5(SerialPort.ONE_POINT_FIVE_STOP_BITS); - - private final int value; - - Stopbits(int value) { - this.value = value; - } - - public int value() { - return value; - } - - public static Stopbits valueOf(int value) { - for (Stopbits stopbit : Stopbits.values()) { - if (stopbit.value == value) { - return stopbit; - } - } - throw new IllegalArgumentException("unknown " + Stopbits.class.getSimpleName() + " value: " + value); - } - } - - enum Paritybit { - /** - * No parity bit will be sent with each data character at all - */ - NONE(SerialPort.NO_PARITY), - /** - * An odd parity bit will be sent with each data character, ie. will be set - * to 1 if the data character contains an even number of bits set to 1. - */ - ODD(SerialPort.ODD_PARITY), - /** - * An even parity bit will be sent with each data character, ie. will be set - * to 1 if the data character contains an odd number of bits set to 1. - */ - EVEN(SerialPort.EVEN_PARITY), - /** - * A mark parity bit (ie. always 1) will be sent with each data character - */ - MARK(SerialPort.MARK_PARITY), - /** - * A space parity bit (ie. always 0) will be sent with each data character - */ - SPACE(SerialPort.SPACE_PARITY); - - private final int value; - - Paritybit(int value) { - this.value = value; - } - - public int value() { - return value; - } - - public static Paritybit valueOf(int value) { - for (Paritybit paritybit : Paritybit.values()) { - if (paritybit.value == value) { - return paritybit; - } - } - throw new IllegalArgumentException("unknown " + Paritybit.class.getSimpleName() + " value: " + value); - } - } - - /** - * Sets the baud rate (ie. bits per second) for communication with the serial device. - * The baud rate will include bits for framing (in the form of stop bits and parity), - * such that the effective data rate will be lower than this value. - * - * @param baudrate The baud rate (in bits per second) - */ - JSCChannelConfig setBaudrate(int baudrate); - - /** - * Sets the number of stop bits to include at the end of every character to aid the - * serial device in synchronising with the data. - * - * @param stopbits The number of stop bits to use - */ - JSCChannelConfig setStopbits(Stopbits stopbits); - - /** - * Sets the number of data bits to use to make up each character sent to the serial - * device. - * - * @param databits The number of data bits to use - */ - JSCChannelConfig setDatabits(int databits); - - /** - * Sets the type of parity bit to be used when communicating with the serial device. - * - * @param paritybit The type of parity bit to be used - */ - JSCChannelConfig setParitybit(Paritybit paritybit); - - /** - * @return The configured baud rate, defaulting to 115200 if unset - */ - int getBaudrate(); - - /** - * @return The configured stop bits, defaulting to {@link Stopbits#STOPBITS_1} if unset - */ - Stopbits getStopbits(); - - /** - * @return The configured data bits, defaulting to 8 if unset - */ - int getDatabits(); - - /** - * @return The configured parity bit, defaulting to {@link Paritybit#NONE} if unset - */ - Paritybit getParitybit(); - - /** - * @return The number of milliseconds to wait between opening the serial port and - * initialising. - */ - int getWaitTimeMillis(); - - /** - * Sets the time to wait after opening the serial port and before sending it any - * configuration information or data. A value of 0 indicates that no waiting should - * occur. - * - * @param waitTimeMillis The number of milliseconds to wait, defaulting to 0 (no - * wait) if unset - * @throws IllegalArgumentException if the supplied value is < 0 - */ - JSCChannelConfig setWaitTimeMillis(int waitTimeMillis); - - /** - * Sets the maximal time (in ms) to block while try to read from the serial port. Default is 1000ms - */ - JSCChannelConfig setReadTimeout(int readTimeout); - - /** - * Return the maximal time (in ms) to block and wait for something to be ready to read. - */ - int getReadTimeout(); - - @Override - JSCChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis); - - @Override - @Deprecated - JSCChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead); - - @Override - JSCChannelConfig setWriteSpinCount(int writeSpinCount); - - @Override - JSCChannelConfig setAllocator(ByteBufAllocator allocator); - - @Override - JSCChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); - - @Override - JSCChannelConfig setAutoRead(boolean autoRead); - - @Override - JSCChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark); - - @Override - JSCChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark); - - @Override - JSCChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator); -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/JSCChannelOption.java b/plugins/zwave/src/io/netty/channel/jsc/JSCChannelOption.java deleted file mode 100755 index 547dc91f..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/JSCChannelOption.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.jsc; - -import io.netty.channel.ChannelOption; -import io.netty.channel.jsc.JSCChannelConfig.Paritybit; -import io.netty.channel.jsc.JSCChannelConfig.Stopbits; - -/** - * Option for configuring a serial port connection - */ -public final class JSCChannelOption extends ChannelOption { - - public static final ChannelOption BAUD_RATE = valueOf("BAUD_RATE"); - public static final ChannelOption DTR = valueOf("DTR"); - public static final ChannelOption RTS = valueOf("RTS"); - public static final ChannelOption STOP_BITS = valueOf("STOP_BITS"); - public static final ChannelOption DATA_BITS = valueOf("DATA_BITS"); - public static final ChannelOption PARITY_BIT = valueOf("PARITY_BIT"); - public static final ChannelOption WAIT_TIME = valueOf("WAIT_TIME"); - public static final ChannelOption READ_TIMEOUT = valueOf("READ_TIMEOUT"); - - @SuppressWarnings({ "unused", "deprecation" }) - private JSCChannelOption() { - super(null); - } -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/JSCDeviceAddress.java b/plugins/zwave/src/io/netty/channel/jsc/JSCDeviceAddress.java deleted file mode 100755 index c1589d97..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/JSCDeviceAddress.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.jsc; - -import java.net.SocketAddress; - -/** - * A {@link SocketAddress} subclass to wrap the serial port address of a jSerialComm - * device (e.g. COM1, /dev/ttyUSB0). - */ -public class JSCDeviceAddress extends SocketAddress { - - private static final long serialVersionUID = -2907820090993709523L; - - private final String value; - - /** - * Creates a JSCDeviceAddress representing the address of the serial port. - * - * @param value the address of the device (e.g. COM1, /dev/ttyUSB0, ...) - */ - public JSCDeviceAddress(String value) { - this.value = value; - } - - /** - * @return The serial port address of the device (e.g. COM1, /dev/ttyUSB0, ...) - */ - public String value() { - return value; - } -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/JSerialCommChannel.java b/plugins/zwave/src/io/netty/channel/jsc/JSerialCommChannel.java deleted file mode 100755 index c5758c13..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/JSerialCommChannel.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package io.netty.channel.jsc; - -import com.fazecast.jSerialComm.SerialPort; -import io.netty.channel.ChannelPromise; -import io.netty.channel.oio.OioByteStreamChannel; - -import java.io.IOException; -import java.net.SocketAddress; -import java.util.concurrent.TimeUnit; - -import static io.netty.channel.jsc.JSCChannelOption.*; - - -/** - * A channel to a serial device using the jSerialComm library. - */ -public class JSerialCommChannel extends OioByteStreamChannel { - - private static final JSCDeviceAddress LOCAL_ADDRESS = new JSCDeviceAddress("localhost"); - - private final JSCChannelConfig config; - - private boolean open = true; - private JSCDeviceAddress deviceAddress; - private SerialPort serialPort; - - public JSerialCommChannel() { - super(null); - - config = new DefaultJSCChannelConfig(this); - } - - @Override - public JSCChannelConfig config() { - return config; - } - - @Override - public boolean isOpen() { - return open; - } - - @Override - protected AbstractUnsafe newUnsafe() { - return new JSCUnsafe(); - } - - @Override - protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { - JSCDeviceAddress remote = (JSCDeviceAddress) remoteAddress; - SerialPort commPort = SerialPort.getCommPort(remote.value()); - if(!commPort.openPort()) - throw new IOException("Could not open port: "+remote.value()); - - commPort.setComPortTimeouts( - SerialPort.TIMEOUT_READ_BLOCKING, config().getOption(READ_TIMEOUT), 0); - - deviceAddress = remote; - serialPort = commPort; - } - - protected void doInit() throws Exception { - serialPort.setComPortParameters( - config().getOption(BAUD_RATE), - config().getOption(DATA_BITS), - config().getOption(STOP_BITS).value(), - config().getOption(PARITY_BIT).value() - ); - //serialPort.setFlowControl(config().getOption(FLOW_CTRL)); - - activate(serialPort.getInputStream(), serialPort.getOutputStream()); - } - - @Override - public JSCDeviceAddress localAddress() { - return (JSCDeviceAddress) super.localAddress(); - } - - @Override - public JSCDeviceAddress remoteAddress() { - return (JSCDeviceAddress) super.remoteAddress(); - } - - @Override - protected JSCDeviceAddress localAddress0() { - return LOCAL_ADDRESS; - } - - @Override - protected JSCDeviceAddress remoteAddress0() { - return deviceAddress; - } - - @Override - protected void doBind(SocketAddress localAddress) throws Exception { - throw new UnsupportedOperationException(); - } - - @Override - protected void doDisconnect() throws Exception { - doClose(); - } - - @Override - protected void doClose() throws Exception { - open = false; - try { - super.doClose(); - } finally { - if (serialPort != null) { - serialPort.closePort(); - serialPort = null; - } - } - } - - @Override - protected boolean isInputShutdown() { - return !open; - } - - - private final class JSCUnsafe extends AbstractUnsafe { - @Override - public void connect( - final SocketAddress remoteAddress, - final SocketAddress localAddress, final ChannelPromise promise) { - if (!promise.setUncancellable() || !isOpen()) { - return; - } - - try { - final boolean wasActive = isActive(); - doConnect(remoteAddress, localAddress); - - int waitTime = config().getOption(WAIT_TIME); - if (waitTime > 0) { - eventLoop().schedule(new Runnable() { - @Override - public void run() { - try { - doInit(); - safeSetSuccess(promise); - if (!wasActive && isActive()) { - pipeline().fireChannelActive(); - } - } catch (Throwable t) { - safeSetFailure(promise, t); - closeIfClosed(); - } - } - }, waitTime, TimeUnit.MILLISECONDS); - } else { - doInit(); - safeSetSuccess(promise); - if (!wasActive && isActive()) { - pipeline().fireChannelActive(); - } - } - } catch (Throwable t) { - safeSetFailure(promise, t); - closeIfClosed(); - } - } - } -} diff --git a/plugins/zwave/src/io/netty/channel/jsc/package-info.java b/plugins/zwave/src/io/netty/channel/jsc/package-info.java deleted file mode 100755 index 0f6e5642..00000000 --- a/plugins/zwave/src/io/netty/channel/jsc/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2017 The Netty Project - * - * The Netty Project licenses this file to you under the Apache License, - * version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -/** - * A serial and parallel port communication transport based on RXTX. - */ -package io.netty.channel.jsc; diff --git a/plugins/zwave/src/se/hal/plugin/zwave/HalZWaveController.java b/plugins/zwave/src/se/hal/plugin/zwave/HalZWaveController.java index cb2a4eef..a13be924 100755 --- a/plugins/zwave/src/se/hal/plugin/zwave/HalZWaveController.java +++ b/plugins/zwave/src/se/hal/plugin/zwave/HalZWaveController.java @@ -5,22 +5,23 @@ import com.whizzosoftware.wzwave.controller.ZWaveControllerListener; import com.whizzosoftware.wzwave.controller.netty.NettyZWaveController; import com.whizzosoftware.wzwave.node.NodeInfo; import com.whizzosoftware.wzwave.node.ZWaveEndpoint; -import com.whizzosoftware.wzwave.persist.HashMapPersistentStore; import se.hal.HalContext; import se.hal.intf.*; +import zutil.log.LogUtil; -import java.io.IOException; +import java.util.logging.Logger; /** * */ -public class HalZWaveController implements HalSensorController, HalEventController, HalAutoScannableController { - +public class HalZWaveController implements HalSensorController, HalEventController, + HalAutoScannableController, ZWaveControllerListener { + public static final Logger logger = LogUtil.getLogger(); private ZWaveController controller; - public static void main(String[] args) throws IOException { - NettyZWaveController zwave = new NettyZWaveController("COM5", new HashMapPersistentStore()); + public static void main(String[] args) { + NettyZWaveController zwave = new NettyZWaveController("COM3", new HashMapPersistentStore()); zwave.setListener(new ZWaveControllerListener(){ @Override public void onZWaveNodeAdded(ZWaveEndpoint node) { @@ -81,9 +82,11 @@ public class HalZWaveController implements HalSensorController, HalEventControll return HalContext.getStringProperty("zwave.com_port") != null; } @Override - public void initialize() throws Exception { - //controller = new NettyZWaveController(HalContext.getStringProperty("zwave.com_port")); - //controller.setListener(this); + public void initialize() { + controller = new NettyZWaveController( + HalContext.getStringProperty("zwave.com_port"), + new HashMapPersistentStore()); + controller.setListener(this); controller.start(); } @@ -95,7 +98,55 @@ public class HalZWaveController implements HalSensorController, HalEventControll ////////////// Z-WAVE CODE //////////////////////// + @Override + public void onZWaveNodeAdded(ZWaveEndpoint node) { + logger.finest("onZWaveNodeAdded: "+ node); + } + @Override + public void onZWaveNodeUpdated(ZWaveEndpoint node) { + logger.finest("onZWaveNodeUpdated: "+ node); + } + + @Override + public void onZWaveConnectionFailure(Throwable t) { + logger.finest("onZWaveConnectionFailure: "+ t); + } + + @Override + public void onZWaveControllerInfo(String libraryVersion, Integer homeId, Byte nodeId) { + logger.finest("onZWaveControllerInfo: "+ libraryVersion+" "+homeId+" "+nodeId); + } + + @Override + public void onZWaveInclusionStarted() { + logger.finest("onZWaveInclusionStarted"); + } + + @Override + public void onZWaveInclusion(NodeInfo nodeInfo, boolean success) { + logger.finest("onZWaveInclusion: "+ nodeInfo + " "+success); + } + + @Override + public void onZWaveInclusionStopped() { + logger.finest("onZWaveInclusionStopped"); + } + + @Override + public void onZWaveExclusionStarted() { + logger.finest("onZWaveExclusionStarted"); + } + + @Override + public void onZWaveExclusion(NodeInfo nodeInfo, boolean success) { + logger.finest("onZWaveExclusion: "+ nodeInfo + " "+success); + } + + @Override + public void onZWaveExclusionStopped() { + logger.finest("onZWaveExclusionStopped"); + } ////////////// HAL CODE //////////////////////// diff --git a/plugins/zwave/src/se/hal/plugin/zwave/HashMapPersistentStore.java b/plugins/zwave/src/se/hal/plugin/zwave/HashMapPersistentStore.java new file mode 100644 index 00000000..6f1918e0 --- /dev/null +++ b/plugins/zwave/src/se/hal/plugin/zwave/HashMapPersistentStore.java @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018 Ziver Koc + * + * 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. + */ + +package se.hal.plugin.zwave; + +import com.whizzosoftware.wzwave.node.NodeCreationException; +import com.whizzosoftware.wzwave.node.NodeListener; +import com.whizzosoftware.wzwave.node.ZWaveNode; +import com.whizzosoftware.wzwave.node.ZWaveNodeFactory; +import com.whizzosoftware.wzwave.persist.PersistenceContext; +import com.whizzosoftware.wzwave.persist.PersistentStore; + +import java.util.HashMap; +import java.util.Map; + +/** + * A HashMap implementation of PersistentStore. + * + * @author Ziver Koc + */ +public class HashMapPersistentStore implements PersistentStore, PersistenceContext { + + private HashMap> db; + + public HashMapPersistentStore() { + db = new HashMap<>(); + } + + + @Override + public ZWaveNode getNode(byte nodeId, NodeListener listener) throws NodeCreationException { + return ZWaveNodeFactory.createNode(this, nodeId, listener); + } + + @Override + public void saveNode(ZWaveNode node) { + node.save(this); + } + + @Override + public void close() { } + + + @Override + public Map getNodeMap(int nodeId) { + return get("" + nodeId); + } + + @Override + public Map getCommandClassMap(int nodeId, int commandClassId) { + return get("" + nodeId + "." + commandClassId); + } + + private Map get(String key) { + if (!db.containsKey(key)) + db.put(key, new HashMap()); + return db.get(key); + } + +} \ No newline at end of file