From 3be908e6bd58445835b49aace84d764fe5e5a9b2 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 27 Apr 2019 00:40:18 +0100 Subject: [PATCH 001/109] Removed unwanted files --- .../v15/Server/sqlite3/db.lock | 0 .../v15/Server/sqlite3/storage.ide | Bin 634880 -> 0 bytes .../v15/Server/sqlite3/storage.ide-shm | Bin 32768 -> 0 bytes .../v15/Server/sqlite3/storage.ide-wal | Bin 4148872 -> 0 bytes .../bin/Debug/ASCOM.Astrometry.xml | 12201 ---------------- .../bin/Debug/ASCOM.Attributes.xml | 93 - MeadeAutostar497/bin/Debug/ASCOM.Controls.xml | 513 - .../bin/Debug/ASCOM.DeviceInterfaces.xml | 6948 --------- .../bin/Debug/ASCOM.Exceptions.xml | 693 - .../bin/Debug/ASCOM.Internal.Extensions.xml | 126 - ...SCOM.MeadeAutostar497.Telescope.dll.config | 8 - .../bin/Debug/ASCOM.SettingsProvider.xml | 188 - .../bin/Debug/ASCOM.Utilities.xml | 3867 ----- ...Autostar497.Properties.Resources.resources | Bin 128640 -> 0 bytes ...MeadeAutostar497.SetupDialogForm.resources | Bin 180 -> 0 bytes .../MeadeAutostar497.csproj.CopyComplete | 0 ...adeAutostar497.csproj.FileListAbsolute.txt | 29 - 17 files changed, 24666 deletions(-) delete mode 100644 .vs/MeadeAutostar497/v15/Server/sqlite3/db.lock delete mode 100644 .vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide delete mode 100644 .vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide-shm delete mode 100644 .vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide-wal delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Astrometry.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Attributes.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Controls.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.DeviceInterfaces.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Exceptions.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Internal.Extensions.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.MeadeAutostar497.Telescope.dll.config delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.SettingsProvider.xml delete mode 100644 MeadeAutostar497/bin/Debug/ASCOM.Utilities.xml delete mode 100644 MeadeAutostar497/obj/Debug/ASCOM.MeadeAutostar497.Properties.Resources.resources delete mode 100644 MeadeAutostar497/obj/Debug/ASCOM.MeadeAutostar497.SetupDialogForm.resources delete mode 100644 MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.CopyComplete delete mode 100644 MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.FileListAbsolute.txt diff --git a/.vs/MeadeAutostar497/v15/Server/sqlite3/db.lock b/.vs/MeadeAutostar497/v15/Server/sqlite3/db.lock deleted file mode 100644 index e69de29..0000000 diff --git a/.vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide b/.vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide deleted file mode 100644 index 3bc8c08b96a64bed5f7be077909ae190e27bb573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 634880 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

v? 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%0DM;VJi^$nhRb5HoZ~u zT5z^!KKPw*mM`xFs}Jj20NxLFj49tj@Ud`?*@fX#;T#i-!k>V%{Kerf!ulBAj>tDP z>A{hu;d@}mh(1*QF`RSE^6($vtWW+MoMUW7cv_VI2J$N38{k!7ZP1tdE$hH!8NB4J z;gnC_9o7fiUio-9=irs$iz{9Qz8U6kP~WQX1AzK5|7!3Pu=2}m!2f`APFV|{lSuPx zv-0w=V_x~!fmem|nr2;iGuZwyem(g8aOz`ycpq4MQ-2%4M>K5x8^I@6>E8~Y1E+r6 zfBF>c_)s4CQaJUq8GHk*e7@vwz_!Qo<)6Unm$xHZ@b3>We}mV%;HhYg?Nxqx0a*R| z+6G<|USdGO@9D%J3a9=|e+KND&zF29Z2NgT;2Ytbv)oU+6;>YGEI-u5E6*?QIgg7|f6xv}Z4P4cPK6Z*O=Dn7@HO_ks5UmVhmPfA|zwS>yxZ zv*Da$4u&s;)t9eB;p<@j1~2&@Kz*BEejLs@V>0|ZIQ`ub@UyV}Y5F7KSK;(;N5eCq zOvj(`@?5aC;Okg;UfA-DmluU?uW3F6uLWm&+>d+3D)0O{zu_kVVXSP)8L2U)bHu=bFkyr z@gx5mPXBv0JO{>_@|^=O1ZVp`4zCC+pRaS_bsJV+@;jUSviq~!!P<|n3*mj>>@WEs z*zxY`6Y%k{@~Ch5{3`uL@I`R0fj$ji1FH{T@{O?eqCVvBHSv~rG5ipm{e3C?2%PpT z{}Ik>hRfi8!8x8Uhv#I1w>`Wa`8@w#50hk2-&OENu=#EO)$qF-21l-ecZRcni|x4%J{?wGUtfYh2RnX!$=`;vf8+C;uz3^7t}-UJ6@c zK*4Ll%4eS$zX6>7_(pg$IQ`Gp;cZ~;#h1Jroc1M8snXvBe-KXlmrsZJ8?;xx3eZ+< z|IP4qaJK&z_`5JBJm^#T37BB;`X+ClgdKmrcL%PJ90jd;+ZgOn(RbFa@=bPxPPIQ1((250-_r(o-IOvo?6w#V|m2hX}h86Q7@mxWV5_rvSK zIX->}Zwp($?Rfy+5zhAh2;K`$|MehzaKj`Yc?doVPJbnz4XbZo@^wqZ_*XvpTX44b zVfb#Czrjm>3ds3V{wr+%*xsMR(=1u+=`na=IQvUp5+)eD9_P)nuz5Y?<>4GZPrw_& zIUeNAVEvWp<(=T1&wdLZ+Qd&q{O{ls;cU-S@aeGQ$M(vX!1kA~-^16z>erWi3!MH? zzN5)MRTKXRZ2w!{GsHgu6AbuS-aOgFb86&y_>XYfkNgUp{!yNBsWQI*1TO-ofBQ51 zCKwkpc)bX}8_xF0?}yW0$OpjcM}5gB!a1M51b-S2*T<+nX6z?;L$ z<7-8DJ2=O;yeq7Je8~sE|LuR&;kn~Emo_Y)4yO&tpMlfnL2SiZ)B>E8ukQ>B-`4r}waZyWdy*!q2K2R{U7d*o-}lwW=oR)6M~7hWOS zqdf0{-vFzB+xK4hEpU#Z9pUZZ^uh8WaMmxM(4^PC)RQ=63+hF75+M$_3Z}V z2j`qH34XLmPxcY{Ss1r6c*(P^82X*QiC-ADeYR(R;@5@K{tke*Y0_JOybGLjsC*=x z_9>szq_;itd2s6EVE7AFe)-#Qj$ipv*#0uV{50$wBp(L91gk&wGX6Tq@zbmn{=)Wr7+x68Irn&Y1vvFBZvE-vrS>K89q$a=R%afb@rauWjvxx^s zJ_29Vu<`O$uY59Nhn?N@m|3cmr)@qHS+4xIi# z-VAm;I-X94KLGpQ{Aa;?!n5+;*V*u)@XCP$z7(Db)?SRi3Qql<3x5Z;JYVv6;aPca z`SOq9oa4`fpMfpU*ZJ^^uwzGk$^U?7HImnb@U#eH|5=_q7o72*fES0eetBtl2GUxd zyke7H{uI16JR|RY`OMc_;hA}F`{d0Uw!TZ?cQ*` z1-v0_`)#kh8JzZb75x4t-ty!<;q$(uftQ| zv`^zd49`JY^UG(!Y5!k?zW}GdlJA65|6hk6g|j_3!7sr%KIQ3Fi}ID{W_VsW%a>P% zvwiaBaN3K!8=UqiPl0p3l}~T-+u!n)u>EKM-U{CU&%t|N--Pdg(_ZDD!`XlG({QfG z$@BNDV*iYe}>hk<;&BrQR=$~o*&Nn_Xs>YJbP1~ycnGF{S02Q zO8;|sO?Yn7`;s?>mB*L71DxYi-W|^Vls^b7pYq6O!p<-9FW__G9RH8PpMePmFZpwD zj$ip3aF+KN{5^P{CjH~^FX5a|b;WlknkiwpTt5R)6M~KMGr)uiwEJ!#Td?8{zD4`7YT0 zG{5{1oc`%4_yu@r3*#lv`KB^n<&|K9L4J9)il2tx)Uf$~53di~9>=%5C7kj+2k#8e zXJTIRWH`r%{9#!AY0uBYr@+n+zFvT@fS2UG?UC<>=QEPmpWw&f)Q9|6*zsa|`PGX5 z49~E3Y43~hQn32sb(a4;w;JctCgru^?1R6+Tfoi%$}CTU^P2M|_@suFLH=x$9vt}_ z{0(@1-WxAJ2xlAq4nG5@4ahITwn>}&2mA_b-M;<>zY3?1l4oA0^ntt(tj^6NFAH0~ z{BL+=INSFhc%v%4yj8;_A1G!AILDBRngpkhk`IP+4v{0!Xm*@*m)hSjG${kp|RO$RU7;gw)*$n?f<1m~J`dU!K9^*TWE9K1v&kO5wjrVg4tH7rBH4nTAoIXL`15W+QC&D>~<#XYbPyQmT zetgXff3=BE{yyxQ#QKf@IZQBk&BvQx!P$QK&v4q){P4fwv=@2W^}{~Zhr9rs{l6f* z9K29dzPurhK*knz6j3oFJBL*eaqkL#Qz%3@o)T}JLzY7Yw0iJ=Z9^t z^OL*;Z2v0H+VC4;{jINc;EmxW0|z__enZ9Qbof?y@hbio@WK_p1gAf+{Au1+{EIv< zoc6pfyaJs4Bd-pp{^j-Hw3qeZO`7--Uh>wk_NslzJHzT%_H$r|!%Ull*IVGD;T#Y0 zNwDiB_48KvR5;~-8+;+GyvEC4gtPxPguer){m9>k(|^bhb@)*@`_uSmVe403`2{%r z@y77ThM`~Ue>=P|ocehOyfmyl#%}_z2d6!43cnjp{mCDI)Bnha!P>L+%O}C9pUvQp z!D%m>!|PyRWa^MRksdk%g*alYg^H!Av+ z7lhM(z?qt;b|KArAsZ^7wb<%i)M@A5Nn_K*BBocfTb z-K6MKUKY;rAg>Q+`{XU*9G~(exUT<$aE=e-KMv=7C0_)mKbAiSXMG32H^V8fd@roL z_J{lvIQ#cN_}6gStNbrG+b_?yX|WG^9yrUFmw{70`HgV)hrB*)e@)GC5WG2@@*V>3 z250-_qu|u9d@`K+lP`d?KjqKC+24o4*THFT@~tqz;3a_56|5$iKIQ1{Tx5_W?2B(jfkLkpJ1kUyte=eN;D_;fYn3Zp;_(SmBu;nY? zaqzF;nR)N)c=#E3(ZB&uw?(mU<7a^h1}}Lo*!nC_Ub0~moB*#1zpjaw*RSGFgg5W- zj&Sym@rS|bW8~A|oMYuPVf)AWPl7Lib3C35Ukqpab*`;4Dv z%i_a60?z?wd8fcDz}dg@2C&ya$|vs(E3a)h72XR@dpR9G8qRCPGvEv091rs6;jB-- z4Nm>YKY?=&lAr11{|B7o!}uAtD&tXJ5U%T69-akReHp(dJZs>9H-uB)#=jHJ@gr{! z*X8Ziu=+55O2g{oO!(v~|Jm@l9li|C@o4zT~yx=>iA*W;p$c@ms-Z&+=X{!Qdqy0B3*6C&1S4 zOFpZU{`^k*t6_EL%k34(c`li5jedl)aU)SM#;kvvhVdYaFmj4Qz?Y#(|ciU2*yaJs4Ew2Wr{^gC~Ih*q2 z_rN(GJ`L{%r~SwWz*(Ps3OqaceaRQVS-$)QIQ1#t4m+NeU;YK0{dqC`dw32DeuuK!Kp9#2sqb^@)>Z-a|wJg zZ27iFz822;_fq(~aJK(4_;HwE@RENEr+vtOhf{v}RXFu6&;RZspS(Dn<3(N*PWzPK z0%!Z>t>L+=`ge!Z9~pmeC;r3^UjWZl<^KYl`ZNEXaL!-yV{l#nb8y;=@&AJDe_!&9 z?yuZ8b9~8fh4cDO-X6~OT@Fua*!tx2;I#kG!=HiE9^`8}@n3^;ePR5M;IuFKQFuv( z=Ow=ar@hFtzOU#{UJkD7TMMr9Zx7eIvwia0;OsAXTR7Vz?*^y6 z$Vb5GALO%}c*lVJ`6~a_Ft2mI%DJq=b9cenM)?sq$AJ9XP8lyY>1~to)9hGu@S3mNOaMpJnd2&L#;*+5<-Y|^`!RkSIQ1d# z3D@nN0@v+11Fq#e56&@b{!ha5ggOTLxE8LDf<32a{ZX85Nt z!QgcZZytwpk4FAAoc199xfA~qoccF@=3U|%-vZ?o;Q4uPee&C2g2C$>yx9cK@hoox zr~c(#;H+Oh2u^#FkATxZ$S1;S&+=(ay!Fc$ROxSpKMQC5@-=W?)5$l&Y5(7Z?}k%8 z`5~BK@REPt?f6;Y91q4X0p}V@UIDK2uLY-mjNbsR z>)#Z%JoRDxPH@U|8@v~6dD@747@Yn4ZTO=dz68$kYy1sOezK3q--5G#`QA?cU&7fw z)TQ>ZIQZuH`)l zuG@bioccHa=^Z{7&hcgZg|Pn6{*XTn=bGU=@YS&L883eo&i=RqzORWVdPIH*PJ5Mq z2iqR=%g@0CgV&wBc@fU>B~P_mDPNu+PW{VEcX$<;(}S1sYr&~sc_TR6BX0xO_3Z}h zAAA{q)NZ9e*WP(R zS5bZc{sQ49^j@TQ5s=<{AoLEQh_sMgAf%E)Rq0I->_}6JAWBgY5V3)D5Rhs`K@m|= zQ3S-s`+Vn~nM^_g{C;b_x88eyW@Ts3K6{_t&Y3fF&Xijg+CE++Uk%#rUqfiSKZ)N8 zx`fBSi5>)9(M3;%w)?C2PeYe<@n45_=Vu?Z;>!d`{>tpM-zoK(M z+xZt=9NN||x;AuCDPt4e5xSC}wCH$f+h6e~L%Z$Ghj!arWN7&-`Bl*N`DqvQrZn_U zXj{MdC!p>27JVMt_D}S`(Dv~lx?p%pzD3uBwvT7g4WL2RCb}84J${I83+?u=H?$p} z_~FoYzC@3Q&f?PdFtmMqi$58n&q3!Dn)jtDm_XpAcK)dy4ib(12 z;unUt`?u&S&~AT&q3!-IekiovUZMv>+t+8JBcSc$S@bAqcfMyr+x=bqC(_724;|o& ze+9ICd`kXJXnVXA{XVo?-~Kf8acFmZ-$7H&+Eo9iH2h4y)a{!cx){>xkCLwdZO6YG zx(2juUvwjAyZuGCOC#SC+V)5MVQKiI((tE4+sCiu7eU+Yu?KoRwB27tZ-TauSJAtm zv--pJh~5uvw~y#k&~`pWe+g~-FZyB{{_oKC_$9t)SW5pBeGjyKJc_OY?bg@O@Rd*T zJ3#Ar61^9?Cp5^~_Oa714Lu0j&bRm@pzY&P^eAXM9?|2V?em%FNiKRn^h`s`-~s4) z(6;}gUx2oc2hm%g?R<-V7uvQbdUqQ7kf9Zy_$OWTLFm(lmi-T*zlFBjPxKXNJAb0H z3{TB30PW_Ng|_n{`6|$*q?}E3duY4=Q1rOU9;D1Z#ze)fa!UtNvl=mC&}&qF;x$k15gbq>&3hmbS9kiVT z$zOuD`;6#6q3tnMbhZ(xN*Gj_=hIYr-587@Y*$;=d`9Km z|KjI|&gRlr9NHak6KJ>p4?w%)O@emYn*;6kZymIKe9PW0XuCg(J`J74W&aFxP8WR< z+UV)f|kBafatDMVT=q3!mS{7Y%%H$dC*ioY`r{{VD$m%bCwcKb{I9JD*0 z3u)wkOT)hkZRcC{GsmX3UnC7(4ccx`$%jC@{pkvAx4-yt(DryJdJ1$dm;dvj-TGci zBfkyW?k}o;9NHc4H_-O^Qv3_h_VFwF&op$-xYX@g9NO;BlCKZ#*54M|t-lkr+y8!P zXdkpYpQE7N{bf9~J73cbt^O(d^IZJn(9c2VF!>U_657@$dL48g7yoT&+kf#7rs01E zZMTQ`Kc%7hxlbp5;^&99;}Km7+U}pC>pC%O}~JsyZ23T>b7MLz^>_fOH2pzY&V z^s~_R98L6QXtzF<>3CAU)D9XulppDYWwljqv#;~2WR-8_Ody_)*F1pYl5XXr44|^| zfcnF|fZDwVp#D?~kgeK)Y}W(w0u2HA+Y->)LNK6sIsj#XZh-O?3MdZ`0J6zaqjlb9 z%53E?8m#m7BtZRr8lZ9aW1tMs0i*J*8@M8P5LiCGlG*=U(N>&OT##0r%86oEjM}ea z_Sb`zkNtr1rSD#<8$2>rFuIxC4-$ z?*P>w!aueDpJ4f;-x|SXD+W?(l_?I@k>AoOd*uN6Q5TT^5rEon7@+uH02KFP^vcdr z{;7Qe$dmM{532k$|5WdOKz5!1RDUxd`F()+>T4<=3`p)OApS_|OOJj-$_t)>e)*?9 zDZg}Vs9q;P{#PSD`PC0By_t}gKIKk+DOW02PE@ZfVATUl-;03k?lyMSfn~QCSayE` zt6o(=^&ST#zXg!qPXO6#OnuqQihXuHMGe-s@ujaF|5SesAbqC*)qfjd>1%E5>bFv) z?+vj0+ivvy0#?1sfcQ-S>01s+PYCs;N56HV_P!35|1Sfow-%7TSmWmnu@cszXGy%gnH8ZEb*v69|6nWpI}_@km~8%{*r&j$m=`A@+%YeL=XvTO zYK@`tPruoweCYjm_00-^f|mXgVA-ofxnd6o>pU?F(7CHUe2o{gz#4BF!B_vNPq2!w0ibw?1Io);KylQ? z59K8ba>y{7@iQHlEUt2$VI*90ri_0cCkJAoC4luQ4s0IEInk+b~3nEW~qmYwE+`eS=Q zekB3Y7l9td+0@8~u&?^-0E(>NW+i0LM)XR5dE^ye8?fwd0n5%HKyl?VehxEwgQ+b0 zpP@|gTmclXet$-B>icPmZwAWbPZjD*ejr$W>UTZlcOr7~a~`1buK<;Az)op!J3#pu z4U_@&`)}&UUr}GzN6WCU_O6Rw*{cVZKjXnV9zu~<{~rL>dGr)m`le7{$Hx}1?Bqs| zj++hmEBogF`4fO1Z5tbBZ7^ykB_$_wC!{PThp??(8_gYJoo{svI|1>q|%kHS}+ z4+6@=U&h`w;!?fdM*kVG>W3IT`H@roUgTGCcc5H;J`70DFM#6Ci=5)Ai9Xrs4Ho?r zp!kDLTtm^X_Q-1V^kH9li2;VFByPFL(G&r87aXD3+s z(RVK;_Z@bn{}_3YUj3G?%Jut~(&wXG_4J)6^|KG*t6z43uYURnSowbpto}F+zY+Bu zLr!*bP_F#s220O4K>9bsS6=f{F8h(XLghK24MN8Z?vmjOJhXw55b=N z90yjMae(r)6i~mp0f?U&d$N-ZmLK~4WYr&N?41Tn|L-n2{ zxZpVlUva)bq54A-<>L3IT=JcapJk{g{_DoyDE1ZK7(jmBLp}L58mxXZ11x`YQcv*= zHU3mVuli9du=4aH`jy97=vDb+fXcJOm!9Ha<*7M*#j_l&d~N`g_n!gDcgLRO)_|p_ zt%-Lqw2qJUVEO+MSoOaIt9}sr73UfBD()#@`SU%Xeo+Fy6_s~L4y^Y74t?tHMbW2t#{%;22S9orL{9bRg5}3K zuaq0JH<$o`*>U{y0pRKT?_Nam1@?$tyd7qCy;RHZ-BhaHb z9|kMVnP9~egdX`F36`G~$)j*X`0^(NeX^(f8uI%g%BAlZ^3vBFdGVu7y$?(t_1gf7 zBQN#ke_Nw33M{|Jf)!6O>M723#@~aKE1o3EWq&n#RDT(u_D9U zUiqv9U-kb4Yh0^NJ&k|&VqbPgf#rWE^vb^x_#-_(0`hMJ<5;CBGcIs;~Ee`18zzk4euJu#U^Jro1UMqSkl4#ZTg&+Vv!$cK5=U zUn{_hcNF^N_eWs)vjmXcC!yt68S2aaHRQ!#PPzQk?-|OUx!9GSCjsSoA9Bk3H^$Cy zVAz|LSFSh2g}}K z_!^gf10+8RIobIbzV!Lvt9%6@y{`Z&e+4xlnR9^o9WG4tY3INQ>3s@0*YTnAcyb~fcv$f;g6oRYpS_$Pa-!P2u8EIr4;lGE>Ks=mJS zsW>Y0PjWp?yq_bd@<-7txhlraCibPLHGJtG319Z!1grigQ-2LKsy#)Zr6jzd2-Z45yfYlfO2GobwQD1#BGe+dgAh3MPO1XS51D4Nc(61Qcjow0( zD>ri}S1z6b%g)o3%l@-q>G=bYTw$Xp4lMZ{=#jpEP5B4x%ibc&W$z0^SA?&ej4}4d z8r<2G_lH)!Wnk&m@1LlC3*r=R0#_DH& zk3dTGFW(sZ3#q62FM=f>Vf5xPKV_h8lg z4MO_vHTK(5Pj>} zf@QA{F8$w9t~_4{OYei!6Mr3i9d`kgOKvw!0`;Xo zk#gBb`Fmg;?;nH3*S7Z2ICA8xC42&vI zGXLc7M6l}RF!7ECi@({(H3swNS&;E9x%1M6GY%G(@MemZTSnWb}DA{y=CI4O}X;+DOh>?(csKr z*^dTG|0b~f=!(CR&x<|rdl`ET(JTGWBUcvuCgsY{N$jYfd_%d$odyPfV&p3r{1jMm zodoN+OaN=V`UtH0#i^(AR$#>wN;!X?_4p(DPlNk{6-QQ>^7kaP{CojF6vxA+{w%Qk z-H4x(i$z}ixs;3UVCv~2Ty#xn*~`N}c0DVM{4NNM=O>N6j?nUFjEVaStA>Ze92d!T>g|quly}z@;e7T>USrMzL$*rI-~aq>ZzY?1}pA3>MKvN=vRN~ zi5?w4XW&cEaq3Av2AW;Z`{-5w4S|+_Z-LcLN6;hwcKE_O4F162onXnwBCq%>Vo!3r zD3`uVVENM&zVcVi@b^-VOP+g7c_u0;{;?Dy;yFOM{JjRDezwq*@1k7soIqZ2oHcSw z(WiXPg_iuA)RUgN)RWwE@D*=g>M1Wfja&n;{9Ayq>bC=n4nR)!vr}JwPXep_7xbvS z1$j~VS+M-+1z+u0lzO5IqgV0t1FJnhK(G4sS%V8BC;8@J$$f9|UgTB26urXDD3_hj zjGwPT%g?LOila1gIxhNRpFht5{FA<_lq(NkLCf!a$Wvs!k4BO8JAKl#ibB!(Ox)|h z(pL#P%GZ9F%3pP8jpwtFR~%cAQ=Gqmr6<9}KMQR2JLAuL)RSKwjr}v|6MX@!JZ6C} zKl6a)X8|xOJ@rg^Zt96X$Upg04_f2NOlZXugfjKNsSrB8UI42f9tO+bqsYmhQs`4$ ze?TjqU*OCCoamE3`gV!@I0aw0Df05~3FJh-1s44q*y^WXwX1$FQhKIPU-~DZPxdB* z<9dw&qW@)l;|$WFQ9f8OY?ZS+!Py<;nz`H@kdcmu4urLm#Dal_Q9 zV9L8fqt^NzJK-LbD~4a6qpt*Zm7@;E{)gxl{Wi4x9YQ_DQ384C-$Q-nOuwI?HXH`6+;u=s@`b1`{uJu7 z>j{G||5rmOo}HA-k8(y&EcKM*Hk8ZXjg+geUWJz3KzyH$Z>7G< z7nt%^5NhMWl*`|r!HTCRSmjS5Cx4zYdN+V2*B-v?C4;3mKlUVF6|A@hQ%`c^ja+|d ze_v%J7x9Fk}B-^hj@0u>5I{ zy!3WAdV7Gy-vdU4=O9>dEk%#YlcA~V$p%yH^Ej9yPYM1B|G+;?d0wSlaV&;V{esZ4 z*A}e$KZB*OC4}^R4y`e{-lm6$x%FijVrxUu6idf!5yj^zT-(pwfe>Dx=W z+VgFre-!1?SBi4!A8hy)DVHAusjqyz0j>VNje4^CA?4B&1}%OO>Io;|zs9m@l*{iW z$VvYbCeD)3Dt{Gu`LhKqx)1Wo$M4utJR^}4|5IrBU)$Jw3O&;IDzy9?X6!5m%l{Lm zeiVE}J(Kt+e*@u5&p5-6hEI_v1}uI0JtLj_XTz6#DVT~c3R?X_om=$lhOPxIxhG8h z50IC?)!|F-3RwQVW6IY+6RM{pSna>S__YSU=y}kx{{Xb|{0Lb3V~|(Bn-5m`ez5ZN zC49v@0Hum^DgVU(4Xpe>Ou6E{hMeLXKt0*NV(2Vj`B#{7>3IfP$LA+t>Hn2-9gjzd zPyTtqYTte67kvP%ygW>~>{J0$#iQ@LvFphKmRxbL^6{>rSE8R?&wPYbKF`!2Lm@2B zHlue4gyP>}%HO73d8lLReFtCt<|+8X4?`>e)xe75BJ#2`3tE1>1eX8r8~PvkvL6pE z|6c~Hej$R8-HF(dp6p=h|IE;P;7e~D@)UV;fTj06u<|?xzVr-+spIcMX!-p*l_dAH zDQ}Iu+NmD2_Ms{f{hy7Ue8|b)O_a;e z6_iVEGvyR{RzXW&f3W15U`KR)XvtSYjv~)!u;M91CCMFvFS}7N)gQ+}%m4bwsa-4$C4CQ3F281iMgIkso=nD06;uC3%9Wo)Q@+F0 zd%@UQ16I8kk+<>;t#---t+@6>D~@l$6j{FouKe{d^fvUe>&eMK`LP`#$)BTKd8`So z{QiVp>HQZu+4&q={qJGq)IOJ>xb#zMCa_vY|IqsC*x#zVzouUgwD&@a1P4u>9#ox#BtuEx)sZ6<=$x z%3m^mBtWZP8Dn>;@$(tVZx7c zK~DA}D3|;Nu<{ZBRvcTwvbP#}@xzVXT-1Z*X$O{{??cFssYdT8Fn`u>zR2!B$cg_N zh0@d7*qs2D-=nFoetX5}d5CiPc?_Ce&qX8Gjrx-B11&v)(9+)-Ir$q-x!P+3SoXdL zD<74RQ@qwuDhG5nI)bQtkMK1>HIDZp);jLiBTMv1))A#U&`xrYN!P2`3 zEWhr9FMmV9%0qjw>@6_$R~Y%r=+*flhvA<$^2OjQPk%wHJw5@8ev)#H*K@$?r;kuB zd)c7XPKCj;I~^>4J~s8@pk@C@XvMJxTKRnoT6mnn;|-o*@Iwag0rTg%#6PNfO7l3Sn}~;`Lo!R?*=Q+{}}o8(ENGs=bzf6pTV=i zs#hK?`3zL;(5-{AAn^yQEVciw;fj`8vc7i)%i(S6p&JxNmSs z;{mPXB76f{MJBaM4v+FB4G13@(JLxBHmYx2LR8{_;KcB_m;qgUVG+LId_vsFSF(9C*J?0+SdNGl7sBeyDpuv!MJtAU^~8+Ob>1C0f_t^@)+Md# z?g?@6zJ#PmUt%v`Qc`5>@Wc?`u(0Ilq@KP+%jHCSr%PCD*l=G$Yk0{CK1-Pq?GPRp z8|sVp;d{I$?@@M_C*ATCq>4^Ci+q9xR{u**oaoqk+Bi>eq3C%+3l5-Kx`qA ziScoXzSeQEvA%E=gy3>QWW2P5_}!+h{Cj8xtHI zIXpJT7n{_DCJl~GicCrdE1gPEf-lV8$L|;)ih`5c$5B72dssqL@Yu-2oL{Irfsj!iO0 zb~|5Eo7m(SUxGSKDvvCwRBU@NNKQzw4&l+huD-Dv_DEvNVAD1(A;y-Bi%m+1i;ngs zID;J{i7Dz3%UB)Dh~`sgwMITh31_59H4Jq~r~aMPo9a4$-C%3aMW3!$M+2V#T=rS} z_Vei~AB2pqHMKvCeO=FLU(dhkT3`FxxRkZFE@rJ#t-A=$f%55L? z?4UI-qg>Bl=$c;o^?b9vzsV)@Hv76xmCQc&HMh|IY4&a3^c+i$Mq$3Y&}1)@5DmV?$Y^m)EQ>cBF>ls+vXFV^VIhX9-3rJ=N&=Zi1>gLA>TVD4J>~{GATap*gzOUJv z{YJ*tQ1&xZS2EI{$K`{b!?a@`2G8!3C6Tw=SI^ejIn?tab|2WqzAgVD`?hbo?;?58 znuBX!@qUbq=9%(A&!cG0uKj_?NRRSa7hAUe%uKRu-)1ADx>W$JtJuD24M1@zUPP?A zqW8MWb-&H_v!t;lfAp*uVwMj@k+JtR-_(A4AkOT|H|5)IYuzieeb9QYs>&bF&(9Br9>@a%T~hjLqI5IMAE?qT1qt9x*Exz@eyel-w1%BSM(NbFii ztpdCa(B&*2R)X!i^VqkKBi(;e4&|rrz1p^PA3%AKPOWX)IZ0sO9*3v1Zy&$9FJ|XT z&o9_|sBUe?KHXj7OqHw^j=uco*L@$aUaWcJ9RHT7TkV@Ft8P4Y&xr!QLaqNie*dPw zul>=lU(2&QpEdZw$pM5Df%Tt*~{d;t1pK8_T9x1po_qeXV1@*a6w$;d!TZ&G&IwUmbIPco+@1L5q z>&VQ&hRqs3oZlC@@V)19EMD;DzIKscG+U5q(wcU!H7PnR&(>L2GySr8#e{Y*ws`W) zgic)}mwh`t_d_l7uKMEL9TR8gAN^dVV_hm_{kV3vI)6X=;P!dbK3M$q<5fn_zrLb& z(Uada%TnU`G7}fR`T6LfH=>62|EWc>XHV3ewCsA_EKmOU`jl}6Chz*G^y$^d{wY%6 z)$bQ}>(OJ=D|Lc0W#Z7a)>b@c85Q>jMBy@&6#rY?^DMcWY3m(*UnoeeI?Z$JME3M)PE@e4jW&p-M4=IC^uqt`>vxNhAu9feaKR!rHuf(@t3} z8!<4iFkWdm(&qL0XR_YBmGP8o_G)GP*s>diD_<8u$}db$GS`&WjMtmnsWX&WuT!HE z&*EuV(B{oy*FYkuh~+6t-!10yG?x+SWjT-{G?4q^8jiGi1I-0-O0*StRl;elY|d4$ z6J|1}jg*9??XOD2Pvu-*WcSa(wQ}O9xKZAJa`V>}W|0&k8lFgavr$m~ULEecZSE>~NN69D1ILQjK7X}>m`Kqo%IH$cvp!EVr z}3Q;?Be~dK)n9d1&5ibhO4u{)U4HE9&j_WIdds*p32T>6FklMP|sx|m$=S) zh-2hSWSqPgLWU#LHIvm;(vjU<-!)3*^~*Y|2L2I5-Es-nP|oq0-7l8PuW=1s-7>ck zFl#N2v5t*gLrhV>Q0f_VD&NXC_RnpsPH1%6lUYY+-X<=cN|)9K9PamUodYtb;aY19 zj>x8_u0EE}En=-3IC8U_xyETnl~#QmkrB;Zsw`jJ+-5D(`T{q#FF`F`3bNsgf91e2 za2mdI)a7ussUxu=*wuUTxFk|#_Gl~r)svOkLg}tQG5SWtB@d1ERV(Ai&RF_(h^x!w zPQ6a$_;I|At6B1>GPfaGbT$qcj_fGN9gyit}uh_gV|do_3&|13bS-~g%zL!DJA67 z@VJPzHgEQn!`oZ9vgL9}WCDw}tO+JoD-#);LE** z*f^I%feaw2om|=5)t9rUECM=-8QjO^O-}dPpd(VfpR2RyO0{I@$kZO-8p=?UvXbbC zj*vs1&|QFpb&?tQc^ipsF|I#9~E)N+zhDbm%zIb5rzDZZB(=}JaEzeu`4W{GlH%IRKZO>sMOwA<~QR$m>z z4kG7VEf-90QPvTCH`aBy2itR^ zjdrEc>mSWif-W)Eb!n1|^hz}05Jn57L zFXp9;J-QAG%v8~n=gHh5xn9rly!Tvy5AyEj&cKX@Q@XKs>p>$LWOuOl*F z&!1TRnF^n;UEa;xEc&N|3%!|YTbGrisQS;P)m8t>k=QKH=91qoDfM`^Z3Esb(dzP| zaj#4*ROqW0YRnilws*h&)h|^2G4nGswv5Z)vek~`k8b*WRdk7W*Bu&?ufYR>jVm4d zF4Ls;(eIRQyme6PW|f~^xv{{{n;)w9Lz6QdCv{|Y*o{8`uiyK;YD_sN2pU;chv z=6vTiW_dg5#F8?#7OrpBdD!y)b2fcf?1RyRLjNrhG5VfSp?M2tnHuDdC z$kAC{CjD6LiAO5!INh!Hmd8FGIC?>!E1#ANYqxsXv z8(HPURqf}VIJ2xs$e^DtmHwyHx77l6yBAe5u_%(Yg1l%r&HsLte8@_>l8IQL>hgg;x z!lEO`b2r&oH7f*JizB2*owX#W&6_nmCZby>jg47lEh`i5tQH4eHh5g`hWo5_2aDeb zem0x$jSd^?i>~EVj)&8-&xvdZEkm-7$2wlkqsnKeBNO(_#t{J{QMKjdm#yZy1&E3Xtg_&)a*`VDw$ ze(Shw8$O-zQ};9lxe ziN;YoOJ{q0$DDojgUW1dpZANOYnJNLV^AY+$X9zeH5qbsX}0RG?i+gT>aZTIkItF* zM!T_fI(}St%efMRwjMt5@8ME6ir1JpereABixw~Yy+uTcx68&)3JeHy`niU5d#$H<9ecbyimUY|ofiKT*zdSW&c;c!@N(Rht`A6L> zOMjWYqISiGb+Vj@>mE9!`mm7D&TE&JE?uZaOjM@wC%12?5jLjlQ||@T`6K?yl8Y~N zt2U-=`+4P>Yz+Qr`_tzN{&Mm6!1pFqu6o6c5qh=$OYiuJE6R4>v3cMxTbpHj_?-f6 z|K9h*uiHodaC%saPkR43Yw+sBzkWPDV9oC@SD#GPTM=? z9sbwg^9#4;+#l7f>5K2|T>0q}m5%=0XU639g+_cbCGUv~kz+sl$oJ@*q0cmYw)e?; zldAVUabQj(?=SyWYcRHGaFc*R@16EcEp@O-mtH4x?-;O)-uLwE+EeL$8or+#;qQKR z2Rx9Y@ZpkI=3Rf{(w_U~ln(y=slV;+my;^K?`D)q&UWH%|lV>iT@@Uh^Lw1e5RPML=Z)Ta>FQIPe;s+~!cKNTm z-B*phP@s5+dJoNBF|~5ndB6O=`Hk9t&N-aivygi}DgvRkh% z7ht5(w27*WG#ymK8yMriRn9@{EuO(JC_#-zy{YdEYk@KTo9jB-tz~4r{%vznmhRlR z75%OjF31aQDI=&^GUYPZdZyo2dAva6Pk zi%~3r+pz}~w8WLqd8~6g`7GoYS3Yl0?uaYTs8RV8PKA#8!mM*suFPGh+{s*EYyYz$ zj+J*g_t~|))~bgd8A;JPnAwAK2F+?cN|M4%V2#{%aaxWkm;58wtYZF=E5Y;c%JLK2 zEgbPy$b0jf&n>xPOqYE2$fbE-l`HR@&YkJTsX7Jz%|4`Q%UMsD;p+i-bKA`u_E>0K zm(97u`rbEtLXR=eRh{s2p@F-aUD+1U^@(D;5+6#eGJ0z5<wN3*>jaQLei zD~^soI;_x&reWn56|8@K&5VNs%V*o@X?&&Hjnjn!8+}s$!h*sL+=G*KbeYsBMsGIz z!N5e1w`>O8fya5w(}h7Oe(j%;=A06&Aj&Y|) zWVHftcsFp)Zg4M)meymHdREerm`~TVBbc0H${Bx`m}0s_*RRH9`?Sr~@>6HEO)T2$ zhxo+k;^W+1;>V^Tv!1vx>65LaLk=$}`Dw3S9I5@x0la*c=xc$`H;raVr zTeqw1mgBvTe0=@>aaE^;MwIUtT%qKb?PEVp)x=bEZ&TV%`N;3m^t}FFTI76>W4o>e zj49Rkr!ZgfC0olc{yab~X=zQNKHcx9Vt>2bnEB(D`O^;V%9Cwa!!4DkdwWj#XUocA zzhZR6Mu}E-yd~{^E z|Dimis#RE`&zmR0G>Un6i-z%5xqUCR-BBlOiiauP!+noa!;;>Vvb)FdDck+YoZQo& z%(HJ#{jK|ujz5+;aPX~JZ@wSi`Shj-+{sKR-tObJCYc%n_U!G@ckfe&YqmI&x7@() ztHu<`C~3%AgI?Cm%{{rZ=!E)zBFLU8~2YG|3RJ_tDZj5H{S>2 zKClNPYho8;CU(c|iQP>9#4hAcCw9MSV%PF^6T9ATCm}d zz0TJCeb&iV+1C6q>AQo0Zw>tQt8JxL9~-y-V!Mw%c|ONT-;K<#J@UfZB26a8HEwqz z`ue7ld*Zj`U%dO^)1w}AYqM;O88Ytj2X*_!cRKaluWN(L z$Gqk4Z-(S93{xx;G9(wC|_sShM zk2_y!cZ;2`EUG={ixQ7CuGxkA#-4>!lc$*z(aczXcWl(+fiCgeng`cfSA6rdA!U=d z&a1!HJ$7!X-J!S6ZJc1ON8!R7^f^EB>sOn9_tnG|{+WVKUosiJs=z)%F7uD){^uXEDPdy)*b>!-Wf!7|m z(%{Fwo0^?VD%B^xTSS-1Cx?YT9Wm1 zb^aWhYMkaVqDh{X)-a@Xod0CSYY6iCo}JD&)`=}ZOJw#%&7CfI4W;&SqlH}_3$d1` z2Dj!E8Racd*}tq@txTKItfU1e4EH|-pzmktnOOUB#hb@jxboKw3eucWVqd#YiMd)O z#EnVx@#wkUY)KIs#l@Q%N1NBH)wJFng0fmFD0z?6*sEN#YfpR4f8xA5%fCCzzdOsn zJIl8QjiCSgXZb9TU-FM!_VRe%FMB_hqifqz^D7+L+4k%9_Xd<)_(i%`QO@$Xxr(~u zC{rY27{ zC(gT9P5GW-ZrFU~4gowTLHER8YLiA355HH>vk9RWUr#~K> z6K%?5Pg+yT6}2*)!jX)(-p)oua zUoENpDJyC*#h`4Z=uKZDeQj#b1Y%KE-8$Um?wZQH-F`lN2*bOSyxIPyj>BD=zHe>` zw`KRfS|FS#?Wp~2<(9ZrKU9{KA^(vOZ^fIoM83rmO#(RDl2$KOkI^xtqeMrPKjZRd z82iZ$>i z-{VtzW?fbNkN=lwGN2m+_PVb2H5=6mx5@;XyE29K=zTDKGf<1o%zdqQQY(OUw^{Ps zPqKcynfrRy-LBH$mVkJg!l=x&m5rv7ZSRJsn#1BrjU;Kr25W ztF83SXyr~@Pe9+8mVWU?zi4Q7t@kMPO?KNq9zV9e*>A7$h~Dk09}4}Uk(d46fPRZW z^#g!@z}L`fPi;I$Y`r&a=TG#%@D-o(BRVHL>c83s0R^EIk2cZz2D17K)ht@?SgU_% z;{jvqchT&dEuve)mp_sp0(3R?*|qwr-nrIsBYqg5-v;2euC)#2{|so`AJOxmZF{1h zhnD}^M6ZLEK5e46L)+~kTHndE^B)eaZ}i*xBB0M2K8R5=u&n_{0x@w(~h0THmI2)Al>Tus8!Vp1`;JgXnvq?fi?@JG*xO8Ufu1 z+8(P!>pQ*bpRzBy2eh59Na(@P>d%T-^eAXMUs2E#paa3$G?q+(w&NH5D75XLXnnU- z_N7m>zMp8v7YnWLW99^F6Rq#pDjsd3_om_N8~1Mh8ED%d$$tl(Tb0>F>wBv5NA^W4 z`D$Oq9}nb(*7%}r6rk_$@_2!@iEaRG`zN|}8u?IYyT6DZ0d2=GIxda;Bxtw3xrQ%) zB)=5e?ym{ZuS2W7w29XDA?=3;MIVAzY}!O0fzD@9e)G<94~SP0P=Ayz*_KV&)_GfH zwE@)&0VLlJki0;;WLxq)OJdd6Ib8ZX1M*vKDZTXo)#(H%cIlK~k$~jO0n&dTAi4H{ z^s6t5uWJR_DFaAf6+m)T0qK%0$<+WPBhlbMp;1hDg(+-bwGYK29$T5Gvr4lK=HH&q<56TwZN+10Z_ddL-zrz zy>zW0y}GuLzFvUZH5?GX6rg&shOPis{B;1?3kGDrA)xY>fb91GRNe-V-2H&;#2dO5 zSp1%V{L{Hgb`k)U*94TOwt)2Y1|$~&NKbP>32P7X2sGki1)P5rYZFk@Q zzx)2b`oS&V|L;uC)xobV!}tH+L`XeQ+wI=}zl5xPHoDdO{|z{VGzw|+-t_+eXt+8i zv}O4Ie*=2E<5oKF{~w0014Ubg@Bhz4gQLX#{=bi7O~a`+`zEXZ{r_4V<&NI;-~W&2 zq(CC9?H2F<2XSuGkfH7N@Bd#xS_7N5JA41X5$7xoRoXIm|NkRSJC3Irz5gH2xl%)m zHs|@?loz@hFl0NemCpPBvp8j@BrLu6|8=r8<0R|m_y4a~^$+Wojr8CD|Gk>4*)o3r z|Hl2UK+?YdU$6#=k_|SxR_gcvPrI2Zk5u3MEVDjmk%=i*O;^}Az5hR)GrrUO>AwFT zR@>FQ>A(M9m(#n`18#c%zY-T$j)@H3|Nj*kC-1j;|9>ABlg=oW@%#U;a&6=spXt5- zKbMOTr(0(9{{KL(betjP_V54K=R!-@NZPy^z5idHt6)dxP4EBz4cAGR^U}V)_)D@IA?|=IK|KSioq z-v6)D!8Jyt`~LqWB%FY6{r>+S9aH9;-rK(af4y_cY78$1r21s0lkUK7t}yTX{r|$< zU16np|Njy^T@`ElPu~B3fy@4sBQW)={f@u0d%FC+)%*XiG8u6$hi-oVe@kyyUrz7+ z{{$vEjyLJQ{~z4X)!8$6|Gy1$EN3W7|NZ~+gVL(G`ThUDnc_HVGJ602Q|2>Hmreiu z|7}dooX&QO_y3nhxVrVN-v6J^9L5<`Zu|cKJZ40iBy00#@c#dj;jVPt>iz$4rd5vV zo8JF#6zOW<^xyxlGt!leTfP5ZILc)ygZKXnMZ4Y3`2GJck#oGh_51%H#kvmno8SLG z67M<&(|`Z}nFN=MoR{r^7GUFU#w-~SJt;cDR9zW*OM%YFEy`~H8&*)D|{y#GIEjw|Q?-TVJ# z=cSB2%I?`smzUQo>RmJV)NlP?Db(=58)X~3y+7fx%Zt{ZU2x%#EzzB-4K2Mq@XdKmCj4&RC;jn(&wVPUyf@YF!23JZ4*4ttv<3l@YNF2&*#nk z()nKB)L-AL=l*4T0^1$kQ26tS%d5ZiUexBCCqD>i^>E8sLqF-3`^EK}!eU1MJHO;- zC*Ell*C95D_d2;+?TjzxQGPiiM_m?jl@y@fSU%S%m=#gKu96R*J zw4$Gfb|`l2#M-lKI?nDopzzv~CI5;KdS_qR5zW4Ps>k%6u_veRyZTCr8`nCtU-``R zR+qBHw0x#;*)iew{&H>jspTyW{k$&A=6-Lkt~>Rw9OHi+8{gsHkpT~_t#M}XzY#TiHoN7`=nk-&b8>CT{XtB(X8MbJ4bX7rK3rd$F#=aJidBrq9S=kog&9|?R1 zImg4B776}>>s(o;Gyng9b03+qwhZV06Y$w_+dcn(fGfrH=l>O%5;%I(pZ^cNv-y9m z|7iYSine#g%{%)3-_YC7|Npv^`Tycu&;KJ>YEEeg=VK|(<<~{l2T~H2-u(Zba;_mV zz4?Dt76_aRs|@DbiOU zA5hhGbf!Q5zkvvS+uw0Bp8sdR-xWyO`G4u^uFjHn{(r&Eyo34wo2(Z&4S3W1KcS|p z`O}^M^975P3&`~6|1D~}L~fe@*Q)C>k-_}`Z)BXj-)8=QoV5aH0Lpm&zl~)A4t9S- zq&NRxzyg8OEi;<`k7(!`Vs1bG4`#VQqrA2Z=l|7NByfhUo96$4x1awXL&WK0x0wIG z#5#d91gAg$pTQD=qw1#l|AVX!ID>4AorMvqG%wYcibPt!mx0?TN z>*>1Exq1G-Bh=NG)0_W4%mRTk9;842@7&kb*)y2`cYn||l%+raug>j2=a{k7+&upe zyp#F=xgoCHq(A@PJ=E3NZZZE~!#aU8T;6K_zlenbXHdEA{C^><1-G03zckF1j$6(D z`Pg5I>6_;NAtPK3oc{d3d88{Dx0?T#9qF=^!Ti5Wl-uo$=l|a$=Opab^Z(CdT!;J3 z^Z(D{T*qMg^Z#X|Tux;$|DT-b>Y+Ey|9d67(sv%-nkZUv!d7 zG~@Yy|7ossK)Un)eyk8UL+fql|9xh-51(}B{|jfj6lO60|8TY|=l|XOf9Twlu_ss1 ztDb;>J)WG~1NLM;99Y4BqPYA2ZU*jV;BE%~U&+9fZ z@XV7-4qUOR=!JZ7-~F+9?Zq{%bF9c+Z{*+opIu$J;^a9MioX0$+a=#--u+kif|tro zD*EY~58FQWN$i@2#ScB1IQh#;M>hQY&GZeAO&Aujt<|)-#{(-gb*~j>;_7FT8EiFS z@fL8_?Oe-z8GbJ*MJ6cA5UM{76acIR#DXach$(X3fatLC;|$O3^Cz8o|^oGw59Ue&CGk z{@!){_2G4^MxLm*`IV6D=hvLNKC#s|L)5!)-vW>6Qe~hIR{f*NjH~yp{b@s~q91pU zUbxB=5;r+I^sUQNpGw}av2Iw}ZlUl z{-#L!vca_<`V<>jy>G&Sm8-h6F8*@MC+!1WK2|FoTci4lb7f*`nl@qL=J|I0W9Qn; zIQjOt?%xK*uZviF^lY;=f6spDpUU&5UuvHJn&{Bwe${D%^Hs!s`zl7CmtDA;kVW0 z0`u$}^48L`Q$AYfZdioUY?<_BQ3i(TtlK>2pOpzw>_XH_tVhw*6w3Yu!@W zo6_DMOQsj}R|yTPFu81xl~*^ddm!`Udjd+sB)c|@u%lEyrUKsM%Pucg> zzgRcx>uswIYBF{p|8r>Ez5nl;yrsT!Px<}7|2OXc=dYMDqwr>Y|9@{K z*IkO#_y70a>z?MM^ZS2#c`s$2lm74j?L)?%*m!Tg|9`5AYd)R+{r{s?U5mjP-~a!j znk$gB_y2#rpKC;O8o25C|83P>%saUMKf8u2?3?cYhtzbf_NROQzj-ZJCrkhSf4*DZ z|Ifm`{XjdK4DSCQM#jneZSMcCy0iQLb8mP5Kk`oQ|2J;vx_j#&m8p z-*o@~Q@BpLoSXKkp8tRG4)6buyZ!zDez&~;fB)_8|NnuAb1yTU`~Qb-d;kCWmaYz# z;r)NTC6LGNMgQsZ|7-8${{PMpSF>b%|9@*+*O8mf{r|k}U1LPL_x}$e;jFpc`u_jP z4z3%5x4r*=s?#0Z|3BBo73Q7a|G&&*1I|)nn*0BU{>%IS4|R7fTIJ5*{{OHZE`M)z z|9|eS@Bcp)>N>8{yZ_(q_V@ow-NF6;a<{+#uh)T{Vv!i z|6g#2_y5P=>HYuc2-ofG+ur|=^4LA!FFeB4!0F%r&l~AF z@@{qi|1yHkJ^Kvq|Nq8vuG5P7GQR)+c9cukt?&P@k8vIDH{btXcl-PQ33qV+zt=7A z|5v=_{r{|Ye*Zt}&hP*KFwxc7Grs>{ZJO&Gkna8eD$`vJeB1l~m1npQpLFm4N6mC8 X%;5h2^RrzY;lI28Uw3ZGNcg`1vjbuq diff --git a/.vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide-shm b/.vs/MeadeAutostar497/v15/Server/sqlite3/storage.ide-shm deleted file mode 100644 index f4894a1505861ffb3591e1173b350fb8aa8274ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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¥S@WXPkzS_A1@TE+_@uYS!Z{SS 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

mgXsl?eR(HaA^XxRzW2zKO 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�^cZOilUWjX@osZWp)eowx z-%!8acMsP|+47Gig%zK)J;$%^(e`4OzS&+&pUHE;F)hlx^?Ztr+J0k~qW83zG&9?% zj#}LezuV)6gh`3px?sr7o9q9v_Z@&y66BGz3 zn?g3(u$vG-1rku2f`Wp83SvVMD^@I^prV5MkYDT%)Q1mIQ9#7{f8U)u_s(uM0iQnM zfB#;X?3tM}XU?3dckawN)lIV!ofGK=SY%MqB_Eqz>J`^)YYs+GYb-;INvV#A4zveP zGQDGjE=-L~T^xH4P)lwQ+zdqOyVMZlbwphcxq;LS%Wb}LX-EyYesGN{#p(g4;iR5( z19u#7c|%IWtz+T_(p(EX9(U33BK3?7DxV=P4|JsAH6m%_elZV_gnTu|DhI6u*Y4=DSg7`MP9_9iZrb zx5XQ24D+vrVE#+2m>@~*vBk&~&=8L$5?Wg8l$CYCgv%6CjSYUglARcb1a1ovCEtux=(ngIzVp}VrbeBc3#R-J5 zF0T(3c?_J7&sVstZ5&7pL|c`p2;E90{RV|qZIu;cR8p45Tgv;_W=a3iPAN%TlDi}UVo7iX}*M2efwb}!5DXCC#BetNi*?US(eOM(r+2^%6r~)wj2kc7;DvQ6hoj$MD{Zl`P^ITc&@R^B`H$WTO^S={)QH`9i6X98Jyz2dV4zIvqqMO)DvG9Mz`z^Y zR~e@bQa)%HFi_fEs*uunQDc8ctT8xf1Q6@b%j^9V0#V>a=+HMZSev9YzZj)X4UCfh zN&|B!7=DsnK0w*BYJhPFXS%fu0;ckZ;JYFmD6bi)G?{pRtri9!w+vFMrFNjQ3j=Kt z=5k})x6AHg4l@T*lrbVk(T!nHSPL!S#;{%AXu3+t4b=OFDoct41J%C;8rU0Bg|>Ck z`ur7a7)Vc!P>QL&J9EFqmXK&Hgp#Jad>x!Qo-*v#7!%lzG^JQpb|kaNYtxmXH`?sp zwuXrs%gF^^Oez@eK^EI12F>9k)gD+)p?Zu`_^s=YF)L_6UVHnN*|1s(SDsE*{3iSxZ{Ww0cXb6WlGbE)J>llJe-)Oh|wlSbF;2KnXarp z;$SI7vyY;^9ocM&#sanx79Pnk+7-uo$73UEfe$Mni8^{li9Wah_2mi$)e&HF#Xd!@ zGa{~2=75+KpZ{tV>s(9te5HcpHRas~lFhC!w6*bv96q@~?LLZW7g1h}y_S;;6@sy< z$rlr+*Y%3bqfJvVw&uplUcMESWO_4;d`|HJ=gNs1CquFM`t}lY>_M(;=;V2U*M7Y) zyWd5>zKt;LDcWDSblBvn55E7~;$=T)_WZoQWy#9or1XO$Nr$b%SQWo-n6UQwVZqKX!5qp)|PZ`Rrln*4?WR&-7AlkZ*op(uzrQL z*H^!6xueyf_lgZEuRXP?VZ!%Al8-wEwJ3If^ZeDnCZ%7}{oUjhmu*k#HDzPF z$(NpZ^WNsWzOVOU+HudkFW1ao_x0MHhwF5Eedpy{BRY>8l-()0$4icvif`<>W5O$G z7k9cd*3zusb<3M zy?udYJ(Q*rY+t~0I{O0s{@A|2xp?JAPuHGm_XTWt^T)^~kgDtpe0u7Afd@`=UtspB z_XQ@^xG&J9pHg+f_XU0fiZM(D*%#Q8r1ZL=`vP~L*1o{2e`a6c(bL%%*m-*U0xw|d zt!ZDNA>R7!qH=MdC)mEgp3~nK_z-JT<5R;a_XR#mJ&k>VL;u;nz{wi+1@@#XL+>Bh z7pOd)eF69B?h7odd0$}FsrCiNoO)lN)p(_`SFWmIo*8$?;qM1n3{L$eSz8eia2W87Z_CIzCdHV^c(X`@O^=Xg~~)# z)4sq-Al8wcxSD-|AKfb3)$a>zD^h6Hyf5&0&HDn6O;v`L;QIp8Ph($Te2x18?aLK0 zR@oP*J40E=*1Rt;{c5EJ*Ss%q;`H_fdY*D$p!^B zf#U0xhVY;53s{%>?F(Sf!aOf6 zBoLB7NCF`Vgd`A>Ku7{134|o@7fYZbJTfw&O`EWafu+1bl8WWoh4!zyC5G~&oA&y04;U|AHuRWHbx;VJ2320BxQCl4IwY@r}%30gQk z#eShJ617@x(KfA?Eunq;u<=@z>Ad<}Q_Ebq78&3T_mf#bWMVN6aCSh-wiWSVkqIrq zd$vYXVMPIJ`O#AOtt$Os%}|Il+v{RGuclGzwT91I;yRN&FOV^O`22{W*G}cjem%!J z{I&FV{OtJ7aoBOtalrAhW1nM>W4B|cW4q%;$Fq(n9FI6QI_`D+AW(@Odj4OQz_oF; zA}XU6IIHMOI+d1A?P$)Q(Ls!(HaMs6)-xk{qFfAvEjS;fM<>l#roM_6;Eyx~Lke6SYR9swEoL!KKYmW+;mRam_56H}6_f5?# z&cyJo`_eK?ak{8DMfc|D)Q7opQi^j5vPnni>f}XEUEjQ>Zhly1mdicJ?I|CYIm1(i zLxad+j1P20VQ?1`qkKK3LHv#fpSHEL036Wp#a8?9LzoZy9UpvT(>~`he3$|=o`WEc z{aCOSs%_Fa@Ou*+f1}{AU8&Kji{C5Y_+g23u%oDj69?Pc+7~v4Z-nD7)AKuZwC=}Q zF5`Fs&LtT5>j1~Vke)UVbHj~gzi6ooQCy4VfqdS7)$X|(r+DT4BmH^~3MKFR=pj0%rNOQQnSnZ%o~G0d zk(8C-I)mGj7kD*BoP^P@q4alSYL_r>t>~bbBPIXxwuy4B#JoS^cTptpMhFi)8FxJV z?sCXW8}jN!$o6B%_M>?QJ7oJ&KY|-@$X5Btr5To)KPXI^K{8fQD&oSR* zxNuBHl80EpoX<$J9^e=qZmPg-6`YFzOFsJm<~<{(9SK-M1YoWoNVAQOGX}pn$f4md z?R=RYl<@DA@Ivq`^ZE_pQns-Omw6=smhx`{xDN6pZ#@7v)ZyWPWxiJ^ zIDM45^CDc*yhg!UqNH7|gl_~a+rvMQ59O8&cM)i!J7_$d16cAC4p_GN7m*gv^0~wD z_llPIGs1~KLz?2xWjL5?>DL&4F6D62mudP?_+3b;EsNTkvTaCV)TadNvS{&?Q!Fbr zt`+{oKw6r34gCU#^4GoPsAc<}DZ;|Pu;72_2}vL%f&WDbT(`1ID_dpj>mM9m^|f17 zoBj7%9mKnMSeM;LCpOM`u5ssq56v0*X<6%iMJI#Qv9PvTc)9=+6-OCtk9BN zrtw4#yn!@@CfYzOa!5_Qq*A77nH8J|<`PIvYUr&RPJOx5hg^M(nWxJ#9r?Nxy~Y`u zo?w?Ii$Dt0_bp;f3X~f4=Tg_L(2vcsXCPE+7Y?LCy}PUl;+u4Yc5-SGr*>-A7$xf; z>R(4{TyQ#4GcR&d+{x#uF-#7GrfaF0eMXS9)NO6Xn<;&e zM;;`}HYPM&=YvBOi?TdP+Wt!?KvkizIek$5h7Ah^4SV+u+a_2#Ifi+XL zFRSUjdRtM$rfKDLE8GW@Bzu(XpK7llC2IX<`aE4$QfoK$v5WpCbb?b?zo=iPqW)?A zsxmW2KA|_A6hzOLDTU7qIx?*oDTznj{}Og=?k z0!y|fN~<)08;%$Llo`Ta%8`t+q9%0lSBxEur)=04*iuDb5g0l|ICA;&_5OKtDLDR4~Y z_)`XK=FIt%8uvK{RUIuP$5OiFRLHUF3|uvYTnX8c^8(9ESJ|%O98%`vXT^mMbuhwg*^iY*nm{;PT*z&e2xX1xv+ISLUV0u}(!lU``^& zKa8mZ$4GK-u5<*Kfp~0@Yyli8L@zmAywh#vf{lKN1F!0`4JXC*h|?eI9>(I zN6ZK8?E;Gu=Gy7>u!FUwKn~4b7o4UU&t5JpC#a)xFs{ustZ6Y)vMq}m3Z9Sb!J_S& zJyBSAVcwigvoOYqx@Ie5+u&-9GdV|3N`|&G2y-1E+BQdPO3!~@@*l&^`oycwRdD_J z$|KJU)Ed+D)gOL;cCfZDpxG(3tdv$0{wg~Nw3iWR<3V!FU$F-Aw<*Ft?2n#(NV;C++A~jUhW|5XVM|h%vHp(eG6_fF~0jW9?F5GhEl4+l8qYA_RY4-@{83l z%W`Ur;M7=mY~SQirJ;taDcMh?)f$fWa&02kppswza;TxzaWBfrbZX8j%sQ-UPesM3 zsm-xZQ}U+m6NCsmg~QLhox)(YutIhUaabVqZ98PAFl48&if%1chgOw4vB8vL$s;iG zm#1k|*rzM55*n)f)Jy%*Z`*&#K^@pB9C4P|DSUU{+DQ++5;5@NLnCg@n^0=|w{>%P z$W9^G%)wTnd@qyM1%uDnVs$UxwwH#ELgi+3KeUgr*R z$WEcOvly~d$afv{jk;=23*Jks;?=aeW-AnXTp>G!E^Y^`gyZoAV_#sw1=}XZy*cN@ zXnPM!gYXp=hcEtfd*8T^<3`5rjO`J#DW-As_0hGWuCzaAD~0RrB}t|C(9qGn%=ui5>P#&+7@b{iDXjRd~TG{7}vm~yX zbky&ebkr`Ibj)$PTUI!%mCer<_P|h!iu%^d_Gb%2y!=NoH9xDk8sPD|$d$9Ap0%>= z*&?fPMQ$?HtRlf$+39RyD%qP!o!n%sX?#8|%!XZKt+*=482Ptc{R!KBR*eR@QI=bf zSLW5s7EnY@Dq34BQ_q&V^Jg!m*jJkA)|%LP6?SW7z5k5OKYgdru=+!RB~-*)E1R8h zPR7DQh==?%{1e0ZpO%cgoQ9iS)4-6I44qREWvy&*h6FTldbUeb0jymBt$!wElkA#S zknJ)qjcE)usED*y);UA6(QlJ#jMO`mm6TKp`%qbBFdxeHa_$*r#fRI%FpK1!K~@^! zh2iR`s%y!=Wu~ZzvsN~#+B8meV|t`3*9F6**)C_2&*v)2a^n*7gw%p;ugB-fEuAn3 z%KlyD9&h189zHht5&cD!hUej#%Lj5_0v|AZn~o%6a2vM35iMU1ub+%w9KzJLWY zymYXfFLUy|z;m}QDtx=u>~qCEf(@4N4H4SD0dYc4NCF`VoJA4{ofn`n&(K|XDA=He z01uU;dXfq#UEyn_70EL=_r>M3Oh72 z!Z2Bbcwyt!G<|F)sRp$|nbLUAe=zQ{^1f>++&(zo$tRqSaIOmpPXf$4%!G3R^O7oI zFJN9`CCrCcR{5mD5grFu2^>jtfdcQwy; z@kc1(S1S0_DIoES0n2iIf;2Mx5MWuBI%)_6=F9MM@GN<&1kC%%%(o33aVEiy zgd+~q!g#lVe-rSf{69io#3$Y}Iy?%n)CDjZa4n=I4(U4-9_|GlS@vAS$+p)7__7|M zwa%0q@MT?7|ANGS6R<4HXW)TyroR^QBFyqqFGGF&l83JVQx^c?iNGNp%Cjr-lJslo zch`w?HE@_V5sr7rC2w1m@&ZLm%W}S|gx3Zg$!8NiFY=R&ynv?ha1L-Jyc#%!S#KU4 zCU2Cttn0?WmpnWHWa6_8+zddYX@?9Y&bfeP+SW>VH^6Kg zq)$B#lqbtO1hS$IGPap5aA|SWz?2VZPSRoGQ}=-l zzl5&^Ec>t2zrgUd2$wv=%ZFzMjD3OhidU0v>Gu9b4EtX?@6S^tJohfokcaL7@J2%D z4gha3oRK>K0k;Bpl1|)*lsA}o^N@AKGgQ14W8UTC$*Ej~@-B|Ja~O!>e+Nh2lb5s# zwbOff25sq=CnN*$WH|41^7JKdZWL;8^|yO?r#V}@r@3F9ZXg`#^Jxh;6pntz)1MAU9{7+pby0HeBt7~w;W)pMW*a!S;_m>s9FF*;*9mSG zoaDbV;Kgv9vq-NS+&Vb&OL{QFXL$sU>jlR5g?ko`^ELfRaGYydZa&Fy|Ab>a^P~S8 zIOflXWjzi@`7oaTFaVrCNpBDw*QJc-!#T1k{4zcLtpnma!7t^*_+ENE>x2G5@KZi~ zC|mh{B>j9xB7Nr1co+QSpU-eOAN*W9@uB}(_?aK^>E}BT<%1usu5JZD+413e`*!$A zpYinHt@{C5xUSv^zvPepC*fxsBR>5*bbR_p!@UWB_{@I{+ZFx#|OEd?uU+ey-j5WWikrzvPGhCGgAq=)VJg^3R9<2jM3@KJ;&e zU)Bfxufs3ppAG*z@Jo6*@bA~-@q-c1V)+t)%s&_YBLV&&;is(mF#eYSKP!guEFa^o z@Jo5-!5<&sm+uOQ!i_qMh3^8gJ<#62e(kHIhHRS5r8@JHg8566;9_@zAPUj)D8kN#WWXa1x||K0G*@)pDY z5d5+DHD_;cV_>0PhKlON*W4!>-#Uicq{ zpY_Fu{%7H@r}>0`7yK+6AI850e;v&y{Qrbs_IJh~hhNqg{oFf{{LoK*bW;BGa}U9W zUq19VhF`WP`rE@Vw)x8EgB!lUc*N+tz8g@pB zNBqm+h)+ja%$xY%L8aHQWBj(CINNS|$y z@mwn~A155?wSyyGdpOc!Uc|c)j^SP5nEnzt;*Wr1J81+*I#glD@HTM7zZ{PEoFiDK z4seupcR0#~V?Fa|4##wfaFkC+IMV9{N4ay(ARp($u{;CdNO!9K+X=r+p905pMY?}1 zepz2!E08YN7Nj={j`f-i$M~jjOjoS?Tj7`G?*hmClHizs4>*SRgJb^ba10*^N4yK* zm`{oB?~h-`kAx$CoU53R7mncA&Ry$oToF6R{-C|fM*Df*w5!^+oO|$S^0v#?mUM1a_vF0~J<)mH zE02|La!zQleucHySHEnzqt&3~M<4(9iVZ2RJ+-M}!uLaxk2?mnD0YAI{MElErC-wh z-Q*RQZBOboWn;U^m!5d@-sZc$ulHiwanHOj*UVn`_1c|>>vVg4=jB@?I*%Ka-6^@p zOOBU{Z|u2a!YgSPce*py(yZTg%bRRFdho*h7kO%GlVq*cxhw#ySQnEVqYG z2IfIj80&_lY_aC%{@5gG{ zcUEd^Gz4U=J+?X`T2bh&;gL*lG*tF|KDN5LLUBbcxj}F<5IHFDvBm3%x*l=^sTsNf zTP7b{gVJD1%njUez?HLnyO2fNVvl*WLGGzxPJha5h(Nd4BmS=#e3RT{MwWqk88idpDX1s2#|DTvQnDqKVhZS=HJ zV~{wG*@1%~A6uM280+%-V3EhbsnbT`vbJ#`F%WH6q9SxFmD?K>cC{5lww6njq4VA> zsjaPz%hhnmn!m&=#M%mT{u>r5a4M61LeI7lxnLjQRE>41MNUZr64wO zw!nxyaiP*!5Xo=WM&#Cul*lOKB!bP6XbeV4(_KE%jxfe8#awT+_(=W0fP0GWRZYnj)4*h6hDTeuqZTISR7-G(-1}`?*hk=djsI0 zXDUYm_#xTA-H64IF-p}IxW<_QF@msJF6*I4I9j0j@#Vqd#%PxDI)Z-E!pN*2R#e6i zbB;i&dal4gKexBJ&tlVQ%5xb8k`1dtgC@nr;~GZnr-(Jg6|2W;r!owb2e520hK4#S zigviez?+TbkTFghqhhmJ|sFs(%YKus=#QcWG?#{s(3Zq(dW=V%lYAwk7xvA5}znGEFI#l^w|}@}6{M z=#4hJx2<8K#&U9j7q)>g-1|Dvn4D29m00GRJ+PWWx$*8{R7+idB)=B242ySTITWcM z^)Z=Tg?AgHUqzd(#t_UHynGql#HuHQ43t)Qk1!g0oZo>V11Ayh0LD-TGNw%p1I32d z8h@$$(y$6*0NJT|=0=V!R$vP)CT7jd z&R4{tXDx69F=J&ms6fd&lEkpoGNjsgic-NbLXS#-Fd7yr!l)xqf)?^55RF2{3dBIR ze{`#Ci`Za&cpGLTgI0Zk=iiKtB0TOD5#DAwKVoAa-GrhI%N)sNrAy9{oO)i9_w67_xVZ%#}CMNWfvMqHoLyi z*0LpshZd;aM=|Xp%8Rkra={{nV61BL#l$JTUXgjUX$r>H+*sMmw}O&PTy^j{J({t! zD<^843=PNVxzrqckSlmI&kMBtKkIKUTX3lBsPthNOq{u}DwA32?1J7}tCppo(+N~= zRd6q16&%xYtASzi(dbD}HNRF%$B3l3_y;YKu?H*;kE2Qa=D4ror^e;O8+t+#2uUC$ zfsh135(r5kB!Q3wLJ|l`AS8jmSOOK{k&y{)+JsdM)J(=Fd$P-D*PYsKI{A6*{$}I- z;!e+Se6a`S;>+Cb4sp>=JS~_<3ul(wlhw8YpGgv0w+^cqpmBjOZ?tT!F`>ed{yeBr zf1ZVKt15_59yh*_d5Se2{5%on!mW6lHp6I161foHYodXM`;w z6*oa(px8CtHx*y#Tp5{Vr5??n;g?rNCqFO0blKTB^1>q%E@&B65u>FMpQiY2s8a^Z zqWGl zd&-Ap&hV7sn<{b`<8yg+0wc67xq3>2;QdW}+SYc@IiPif;|@7tKJ0gVc;<+k@C+ZO zz>Mc0i0wTKwnDWHIex*q368(~D2we%jSjzC@T`)gj~zuVoH*Fl*1i^y{zf?dGCe;s zMC<-(`Y(R8vv{$(e;s~f;7Df<96x|CEol(OAp$K=@=82z6w;9{;|P-$%R!i7%$G1X z7`d-4aaNRt!Q8^eSykHOsJ}%ujcAC=(o#0e&D^!x`TL%C62p$AFWh(M0Nd7Rtsw>; z2QnKZKdscl=xr)EcAr~;;akChoa2l9PJE?gmF4W z2gMv2vhfhI@es1{P~|(L`aQAAcf(*G2<3M?`O6VUh5teu4@$pR)F(^7 z=afRYRKT212)_cD^8?{MfH`jv{tz(d5yA%nbDks2N6w?EI-HJQ-iMJie^p@4bIdmx zE*z7QSbJ-{(K%zH5sZmZy21X%Lf2QUwZFzradk~iua;5^81H(<{3gl7Wg z5k|txl<;+cB@g!jmgRjMFy~3)^ZvXHe_O%lJ$V`a8DLqiQHtC$0LSQbrT~`ww*@To zJ&t(E=VySqu3)~ifFo(nhF{M2_vr9c{0@R69m@X&9cK7p@FVj*0hsFt(rlySjKMDs za%ebAJ73|`hQ*JR?K~Zyv@&&g7=ESB0vx}vlq+RqGcuyIKZ(Sx2`4 zHe>>PS&zJXBk_{}%d#v69pcmffDSXSVZh-r-a@#^fD?3>Ix-~9a)e8MoDinuAs@Ju zA6Q6#M{>$)dkyi4v1AfBH_ZiUVnu__}02~QZex%Pfe-pxGUN~o>;V_){MOY4| z{Td0S9CpD^K1jbi9P2I}t|J`V!w|SNN?Gm)EZfW$z~r4YaY$6-llYy%r_4+08XylZ zDZIT2ShnYVfF(b?|1ZP8Q^Mu_dFJ&S!li6uQ5Kn30$?fsHh}8@m-syZH`L+bfF=Da z6r4Uv-SG~;qpWVnk!6Wu}M;T*t{pK!pk&A*7Wc$Uu{ zfxlO@#GesP{29^|e=g&Jg?^3k=TZ(QeVL{Yh2Mpg+OnvvSziq)jQW&dT^22#brQ=; zjcbKJF_4xfUSnUtTCjNY`S-1<%M@YZUs&)z^n@f3lED9>1g=}zrIoF+_4N-9ulm|u z;&QvSBTz1H#@}mQ0Po^qU3MRx*f{68#+?T~G-u?eWv%y>54k0K8IGrAVD=ZbV@<2R z45Rf)+H9w-BU+tdn6MQ}3(aomkf<8sZ~47yywuCUm_Xan8Q?gW6`WQ1$(^4(1kFpdQ;D%PS+>l`)1vAE^K#RGw z4N6i@O zIHJUq56eV5+8G*c#+Z;lm$YL{OKa>4teqT`hq^vk=T+;S*tCL7`|HA5tiPUM64gnAV|dqD?td7Ah^4SV)ZaifM&7ux6_EWi`EN@7|QjG_99N ztG`07Rc*Udg0g?I=9mxd@sc|A!7x4T6bt`UaK{!ZBqQ*Nr0 z?Omo6J}+d$oc!@ATQAbn`k9$mbt%Ny;7>({`P;r0r84spSh6j#-LXHa+(^loX&Ay@ z%8`t+%E3SJSBxEuXMGEM)6{h%dqs{0QR7Yy_PfP+$}~b>kLdfE@RQ3t{A0R2!0Z*l z`UEYMi#)Rs??t+NNUQ|>v+ikMnOqZQ4T>?3aV(<`D|(UEjLS!E#A456$wZoRP^6|F z(h^}a0JHrGTimQ&5iWQL)@~&wmPlGZcY!WPmubkc5aE&vOCLDDaJ0(;Hm$m`zxd!M zRyIl;Ofr&VDP2?NQPml^Y6!U!vSYalVBcD_`@p%|-@bTNI{xuhsj>v3emLSvnB@=5 zNoW}pHr@l{s7r~p##Y6?7F-@2f7m8OO$ob;qNS0Z8YjkJwh=SNKa8mZ$4GK-u5?7& zKs>fcwg9;XVb5nCr^Y+oRvwI6b@B+zmG(P>^CK*KvX`<|RL8ZL57^rUmYg|*(+tG+ zZ!5vmn7!^)@$BX7bLtFrsx)i^W!jja&I!RJDtoYKyJk=1D8U@LM&u|mMbDotnr(yY zBhKXHOIW<;yuf*pIg36ktkR4ACg&ypG2E(?`n7W9ex(9x2QY%&2=~9~9eAZ% z-rZL2Xd5@I73xNq|D{d;>(%leH7`b+7oh!91o-d`7av=hz`TsC-a7WXUaa0D)?j&I zn73egd_~+078h)_TdxYJU85C#<+f{;00m8agccYAHX?COMtr{(xj-SnXpc%&3lM3< zUqzH6z+VpXJGT7&FMiuTBL{VYe^A#?orUZXh;NLgSf}2B?`HfiM>u4UK*%9vk3h&F zWRF1DN|0v(QqV_2_6S7V2-zbLa`*%G2zY$K*cVuHM^2r8%{l+mXnPM!gYXp=hcEtf zd*8T^<3`5rjO`J#DW-As_0hGWuCzaAD~3gi+_e&{(c%owh|q zeQRa=GhT%{L%jS)F*QG{xEkQ`y2zEYqMo&~?b#x$aYdSO`DPUf*2+$23scG7OzPgE zw3^1}cY*Mvpoa)B(U$`VI z!i#{{U64glI4WYSmFJ#OcFYwbFC8rB%bYwf@Z|8Ghcez=^OkmAAnH;})TI&Hz5#JU zPe=kG37ka|5a$JkpZW6w@1Hm3o8(_?pT#$SebI}F7uUVmcK$7)^8#4Eh3>+K?!t%e z!v8;Y7yd6fFRl96mggGfEf{g?HM2^%I5kOXJmttUwLbl9EKfD^ zE)nAh%M+OLWU4rSD^6$6)J{wCW=uX(^Q0{AIq@X7q##1ct$Mmugi6ZN$2$f*70Gk- z;#8)H5ho>CI&o7&-0~6UdnGq2rkP&GvTWo|Q1Z`LhWVcdRq=Udns;Et%>>^0Af@W_ z540>SX^FF){yy`RXLaGM8DYCQ5F;?$A4~WG>8rMl#aU=^wwpKBc;=jS7Z~nA?YRR& zd1rxg;fYp(FHa=<`&etH6=(lAadw$4hLVvdoQYG6f8unwxSzui<|ogMd$l}S7T&TD z7NW&X7W%ySM|!1NkEq&aYHmsX9Q*rtvw*xXlx>O`Mj0Gy9?~2>=XWeasN>b^FRIWg4O}vkP>Ir#W`uV8gVzKs7i0; zNolq+aXO!M%bv|UiX0`Xp1`l#(^%4~60eHK(p1-{*s8>xm}1a!0h4t}39uzG#J`k6 zmVu*(Xq(~`H`|vO-#9voI`nT(yrYt*pZpd#oLumUF;AY*=Xl8S(Iz=1DtPq5!emcq zb|}*L~!1YZR+?w%C!-m`!h^UnSTe&gwY9-iSx9&QN-iJc0 z{2dawr`Nn2=ggVY*lKxwx~6}v^E3C~bG{LlCc<93^_TL2zxG)cS1+sC%{LC2`}K?u zzPE*S*0ffP!J)qaMeWwSb+qop6EA!FJ2#AMQ0biC==Gfo4#f@XJoq02?mB+n8!tjT z%D4&3mk#hmJ@o!nU#HDkAAR${cGkrsUdrjS=i>!CzJF@T!N>c}e>GPME^3;ZKB=cI`O{Z7_n!R2?J*r6el6?754q_B z-dVil@yn)n8M3$Qlb<)9^z`m`f7{*k_eK|bX5Joq#p*Tdj$NA5cuVt=IoXk&+f3~< z>d9R{-}hqH4fe4sr{AAv9Xe#zucHR7`Q_cuz3K5ywyqy{sQ0#AD>v1_!u{~(u|3b(u>Or6#YgT;oAKiMbt5*vm!r%3zjh@^wH+l51jkh;z*5J~j!myTmw?1@XX8G{BeXU)7EIEGL z;k6?=ls6x|q($$?lHT5W^XK)yJ$x+kg*l1skHc0bJ7_m(D4E}Q-i1wuTzKtM=Y+pJ z=E2v7?pS*G@?UyZbe*~BVcWFcO?z!y0{he@jV|`i{-x2U&mUU#(K8ngxPD8&d#1!U zZZd7n^>aR(Gq}z@AB-k{&xM_CTcX>`}|Y1Wfn_s;Iwc2L7_Zn-jP zxA&lDd-5B%++1qwc+>uO=6-#2R$}3*pF2j!Jo3e%h;vWedf%9HU))x|@rSv0wVC~D zS(DOrH=n=coA?g5%sRU3Q_G>fbNiG$yg#ku*qgE{_We|E!^=~Wd+Zo^f18`PEZYAa z#I$B^*}S(!OP*gWT5Zou$ETJ&+c&AxgN>e;H@SJ)(@VN-WUHk%7HVI4vUAFq_jM^> z1Alh+vHzNK;NiXpKYjY>b4x$S+4OAKiq&7`pZMzb-6!K4zFOzDo=4O6M?N2W@z7Ln z@^8&IUU28etGp@iygp>(>P{oyd3}Gg<#!ZBOu2Ve-ubEY2sz|nv6_UDtg{@6P4^YVu>Z7l{oFsENa?cYvz`6)}ajB0^p)H#-ZU`goE zvN-~dAX{p-kLp90q~00)SZr1vX^vE{$WA&W|QTnDdnmPNhOW_W(_mwFrEeY^RtHzRj! z-?rl0)XsIXUjM$=R}YLV{pSm*z52fT`|)0fbKl)zx$9WcOBXMmf9r!=4={6J{5lbIB(a{Yp!hl!O@?) zrrk6B%X*DcF1~u<`nie2mwbEdiN`ztw0L*f$OdW)xU&|7-?*Q4{g0npY*xO>o}$|8 zL8g$HsP>2yrm#g8Wlk?BDl3A0C0nCv>Yj+yUo-~kshWrn5*8He3GFt<&QxMSEU2Zv z{;1hbV1ZolF|3tJ1FqEe^dn-;Y;=8_hViOG^h_mIVWJ3WPpGk`=}e0~+#Ws|@kgMF zi`t#Qhs741V%pY>Nuf4bmp2o}1#MQy1je-Dsx=C1q+`K*fuK>K2rq=iwDvlT%S0T9 z5IHy$ zTob7&zWH#H;A69v<`?*E5m!P@^+ZxBK;V2J7|aJ+6Vrt@6K9f11QiTRy(#K74xim& zGen1+ZE>YgLRyH;P&OLK;T&75YFd>a8OmzEo(({YExg3T)b_@V84cxM%$$!c((TDE zgf3qr_94VdK_EpmQ}qYtRH${6Ww+PY&?(O)=PL4SAkZn#-w|%0Q_dj6@Jd+eHOM!# zCor6nJBe^Za*+edyj~1-MlR2zSISg2%?9Ie*Yr}8Y6et;Q7s%FTLiSwx|B#Sl!wVG zzuPnSh#0wcW{Huj_9tU*h#5Yp>C#qjy*%i^;5ODKt3Hw=S7@>I-(76A!@%*0ZRYIt z&4+D!V&bGn>tioBhO|l7^X;?FMa5nz*ap=0>IS zk6rhpmc!akSW{oKoUy?@jB?|d`%x{6H=^7mENe)r3Q z>2JU7TJ+TDTY9V*v-jdT9WQ_P^~F7H-~QI2`}A{?dRr&G@UdlX(>Hpjj@lc)ZNhdm z&0FV|&DAH)(5gva@8IYElT{N6N_&IGd4Wc2>Q4In@;ApajL$U7q1$3E?RnKJNe@qY z`rhL6;~u^K=9j$Bk9)PAEkIL|#^zP<0zb7wa>d0Cwf&C@qN_)Kwrzt&yOdvU;r zlP>$^-BGnV?cS2}>&d;BU3;=a?=4+gwy3=Nz(0;(^3cptdp~LLcI`JGXnXkCI-S-$ zI(`1$S@-<2LDPwE3_8^GwaSPmmL&iDWBKRJ9=@*W70CmBcy)M}$2!D6^unH-BhKBK zWVyVg_vl|A{4IO<&?PtDa-`PM&DS+-@ZH_@2JE_HU17yP+n-yiuF>{mmA=zjTN}x9 zAT3*zaqIaM3$=s#Dn)B)u_;Efv0ZHSGfG`<7nZ>#F7tvR7jMq$rdf&3iSz<2GN|a1 zkIgRiife1D!3b)NWr#5;)e+Hw_TWjTcZ|@5sgbFRC3%2aa)aPzAX49@h8V9S>Uzix zq-I!d^OZ|OYQXh_Yg8##4>%1c^_&~HQW|a@6E~3NTHx`xi-s4eXKYaU1hK~C z47PL|qgt*S5(~K&ivfeJC|GBKbre`OFygx*(pa;_XYvG;al+9+`W8qAky@p0gN0pq zx#1#|k9_&E+p^$Wg>{`lH%58yGEKC8i8_R2wZ~RFPOq0=4f za&U_ESqG>1HB2?%jY7-UC0pzOMfbZc-biDZe=P*_Ut+}sNotQRMy7y^c!m6!2GV3zh@SPdDq6@^w`3}Zd69HW@sovOeB+bad}a7%@Y z=wxrfG?$k)Y77$FS_!4QEQ&2oAdGc+eXz)5;Cy_(!ewpaKw==;szgQTRx0T?D6DF$ ztQez`vOL~W-oG|W`j2)>N#c^+1$o7^8k34^CkBz#?G-lcxS{QDRC+@Pr3=TZ+64>> zcU_=VTWyJwTmV*Kcf&w?sH0L4TTNhZIcTuXB81kyVy`8ix{F#ap2^2qu_g<`I z5y#jv{X4!{;&t5=xiZO11+JlEK#U-4mXmrY5{?#Veth-r zsWi)Y9ihPGr49ijv)EqB5Oa<|^1pxY$J-Y`=kUhIrqh(KVg}8B^j2t6Tx_RC?8ZwJ zamDJfnyvr?Wm+Gljnz?6G%W)L-q60vIBk&fLBoK7((Y1)l*Wr1`#WNd!9gQ{Sbtt# z@23!m0x!biwUNQvB&GSqD0OOJl=N2`m_xzvlkD;V%9d3Fj6*ontz8f>l|KaE72!a6 z%|NBe#QSTtF!;D-kWwwR1C?DEXp1nH8{@uRb{BJ)Igp}^5iyEx41>a2XaP5d?fOR3 zRZ4E4-ZxZPQY09t{w>hJ-jFJ^t&7&@uVBMKdUAwPOzqv7`z^MFL}MY8G~MOv;LP!q zVYkMZz;>i5#j>&^nMGckt_;1=X7{!=Ow?FTF7RSf!Eg_<*d8%x4j-xZz-kKBW0b;g zU4JCM7BXqHvK)%U0OHT23kz$bEk~QJ#t=;N%N1^7RZSuW%8_wOV~_JwFk;{wo1hG3 zAXDlZhIU$7rVJ|om=s86m{dn%kl8p{ArsFL0wvP5lo&`0vJ~0G2z4V`_q6wuYlH$U zj*Z4vTS3u=3KMUbOKH}11fHUn#6;|ys|+d)s~`rD?UN^z%WF+CR$vP)CT8;)ny-jM z&syLJVs*8$fI{5@CF@8M!&1u-#+QgSDmX^bv10OmV2UD)I#te6nTR_Im7HP)Vj$bw z-74E6Hdr6N0ke^@TCOkf{F|{+gxMaYyW6Ww9J8h>eK1x=`*nh3pTbn&jw4nCoEck} zDNQSK%;*8QPH4_}C#ET4w29H&tgBC^E31#Vk*>Tk#a>sQ_I6~mB^nFZMp$?x!)R9= z>m84cs0BW(fF$bZ872DQ0@Rl)6jX;s(nPjTk?V|z>y$YlCdKE!TE#lo5kDmd{2_-=E>OGANLOZ#{#GQ)i?P>oa-l*n_Hr+}a}}Ik*DErQ9_GnQb@_am zc`jRXV`VSj3Q97)nMFRQ_<(ceM2(Z7*nE9^i8=Nl*EMwVyuhuIKMkJR^F3}DSzft0 zFRW;P;nHD~r#|@pZ;O}xoZ0j9`j#ati<8n%UiscNGm|s^z1g-XH?MqWolZM>T@p_AVRk=XukvYS(h^!K2CBE?ZmDxmDeh_dfJQ=XI|~-T z@A|&pi)qI_^S)d&d)?P-cOI_O?e(3PZ;j|YZcuio3-e$2DdXP*58Sxs>zSElZFAG_Uif(PS$pSw_xsRYcN}~pYQO8-%0Uf& zSdq5iSl_g~;`^R?^w&j4myKWe%ZFoEzOpJmV*O^TQ-}c_(RmX06amEFq zeF5W52#XU-XkXyJvMxqc=I>kJ5K(geSv@BZNbK#jpy|C1=``u z$SL*(ww=ztKxWPR0*NqLW6Y*O_624*{nz!rY;S>fsnM9szB|>vKzM6&(5r4=pjjJb zW~hE&;KM{^_2R!T@L^kJaT;u2pniL$B-QK-d;}b0E~~mPaOl+g0$*I9R9p4?0!M1v z7l=?_{R8&}cB_%6u`h6Yjr#)QPPs2IQhn(UzAw&aLwuL3k?5b`vPt7%8#C|J=N|D)W@4YMlOL=WnbXyQ|}8reVY3M zH=KH3z+L0MKvF-Y>VoeJ#3m{2J;=Vme#A$~!Uo+JcC(DJ1y5K>dtBGFA5l zzMia*scv83^;7Q)Y&^|VYT6eVjW_=~vYl1g7ifo< zeq){qzAw(*fv12iu18F&g#wP;MJaHKyE zYSf=+A>678VwA^?le3;;jR!wZgg+C0aaFmPmg&vT&pd5G^o+12q{5;^L2-_2x^F5@ z?z%EE%St_(Kf^Dtj81-De(BOS3-iJw6E0{ORuQA65l2>eX0%fV%cA(LdO^kvPe~s$ z(3vtkdEhu_3k5+-(8B2{_6u#1sMT_dwrRC&3GLg5jn}G7=hf$$TIRyF$N+D+pUeUx z6N_lJvEA{a<5|ZOjz=6D z9rrqZ5U4~CJ^wFD;M%xa5tUI3oK^HCok~lmb~NYD=pe>X8=TX3YZ_Cv+jQN>_xs?Q zOWG&yI%m@(_R3pt4_oc+b;R~)n3j{o#t2#B^78aQPBi7_7Gw`A$jdKHDlRT7&MwHr zwMPX^%Pe-e2V~~3`=(|VM)`V5gZLc}K5c7f0XU%Hi>>zIhcF-Z zJ3jcxrhU$1_%H=#JO{yWIBbP#n{*ER-UP>Aeig%ZrADVNey@Pzhb7X%j-nP$9BgZA z`^*gA2*+QhkAsWW{W!~I952AR1OtB^;21d4nFGiDai%2=!nNR-CwV0vHwx)UmvMx- z$IWsOW*GA&%uPq`YfGFJWnoaOxN%mM_BiTqQEo08;g{dx`xCGY#_ zAv&j}!L9_EfjX9+rqm6Ql$GE*gWHoAcr`|xgwd~|^mk)wmoRRv=%AP*CI9laiE^#P zyg%Z1Q6%t22oF3NcRc*=a>z>?^6Ev%_G8HQqj?59WcyJ+f*WwiR{6-K9&$Agvnu_b z)27~o@lDWpI4?erL7#I9zNcDJ0dqbf{0d;s4}|vs=Db1pL%^Iz2p3sIN~Lrp8@8&g89w@j-)voemURYqr+42I|z<+DE}99nBj-PkIeT3 zV6GoXvyF~32ERDSq2Vy?e1%UN7C%z9^K^XD%GBXu`0WX1m@kfBSjv^MJf-81hen_y z%k?4rvRy3$zO19$02?v^zO2WdfF*tsU|E*MphJB6AJAduH4HdBb5jU688FvVglTJ2 z(kw@~pWKG#&t>jvORnDQfiw)vY7 zF7v`U6Ag#qQOJztVA`*dP|9H!{N#i5yTh^W(&0M7u{{idTcecae!#NLYynK(NfU=e zH9m>o8GOpT+JQJ}l82WR-rfW(+y6emlAkY>@b8rHLhvl}`VHYywy_A8c_jdr@^1sU z4)P>#Jpeb<;o*Q~zE>zXeU!TMB3#nEM!{L4q+P9qZv-sc!#|J@<(3S05on@2Xgr() zSn?ANSho2WkrvPLxfJ>pE%9fB6Mu#@#h=S?FxS$rG5%c2;iNCq^r7&(kWyO~wKZki zkiw`>3D#xN;wh(CR%%=;{E30IH1Qhx1s?u-?UyI7ePtF?goS@$!T-<`l0ZlT|BDj1 zZe^ENw#wGmKRCSVYqzR4`|q_nhUfE#MZrYr&}m@y^=N{u>$sl!=l;AYt~5Gu6`2U4M~an^*;ax6

8okMt)1#?Oao-3g$5=ubKg2>VaUn*`vvl>U6!NA3e!g(uxN&VMLqWgq&FvHY1I zq$h!itO3d`F^u#!vqsXzI^r2A~c!$4-1mp9Y%ok)Jf*foLE6h`hQK2yMrQ z+Z-Hih z@|h3ddy}#s=^sHeeY6j0p3lbe%ZCGpPN10{KBRe08_NrV37YR%EFXMuS(@t*D?I&4 z7lNjKq!$2YSmA++vdVX^PQd9O07O7@?9OK);B?SRAJVHptN2J?0h;>rA$=og%Hu=& zVbCf+NIwHw*}n|*^PrWya?sl>fBc}u!;REHRQ!uTe-=l71DdwxL;vsNXl4xknLhfv zK`VP!fX<7f)w=?`Fotru_%5Kz1L=OCmHkO`EU(H}C1{?ZrrIjflR>k5GJet}pq0I< zK$n7Md4}5P332`yXl1Wz(8q($#4jJVB~74}JxHGoTIomn63~pF@{4qBz3bR>>{C1_LLxt2fmA^+u|Re6nqz6~_ zqz8gl_9s0Iv?-5n^k@21K2RRAMd*R(1wVp`azP%Zmohp47#H=SjhSu&d6_2WGusBH zmwgj?4goOC3;<;_F7h+Y)Pu5#_Xg0fFM#EdvKTkxWZdkx={5|&a76&}9}XZtfwCAk z`S$`aym~jD2Ap~`FX?_TfMKQrn0CsfUR40<(+fcP0|4Zk44{0LMf!8Bz=lpOiv+za+g@YL-EV-#Q=t@vFLgDWqxt2K)D=SP~L0+ z^R)~>|9t=q7q;j=_+|Qs0~lWcfbow4(0x3B@s|MTJ`q5^0|1Pt)}klim;SQ=)Q^1? z_)+I{!iV$Uij4gjaq%=fdv-qu=S|TD3M@Q1b0DFQ2%gsPz3iJ!dbfXxP+#=%&qA zuU?b0(tD$K_(t#E(V55Z-}{v9JBl7T{L0#4eL8%5?ag-$+wkP=4LAAccfNX!d(4O5 z-*-iyNkzBa@&20Yi=V#xrY`wkOexywo75{D`s9HVekdq8bmWUgYYu*ucRx%rEZ56#>eIrY8uCvW)p%1s}&AMwnlBOlHfcGRS@p+%z}^*tJ1J^G3HPtH7e z=v6tceaD}EQIAJA>pxx*s2{MXceNXIqTh9@2|b=w=bWw z?#l}vT7G~xjpI@5$1$^e#^qv1n{?{O&++`T}rnM}{$PD9V## zPwvkf?&(w-3*vA$ehRg}4&b78k3YGm;)eHbs8S8`j#s0d7ljLz9o9-F&w%qn3%{bQ46$MS-71Ax1-=@ z1MNQop3EdZp1c58KuwB?2CV*wd<7pRvc)N(B2A=Pu&tp@<$K#P_x_jF7ho)F;ILI%5MZDEePls8E^WSxdz0udelH&1Xs}SJub`_dJ=xyjmw5GWh%WR>5%~XOu zhD{D1Pp0+Z%ua1rbd@@{vh+7Eoy;n~X|VY6N<(bxZD`R}o<`3*YP5(Q=pEPy^6}(K zhIzqg9d6{&JidO0mhJR{#CW!6`x{1g^Kg4D;n@MQ$riC>=`-)`l)48RDam!5g|CG? z2Oe!KFHRq?iq)6falAUnsKPnwL;E1U|FzEmLs%r=b^9HB|g(SykAS3Jj}@c>_YoYf6Xxg zeY!4W~plSQ1MulY{I za7ee)S`_a;&@A&YBGRISE~f9$@$tIA*Qv|*V9^4ypo=_1Uq|qKfl>UjjXc#HS5GiX zkI&$6SoR4FVL7tm8nv5*4Iecd2lCa1GyC5HKS4QwV+i}CKEv!#QR$x%X9WALtrLz!qmoJy|6yN#|_ zZS7K{4Ko`rUs{_S^Og+F(hKhqy0GUuF3-?B`{5lxH)RkL3r<5hb#xkmc-13GFyZD?~X_&)`TJlI?dSq5qWkj7xVHj#@ zW9+@y$lz?_{t#RDPSu7n+Dn$CiToOjI*~b&F<$MjLZ;f%H(4Ei2)&V()k*R>i?L3^ zZ4slodlNd2TbCGhFh_YiD#6k^L#bSo#qJr8tT&2Qrgim+)?q+{VMdQ^&F#Eux7-+g zj7*xj0%>XU_?XKsyf^}rda1JuMO%k%FafE)fac=ig&RZXN)}E z=mWBgu`bMdw-Cx>oa;LH3?qZ{#NpkV$>X&K+9FzN_}-aj^)ZgWk?BR->l%2rAuz|h z^2O!}oom>7p-tG9yM08S9E^GC#GX~!HZG?|)?mzDGFwg<67H+#K6?4QBx z1^55u^w}lT(3toa;Z~VI%s(8pwM`q>c)uU4oT^xF0mE{tfo|#%@)Xg`uiG^^qaZi$ zMptIeTP|P3*CX%F+z<1X4b%IbNqJ5ReA>L9$%YvUb$t-Clr9EthE^`X$9+_ru^y%~wsFWZ^-Z)sWU+Vr#ka}#xbGp~y}rAAxB52vuJwH-S;?My{x4hL zwA?lsO<8C96OICD=`;>81vh_YC=laZl7ECBr@#b5So09|;~R2qB#g3Hhtroes#r(N zm&+h9rH1eEA#pN_yf*&m@vokE=)nG)yWVuGx9QT$(=LmS`OI@$nqXJlXdw{=zw%>R za?zryvT0Qnm9c_wxISD~6^KQm20Akk4u%Q?<*dHy@_0$j48$;t7%sLvado=TWg50= zhRdtUC`X>jF)>_UW1TA}j+L7hSQrdV3Pl>G1(rwZ@o@k#%&iMXEdfV}DY=eDf#Cj4 zeA*VX=WNgh12{uYoDb_AAFes#Bs|@x894pf2x5BAg{e?6A;&LR7XbLnkFuDq6mt08 zf@_tOe9R~cck*CbTYN2`{EYzqGCV&rw6*A^)-Qg zA`o#>SMqV9kU+WgBTiXN2XVSFUgDf!lQYilu#aL{~|}z$bxv`%;M`$ z32eU1|L+%`@1OQ%$yr;kD)cyQ0vol#k&M(kXUMi$|MN-mACTr5pv$(H`ujuw{{ zCKiH8)IH|$OJL+$7qkyGfpEE4!=iAkPO(tgN2+bwYM$O$K4PyEaV!XlU-`jw=(QY< zH5+PihFW5gIp}BADP{u*olZl0)L! z6K#p{{W0M?qxn5C;k#k74}|JFp892rW8!tzM?Cqp&he=&?qizqk<0v;Wq-6X>OH$n zs|MqnpnljdK7dA_eM&W8I&k(U#GeGt{(<-lz}asQe+@YM5#rl{v!5f*NA;uAExZK3 z+z+E<{$Swj=NNAhARV2N(t-P9*q>2mN8s5O&V4ZoA7Jnd0j~5M3!IBX7xWYDU=|GkAT!S5sh<ua5Ps6V|vjEF4Tn$EA?zVWSLpR7# z>3R*cDpwbRU**wnfoq$9U*#kB-YEV8;3_TWKo0py|G~l;*EH~O8E-XU0q}ea=NTDF zW&_-nK7JTe=}-w?+K}m@jmb|sV*S$nG=x?9JOP?G)ZO%wGU^ z6&Kc-2p+m~zX;R8upc9!vcqQ3)PwRz0+@FtfWZKkhbe&dMp|wFuFA}Pz^OZBVv(rO zll;S=r;1CRH9#F6HFSFpxGK+Efh&Eu|6jR(Zn&%c^Nj09xGUS{AT27ceBjFd{eZUz zFZo9S?_%LIfGhdGF?hxrdB;8cO6G|M&nhGAWrjP?o>1lCuZV|sD*_CGOjHMPcB3Wr1I#1x{Z( zypN};@3}Y5NPO)!uhaTvZx;}^Yi-$aZ1?i}yAPXq^U7Io)c4)mFy)f63$Z+{6up1^ zJ=k>P?UTHHhc~_Oz8Jd6yFz(Ga|k!(B)T|neoypQ=Q7YI{_f~fXd&+e;%N-^LMNWQ z5ic`27d7M!J(MEvtCpI_#}Y41-Q1JtE^myDCB!dp*x{`^cAWN2wd$mdQfR|lvqG?8 zylmUYmcV%j?FzuyqRksesOW}Py%n5nYi%Pw`wTw56F<$0a5K^43yg`h5 zF{IPa*2fINGcTB4o+d+n%H}CKQnF3OYbfv13Rtl-ww5_;4dl5Q>c+O^Ny3`9^)5GZ zgD2(iJ~);!dGi(T4(CZYGR3^NiD}}EMWx{39qvqv!kk+2_Bq~<#=5}VDMxyE)(7)E zG2h9}JCb<+I!`c>X93ZA@`kQm`>4{hD+$v6Rib?HJ}MQadC4pTvWCn0)jX%NfXTrW zON;URBA!YVpEHSd*$i*rcW>KdDRPMSmD$=Svm`C3>L+uK+^iLp&huaxp7$3^dI_{+ z36++S{Nyv!#Cxg8ZQ6{uypxzImG^VW@~%QkDvENV!rJ`uq$Q@ujH|g2@)RAX6y@f; z``Xsiyf0aunL}%_KE}7(i7u?AY{_UV-jF8$%C>{HWZ9SJPw}i9RV#RFnmlo*9P{0> zJ!KeKj%D2sfTore_($#v;H(wNa*}tZ$v9w-c;lO$Bjjb9M?ZP~RkamX z-n~XY-n&LF)=Z{MhG~FAo=-$s(rr0#mOptm7jsv-vvg4R_};;m#1yHU)Odyu+oh$5 zu^R45N^%KoliB{%gPSqix27kvjM7+H*FN(ou?J3cp;pp%)VvCJPRep0-*?M<4ApsK ziE^C&iBj!)8i6fTUNQagG09WL^n zl16!^pKOC!Mr{{27KWjO2+3cZO3d1r`FWLmNPe^7_ zRfA<4Yu7}!5{!{!M7AP}t@v4@SvEL6Voy%JI%(BkPTj`zslCurB^AoQ+ z#{(wtl}DW~a9#M)%ri@F_(IML@IC_9T6LS^f9rn4U(c$GghhtU;*6n@5!!%LZE?#=!baciFSa-qdall@Ch`xfvhZHrt&eE?H8P z4`nofSL!Y)l_FAhtkTbUN}+i+q12H#4X4g7WG}$lNBc1c67N|xIezllh4Mavqwqof zmO~TY?0>-z>dEfN_FR|!KmDMd`nGKyJdpafEq9yiZRN)PN&^)OFp}*Eckc9#-_ou2 zZX0{F^$u%8x^{DJ+H`KOR{N;A=h)r=?FVyJewH@(=3PsrW=e6~Ya&=B$-tUQJ{3G*9_syAYGp4({fi?A{Eb!~MKx4YQDKp94+~)W7qA}Po zQ68K>p(-|^zN|VJn_srLe0FtxxcbOQw7PD70S=X{nIFFby=8~NyEXE%x?1dhOMAJo zy}PMz;ytUgO$+?8D-8PVQ8$)b`%DIljV8RLxA)Ju)cL=7S+0FMZLh{o?xumeJqs;` zxcQG}>bXa0RTzl|sg=L6qq}Lqo?@$`YQ*L8`!?pgn}+TwN)<%|JbR1Q+9$6P8)nl^ zbT=NKq>cPVW-8OR?oq7)-t8AvRn$kt@q{!{kH)_4rs;c1-Z|A1cOQmC5!<`b>u&1! zpQ$P4gMZGRLVda~4VK@S=Wg0}w`(%5syrB>K3#rBbN;g}!<{SKoQCacOQBGd3U%F` z_t8&WRu-%k$2n4!PP@}K*tuF&7Sx-@#E#U?jhXJI_PeR@So3;9k&e4FlL}%u2YO*W zwiPmy_S&tg)M2-9O)wT+PF1?$h2ey(-SkbXG1uMHBe7_-v}5|eI3%mVi$F9~wUDOp zHD{*pyec>(O-qIcmv)Ku>YhJOYZ@$y15 zL%6W5|7iELRlj!0T1HetA3go%kAxRjp_R}0iZ?1RAT^1L+w0N0@R9Gr|6Ak*Hk>v8 z!r0olU4if|uX=p?A3H!6XSmvptVpt4_uwWeB~K}J9E2R9kO7o({gfsYlHR=EB4x(K zjSy32QA#0Fj+XMN3=5e?@i#PHNKFzOr5q_!D=k=4s*!hzm`1;ld@X~2CL|bXr<$=s zI(s%^#LbuzP3D?6k|^a^XkefuHmSBsw~APaS%$)`aElZnDH&P9Pg0{oQVw58ddgJR zjdTc1)^cSWZ*K91fXJ!BA5C&lmY~8@5}K_iEfC8z(XQ5zDbHC~yea1y3Q-9;ZXe2# z@sUEI_$iNX)}O5`WV?BDOvv5y#)LJV*08-HvAnZDzEGl7z)PFs)(~6GwBl?{vsy`( z_XG*!!#^P%F7D?rhUH1QaavU8O$)~I?jPlLMSo`~fPdoNO5{EhIaao$m11j%Hw#D$ zW7((30rMtaupvUM23tuy=a^$#y0O*pnDzt)<{)=)|n%NbDosY=X}We<$~ygTMVx#_h!i&OSVOcj+gNn4X%}it!No z8(iLH&0h~ToO0yFz##X%W17^u7dC%w+oFBRLwgSU+u%D6pZfaq(2g>3@``1H{qYaJ zcj;Hz^VTI?KctI&$>63A05``Y5m6dZzUq{9#uWUSb>OXHu?EcWJ`A7a)lr#9PB}*T>U}mr3 z@AUr5o)(upx#R6$ceMJg`5FG%wNdlc zwmtXJ^fxzOzo+qm{fFY7o7bu9Vc5##06iNTN*1_*de7eQkYmQVt@>?Q3j5R*&Cd$V{ki!k&+c3O;ZtV}zIxNZyQZbIXgOoe)$=}^ zH!St8_b0Bn{ly*EzW>OUwv8Uic)EPf`-9G#bm-AZ-Cn*TXYQ11Mqkj=eoj&K7hN0t zCAQCs5AK`o+Uni$U6Fsn?%8FBynpYtr`zXWf9kRw`0?QlmsYt~%+5LU`-B1eh7WrB z?GKj?-}+U<8N(*s zhUswj*fF*scIQqd;Muk zzfS3P!<>WLKe6q5XMX>RhjwRopKx7%&8{CC-TUISj6N?9xv%5(o37gZE!ebre$|3E zMNeMn6TPdB>NuV=5NHWq4M`Ag5t@$czez8v9#b0+-n zv`-%zu=kTE4?eT({lX1T$E>{R%aS8s-m>F|l%}tw-rV&J^R3s0ufM6sn73Zr-Fn5XrLoiQULAL2(&2Nyyl`XxJ;7EJDn=J()x1+Q?)t*% z2j6!M+W6A58JoZF&}mQggL#g&gYTa=Fs;F_KlJ)BU$u;CgJsltwt*l?=+JVwLPU^l zN4Jk!i6Ke7Gx)JN>=bE`CNv$VX&E<3X1DZzD1I5BvVRLj<9~@X#C|RqVaoAo|M>h zN6W)Yf4J_Ot(}*&PCvBbXE|k236E#*mF}wew>pk0@qMB90p7P;=y@aV<(IasJdo8h zHUG8m`h9u-nBd=^%j!4amER8c+h6qd%eFfXrN402l7%-uuzCOTdHcKF-LRWu@#sxY zZR^mv$6p6cd3RLjrBBo>TvL11c{NjCn)yxJ@0LAL|LTc>-s9F>+~NI$KlRSOYvvb? znrEJM+2VEcJB?a;;Lzib_55+kj;b+D)E;nqJutt;K<)Y;KessSe3Ly!vo``y!7A!9C?qZsix^no3p;N{#2xY165qq?gTn) zj)Y9pwq{}`waIz{c`z>Mu!AQsrj=Z$QD7q%tWpNlL>VaJoe4xuHr4`p<5*x?tk?*fD$Vx;7)X zJU->Xll|i_f2PsUpI_bg?dECwJ}NqY*Z3b7<=(yH+jp<9-+So3?#p_PSUaGs_+ZYw zJ3nyjUGFTJx_Zp2^@pb}zWceYul6~u|LoQaljlCZv!ZEUZI_`N)2D22w6S?`;h`({ zxYpctf7dg1ZTg?suAWgjox0atdv^J>JGRXErr-O2zw(~*c9eebbW-p5zzuVg{Hwe$HVC89Z z^j!7CxEuPc9RJQ)^SWR7_G?S}Iu88W?VOp-($BSD^4v$Z`K?|*H*4%WDO)DLgsyqx z{Hpo-!WrE)>H8i0{C~1*LPb}@8S(-XM_kjg$F5(xFmCJh#WCf(%a)CtI{kt7eqFNs zr@X#<8rznx@}=keaPhmB&(6sG$419hMa9+IQhRLMzV6zUN%Nc!ID4&ko*Kx$v`f4B zdkJ@CpEEw>!pdq&A~Kj!{p z$fwt?`D%7vRp+9dI~PCJX3jeczWr^)_FMP99>3djpmu1Jf3D14bZ9_!vG1Oz9{J^} zgUcr^{`rFmtG2E#iCuTWn0kvpfB2b-n{Ix0$?8MbJwNMob&s|iyYy}L2HH$s2#z`8 zja$#h*r@H*cPUy=OUg8|P3YxloE!9bJ&-V|@R%12xp{NfwaiLzE~KYplR-t7d>l@x zS6tg$4MS81Y(tDiDODsZ3cWQrqB%EF=)%;{G=$iDh+1+3;YI*b-=zkaq66xB$PJ*@ z*lzQcO9N`c{ex$05PJ(q!%02o2JA$@@`jWKn`**_;=B!T6nD|!;`D+IEFUA)Se!wY zZevs{RRdxrZ^LH5AS)i$SzsLnmJN*bvyo`**;4W-0cA)y8bAjCWFV;*^co~=$IA^j zp?u`am(!7t&}!`K47`cTdzWdVwFOuJ&T5aNL8$U}tqksTzQhKII!5_8973l%_T``y z`?GFt@oSiB-i1ob*Cj{NU`6-4BgM#Ln13w;@hz|e0w=Y{ktlOOLp-)fc#R{-W7q~6 zlqTySV>JRypt0Bs$(@(+Mqt+VRH&vkS}PvC-UnknoIK=LtQ3}!j;UDs-OdVe=%2q&r91q=*(Pgk0)fdt7Y1*x#RVSs(tU8#s8 zJva;kenw*4nM!9tBJa2xiEpZj=1W-k+YdVl=D6E>DAkTjpN-ebV2Oe4qMl0gC*rg~ zUg|d>#`RK~mk{!*zO#$8E8MZS0ul!h3&E$HtrU^W)GBYKN7D*m6tV{}2H%?i1|u^> z;J|?0bdEAhH4w0djsY=)uv@O{qi{GufLZ98+gIt9DLO!@CqNwnMq%0glqsf}016kt zFu*&XD|DM{U0ug1U&RcdrspX*$u3F}7^w%4Y7EFEJynx1FhHK}uk^806+{#6FyNLA zQ08d^6=gmQ5a0Oe4k-s4gr z_>yZty*pSrvTA~P2r}K;1p!m}L*!EtPLx}QC|xGSs@1|M;XNpDH&&Adp~@}{upL;- zjd|ZGhl@GQoHksUBN7$e7zT#V0AWnqjg79W)Z765a)h#_NHajKJ;wwIlLWB zJ82|mlm@V*lr9FG_{myc0LU>%jZY^*|WLo1M_hpZc?Y=`17fmn&WZ-Ua76U<&? zFvfGCLQRsYNyGr@JxS^8$rc48227tR%2Wn4rcDh4q-ky_nvv4fh5>V6s)8nkGX!cB z^m@jXDhtIM`3i3m6=5XjK)FZQfX%Vd*%~My+Eih}UF%W0b*g|<40)JRP%f`^$s_?SEOeONXIY8D4!vl_AczS#p;Re4j>xdpGC0<4n$p0D!bXTTSDCb* zR;Dl`Re(gSWV}}?DMG z8G}hO*)j+gK|!=ZROpE#b_84*ORJQw6{nj%F=#lqT4AF@%;shjw4J4FO_E_LMbjap zy&X9mos11^b8I{o!Dv@9+Z~UCprw`A0ZGttvnuq-1)y=Y3aBeYEsb-U+-GE7sjLBs znU&VvD)zay3l=I3oHDq?Q&46AIh^`NTbqAK;g5^d;iH%tB~YwLfNf-p%Hb2DM) zT&?gt!88TqXk+Z`h7aE|78TbAhy@o(seu$GO1UzvEnB{qda(EI-z{fd6>T1qS}UbAeNi=Ul*X z)N_GPj(sk0|8brR%suwGz$HgL7w9!m*&}KP3t{I1zXHVAh(I zaxU=5@tg~6JHB&)=Z9!f0;`X8E-?Ps=K}4I<6NNAvCjn@$8j$3$y8+}s_R_f znPZ;|+;W`f0`rddTp;kf&IP6)$GO1V<2@G`den1)7RNppXj-Pc~0lW2F0B07ayuh42PnHJ9 zE?hGI%?rAF;c&WMJ=;LH8=yRt)y@*|%e=9A9DcM%!zTlE{Mv2ZW7CsU z9hn-P6u9cfvx zC{gMw^vtZB4#{0lZeCT;uZ43hW##s;1RdxYPIivs`f+Kew~MJs)ba?C)l6TJzeg_X zqJ-^wMaGZH%o#t#ojEFF$V7Kr1whNt*6sIMV%v7oTDfiK?0Sy0u3cj$X-%fnTIrcy z<-xVckYIfa&q5MA`5?gA4LLj4q{PIfwFB)18cu~2#aqvUOQkoQ`;oe#U}r(V!+u^z zr_@^wpSQ$yCMhp)#i4hfYCC`boqXAEJY1kdAnnMn7?}9`rMg<XI)m3=9C|fI+=0=rp$zh3X_tQ7TG72? zjg<7u+a}7j67&9u<)TRFjSyb_Fz$F*?sCXW8>$qB^vi1);=YBrSYb4Vel-Fj>{6&3 zUU}I8UWya*$GE+K0Jx!ue6qnsq#>zYDZ+YQfM@GB3`D$D4%Eyq+n-QTU5?n|hBJ!1 zjM{z_>HuVSVFyzEmAY`Rkm9w7;D!jtqoxo*(^0sLG?=-&%J*Btu!$aOSJ_vhgE2w)`6Ulc#rIhLCN zS09U!q#+4@u4lyA2>wLf-%9a!R$$JAU((qhe%^*;-ZAh?+VbJ&I>>l0{Jb+l|7`eq zwUPeiO8i>*B@Oq$FYEgl{9Gpq|B@2_rUL)268{wtNpZf>m?5M+x$1emq zG#KVxsL<)a=11~&feuexdAffje*1zLmJ9IVPVy*@x#_N(Q9mu+-2 z{02_|FWa#%{1QGLep#0#z(aV3@7Mh-Yb0POb5jO46@Kog=%=ksiL)BNoGtpoeACJOV z59a*}86_XKBTPDo{~S2BT@GA#IQEC(aBGyh+y}qxGn?Qi?Znv{j&u^fC+L)AbpdkX zBn>Ypw7mhp?Ekyqm-KwD#DA;Amw{$k)~|?{yiG#9EGrFu$^VYK)(8Hkx_=b> zvfPUlnEp!J1rRTBUar6_Rr21X#IJ{6_J_Zr9P%v#?o8msaL{OI2EU}IKK!!JKaae4 zR?MG>zZbQ`pV4mo8QuziF5pFmfi3Xod`>3=n5RFP-;00)1v2)2j`9Xq^iTN>ftvOEQfenE>`~nXji4iT&eYz zaTWMSExXj{O1-d*qn=mlc%|OsSrKCLq2;v{Y1H@{h>$KdxDrEC{Ce?HWZ2!QWGz+RB2jf1?8cogkqB#dc)(XFPA!W>rOGtq<&iJ*fsSU z=W2R_JsK}UF;L&PNHH;xYt)}hUAIE3GV7j;SgBn&6btq4vL%F;V_AElot(PJshyfF zM$TGet!<>Hne?c!QZqDl91|CDQ**GuY=%N96nc8|^wLS^u^~(ftXh3%MaWCt)>3o( zEUk}<9zgBU)cejpCNx}^fL5;#n~T^I&>}PwGc-#}F@07lsb!ve&^Z>^I)$i@=&>^q z3T<~nQx`Hdj0?TUR?W#rPvIyO`mgJT6Z|jL`WN+1%RF`GU>^`8{8+dpFH~HtvEUfB zhg1J_Xv>6;Wi@|5?<;ED46UACh5AUGBnRdAR7V9dQR_GJ7wg=XTDz%_U5qcG6P&vG zMf)-r^-uFx<(WD23BBpWAV$8-DMA6@k$J^TNqF)$fSHq8&dsvw${||Uibci+P?sug ztZ>#b=@exNDA||DtzZZ>oG+}H8N*S^nT))mCUo(aqnrJRbz*CZo+_;$2#x7N2Yn&V zyTyFUJfzHQPv&9^6l)lY;paRasU@i!U6d*2t4j1DYJnH^p=NipMF`6|k7=x9C3f^8 zuh6m1H0oC;6h|g&Ch}ARV;*QBE)h2ie$va;LbR@kXPc4s(AB}jM4m{E>73U&FU>%S zWr&yB-Xmk+oXq*B3eYT>>nAnta}ElhEhNQ~yFx!YsSRI&!(&L5;2kM1warF8_JYv0 zTi7cQ8rqMY9*&hY5IvAHuJp71p(SxVaMoqLLepq_fUPDp!gG%hi65NNIopc1V68ao z%Cgina!HH>mLyWFam*b$N0NGTrz5Bgg=3Fo58zB8M#=HQ9d9ou#i6Cv#g9-p+BAqv zkFdkRQOaJy`6^O5Vm;t!7f|FdSI*;uj?|YzDKtl2WSnL?N4c<^pw7yXs5bMkrNvCi zzARcOayfDYi@s})M9vayUG5P%i%iqon!SvDgS#=Vevrd)9Ty zI)|I>iC3LV;Rf-QN6HH{IOW~cZy&pVq;@W#*(tQGl2#M`U3L&?FC)~(gQS?hVh<$N zbFP}KBV$=NF=vv)(#j1}#P}9I&Tr(5u=>FL7I(11l1L@ECR1turf$m>M^9t>%2LH# zS*Fv#K2B>J;+;gyIl@8@=NQJznMjQltyzv#F;-LyBQj3#h4xWsnS!N@mgXwTRl%GM zWeR(X7;{w^n`RDDLK>N0rVvLpVg&6XBxnt4_{~y98v8frLav3gK})1qwvn)8qo%We zv+uJ0VmD06jtvnR8_Q?^CRbG)YP_10<3w8M;MyzqCSngN=?$%&s0Cx|qTYm1OIH1C zfpB{&D#X$H9Qzx2Y}!6SjIdKU@xHP`;N*>w=M2Y_Yo+@7ofR@6}@GCR4dio0#Mt(HbW# z$jSYkns&6EfGk0U=UWJOGEqB)L2aiSwNuExtG-2Ww;i=p7`0Q#Q$xNnl^JhA)^l^k zP9en?jB|n1*C)09pDwSpPH^_IHL1VS=BiBD;~bFuQSz9iZApC+Hzc-5xH_R;{Kd{^ z9KqO+<8HG*7?%*6Wp579=o96@e?JFm>f3AM>K*<2`hUzU^$9Ip*u;)`uO`)A+ac!Y z9Qbo34BFSUwAc1O;UtNxCf)UWCf&7*Cfy6Y-gY%Edu^MOg**_{wx+SYw(H445HJ6c zO>Ispss{T59#ZA5X=JbMe6sLrV!4+@wXR9C*Y-GBh{_1$Q71PEYn4)h3$rno+iNb3 zFh~9=SASx5om8^{Zj=?37FPu{vjt>P%bE`M+N_hM?X2Ww`YMBYUagCrTI00WHu~4d z{KIz&4XZz7SXxbry|(oUr(^;wg!oBM(?2ks|6$JHkWjmvhMQe8Ku~}LHLHoY*ETsp z3>q@Cz*C`_c_1l`Pb6IveFew$Pyq|u3Nr1T){L*-Y& zxF{RxloLuyC2kADEK*<=NokH3hRfo^_mY3gN>P(+uWcFLHI8*-dW@&Y1H+^R9(Q_W zrKddKi%ZOtvq}pB{z`vQaPm+n`}b7)17(xDj~X)049)1>{mjYwh0Mt?>Wn-7lgnXs zF5oTACo5bviT2u4PAED01{TEd(!mP8%t?8H#JeW!PwO&sw75rbudV*QvD&!-VWLlz z15pl~L>!393(%Nn^e#LUY*0f1ED}WT!sAoCa%o@jYTtn)S(dX}j0-glC)EWgw%&~U z{|a^^&ieJ=YNjnJFHlIkex6Fz=2n<(tw=_+q?~~KJ=x_2P{-e;*dy`j@Z& zKg=lY9Ui;Wv7P`Fc4%gV{ed9Tg^gF!^s$+x4$vB9N#i~LVYti6`>sK_U2wdUPk#>L zxi6&u68L#HnEoR8c}bQ20Q|hfN=-jM?bH`)&fT2T%`DS;NC3D&4gQucuB)5 z_<8@8IB$iY_ju{&-E8UKsK9K3U()$1{JdjJ_>bV1w0#9X?^H9MdIxyjmi|~=?&ZZ? z`dh*;RtnUE$xrrwHXeIt)1)e$uB)kuPS+9?gN5=1iU)JR?{F45S@XK=N z!7u6Y!Ov^MEcaG0mNH?Swe?8Jw`}VcfR{8p4q(Ew4_ptAx578zL<>G9}((lZn=vQ4E<0pfWUPSPNC3Xrxeh2{(4 zmt&*=eo1GA5`UQz|4;a3S&QM9eP$K>vaEIR%eH$IemQ<$gr7PE*pBbPFUzI=0txdf z(q!IW5HE2$!9xji3j8u}2POV&_}MpzpL!g~Pu6!hctss#>@%C-(B(9kJMb%UE`^`% z%DlsYNA{C3N?G5)PyP_+CAy#R)P3N>)d?qBA+ zDsJi7jQekr_orkQ<=&+XxsZ{UG8Ix{Udqu&miCVv8@&Ud%I`;(vsWeg%^L@*484j& zjaPI2SKR>!xfMXZiTjZ91`}@{@}7o}5abO4@`d*aC?jS{%0+^(-ocUguN9^Pp#(C%rF;%Y#OTQ641ILrKZJy3z5J)HA7|MH=q^D@_4 z#?f*9##F4W6VwvJd7kS5_oVINI7buyRJb$YxE5g<(scC<#4ppZU9h!<8v;lCeA>Z{ zfMb~H4Cla+20p}1U6foqiI3qtIIeHR*%8jGguB6C4M%w5>j5_hPSW2K{v~i+vxtui z$67ejOMEcHXL}fq`vs;CfO{H_>ovpaa9nFyZ$24te}`i_%VYR!IF`?cbv+D6{xF^4 z7HYL{wgl?Ze1#E0Q45N3IVXPECm@{SMp+qWQ0{7h%~PCX2-jr;2L z2uu1H{tLqFV}xh;WgVX3ad2%)g(>S<$tK{hSScP#b~J}{PMJ6F%obcP2bO!^p}3O7p653kl& z`OeiCex~Qa`4Q&colid8l?Y3E7+#97ERW$^5hne77=8d@;^V{cW`t#XF#HIV8-6VLI!_bUVV5pT!8LgoNe0 z0+Mi}&SvAgfb0(pcSKn7pJDFhW&bKcm^#$tT*dG(gxNn?KEpW(OMaCioQp8~GswoQ z4*g>YOMaChd?~_l_~pa7q!wYx4~DNoSklMv4G6P*;$!$ugk^nw2tSB$5`OtG{4~O> z4lKyvuB|U`Si*O1v<6-zP!lZ}gGfd{QeOdnsxCRJwe&I76t_{L`f8fLL zIS5Po7#K+r?hH7__l9Hs^WX?S8jk&>IUMm&g&pHN!V&&LIKp#{V4b?bk=N(Iktdw% zSwC|r|Z8x@XP#}aLiY(hbQ2d?Zv$U@p5lL zd}HC*t_5&RZw1GEK0VwXzpQ^RIF^?V$MXBYF@7K%%g=#h{17<8oesxxD)jIm{4#wE z9O>g)#c~30j6V~Od>RTzeBGSL1 zarhxv`O7Ayq zeV3`{A9>^MHru~z^nCVV|AH^p%w7A{ZQJ&zp8eXk3pdC1oH(?gM@F9)Trc>p?fdfN zt=VVwxIM|%df=5ST5dVG_l%O~e$4&HkWa5&^VRIUs?J3@cP@Uc&75}@eEZvo?YHiI zJ$|?6K<&^b|6G~9=+J=dV&6SaJ@U&{2bWJ;{PPDBR&8Bf61(n#G4&RI{_ryuH{Ja1 zlGTT@sm$I(z%D6Xg_HxOCj}lOZgrfm;06+$kdO@#2!gh?odLlF89Q8VNcGhz`IH*@+^c#2+ zm2XAPh6Lff&;l#~XSK)CAXIs~Rz^7zzr>oysf3TiA#}Ps8gv4s5bW*d7Qb4#Wgul2 zD$NOxk0VJ}@~-KAccd73@}d9T$k7684LGSijzpOQ5YA>Ar9k=^mJx%}WF2IzMt})4 z7HbTr96pXX{raw1+f%Vr8m$#?eDgA@S>{$57TRCQh|k(7R3r#(^t4f9pg4@xfs-H~ zN3sBz;0f>&w*iydQK7PdA&?jfw!M?WbUT&X8yL2C7E`uXO1z=--mIykt5TC>i!OWv z$qv96%yLQ<`9|`G-IO7mBqanWEntAWd%DtW4J3$EsBeIM+FhxLL+IHz5|5mrbQUD? zQoND4`Aj7--q6bLaCI^!qx6}cO3{xn$1THJZ}j*$U3tHOZFo8a*tTsfJ|$qmZ`&WAMERU@$TjkpO<9HelCd zGi1zC4Fs$qGazOVcFW~`6b>f{FbiFNY;KHhnW6*eRtJp224Y8LOfk&_kX0_hLfa|l zn&&JI9jE-zZs2raH)!A_yJ)(=Nc{w<2D_5vsR424Af@-X z6bK7vU%?iZJ1ahpCYXmH)2&?)7z>&1(M2>Df!VjvUj@Tw-Q42Wm`fkQe$(hODOM>J zgN|+3R2t3FAXIq80DBH=xiRlMrA&)C%`_dZ%n^x-tc!tRCm@XB(%9&_O3e+>4@M|k ziZlb%+5-*f53|fu8b^v%V8#I2H(IHtQx0ZFnsxdJW8n|kO1119NM@CH<|tEdf;qe$ zO*?5MXOsqD8wk^VWj7j=Gn%Cq+kA5b)=?=h-aU+FX=nwq^pNG)yc^r0I7}c`B3I+x z#u!%#X0I_AGafHr1~o|pz`X7qSE{Tr?eQLAboS)2Fz7bK>zSc-Ljz4GyaO0h8PEhh zBLNVsDl}&>2VQHeXh!;d#a5V4rYdMsI76UDL9fR`&okK47`#a&&^W&~Je>pO9^n>j zj*ZUNKmpOF3KMP~URjK8ohsl4`~3l3%*X@`;N8cVRGNkXhM=8ZY#!t|k_5DnN;138 z+!BQydeH(#ATxGmLraySNuTck!B!&|T#8Mqn?IBPdHs_>X!8Sc)oh2zob${0+N$(BJdvr-`{Sp_jy#z|F5 z*NW3kpBOZBtyb9R5VN`2Rt;wkQZKQ1n(oQ^Map4_~upkE8;TFT1pVF~g}my?~NxPDyP>Fr`_6160%ndok-0B9N7y8S*&Y}-zv?E$zMDxJS_L+xybf-@21mdu)wdYw_1M$n}%!Ti1TqUe~9tk6gQ4J6$_m z+gvZXo_9U%dffG}YrX4k*FOa)!K2UrWe!}CTrajZevvy&709u)acDR^hkzU3kSqK?^u@}_idTZ3Jz0oB;7ASMCMjbdAx)3 z3ORhG@puu+&I{rc(U++w!gRVu%ScaQrmwKHfOv#Xjv>CPa$T>SrdDobUcSdW)a$Pv znK#Q{g^vR$VSJ@0pd%Qq9mzFPIt1@;;?uTvdd>;0I~-5Q>F2|7$A>aUJcMWbNX5@| zPJ%ezv*9RIJCNfStn1+T%a5`+uGH}Gy9H&HBz~MIYVm}@v9|WLfcV$L@t67eks(13 z&(MGIqsihW>EX5bO@t$!d2svy!o0*mKZFRhGD$1pcu+`3yiB8?xL6PR8OL(z=K&+n zwI$5Tsu-ACSU)GMKaTxVRMUu#xI8=a-uZdkZ*u>(^Q}%XhjJG0x_z)?bAr|pL&bs2 z4#`g|_>@qo3%ZQ)RB9wwN{{Sj?dO;paL> zKOeb{X6gPM{PI4G#QBTj=Q_u7GvMlDF_JX!ehk+$;%o$eqVDIt80qhBjMBGmvvbJJcMWXe%;TqMgoRn zyk&4x;ZM{3)R7@^RwG{0;|4P&4JCjj4_PnrnD7ky^G#JM7z6k5Vyk8-siCisS74SZd2dqUse3~9hrgj5 z@+|}IOyI)s)O=Ob#|=)l%3dNo>^Q_V|+sZfWc_&IP8=8Pj9V~JS`Wizpx!^TJ>cdtxwWsJFUJ_O9I$nWgnn(F16wtQZutj|rRXv>i@OIHJbnkFZf&i26t?^`_5CCG8l~ zJ{rdYTc;59p{@_Md3d`MnpTi$e_dFMwdy%JdW!5lN5dfaU#j&l_6(V)Zp`chrgi9} z;g-Bmak0jNW3)(2yHueq6F!#J{HDEolP5FKLe%UKQe>_$%fPrq9w^Q}k3ZRs;mc z2Q}^#;=EhTr_3Yt^@y>bhcKxu#y_DIhwZ}_3%5#73+1BBe541EuLK;c0R0?OwD?A< z>1PXyIge?qV*7Z! z9PM{Trbk%z?T+h$2XQP}j9FooUW_-n zE?MVrvpw;ub1B>)zVb-@0vDaN;QnRq)+@xh0PPXjR&i%huF*uw^DvXr7A9$AnB#!+ zzT8C%I*w)^@xMu*VNmCL892g~mVMlZc~-oWaHq%j6*2SswRl2>#){S~M=mi|RLi3> zj(vl(4@=;9X1rM0#A<5JhBAe{MU1&BZC*3uxu%JpB2$Q?8W;ubA|z|XkXfooW8V_g z?GfnL%9Z<-ikF{5Bi;zN-t-Q=(k<_9 zD|fVw8`cVTBhGqh(|WyH-lOK7WAg&EHAhGYMB`&CGnki=)mz7w>&5ClV$Clv4D%K& z#aG15U~$1#yY;GgwQIB@tlV}Di%`JCM`!^d{6-?=WW@JtQ3@0SjPt8lwFr?%{8d;f zBCLFn-?8QIfAHJ3)=x?+EBuuZDw|naUR9n|>f?{0MMJYRpnvnez!RhlnI}M*GL^ch zJpyhkweO1j&C>l7@mq^;U;J(#gp1lE5PaANUhsP(d2$$z`)~R;!tq-k{qx}XnU8)S z96tlnAGJpy_z<;6AZ#T_S%6IRji@~W(Kn*@2m~K~hdly{FBs5|~= zV{1}>rOj2Dvd1|f`J?19N!yb8ByLD-k#KcFz4(ir&p3jyAIIHhe=sf~Hp|`|pwTDF zf&YFE)YP}v#znBrt$tt6=!Xjvg`UZSN`r%{3d%ge$pzC2$Cg$3$}WUm)5^)|P%2qI zIaC7u*b&`NXyFBw6}bHt^IlD=y|zQRoz<}_2mV|MgZ3wt#d7_gNq6m{2`$sM`vXRu z|Bc3SP3yF6YZ}{YyPohS)CuC{KeDOKNk!FQf51bk+%=8twVh8EUQI05jLWyKNwe4X zI9Z6w2;@=s7P-|br34pdV=lMXTpD4H{8LUUW8OchW&_+PD=ICn!npzN?2<(-YdY9# zvrd+_vy!LTKJ;o`?9>{ky|&T6My7Ti{73E-8rpryu(X;Kdu{6zPRRu50Q8fdrhi~M z|HGW&=^ihq;kw!kDkUUA%}%5}`XMt5JQbQcN0QR`MDhkVS4#^#hPq(wMrxCqID2jC z3F0l#PADmrxGh}n2?l17l;(J0xGeqzebcH*w%4`{ z?;6LtG5v4cl9l5{AmA;{Co5bviT2u4PAEC%4w07*R`6v`$_qU7$<_CjjGcCmCNB_w zzAgUzSnb?^FwrNQ(Yx^fr|!c4TjT{coHc(^Y;D}GK=_tdJwE-99UzM{T?38Oo$alE<3TMFSNQ)ZfXV8qP? z-uWP=y2}r>EG)|wGMLtoDbHC~yeVH93Q-AZZy#zV<0FMa@lzh(tUp^>$aeF_8fDJe zc0xwljHg7YHzbyK7RVP$vbKDwYtC?1ut!Y*($x_0ZFh2Yf(&6HM4r5rJlp7Cd zWwI{3Wx;+U`#VDc{9_vhwGk2CXO7;JtQ1>Ayjeh67|T9I4w!c%M68few#o}LMU^_{ z=%buA?FOlw%k@T+lF>30vb4)BJQkX09Q((EYD&MG+VOTRo9Sov<_Wp7-U*@x!>vGvY_t=z-~_0Ds=X5W4i zy$?l6`7=0hSHA_<&YL%{h28erOilk<&!_IY>og-STf`Orb-)?l6nuB^xBtnwz4*Y{ zhbQkYy(`85atNS1wmiM*+Yk24fAW$wSM@lU|M~3=zuM-A>8VM}jfYg>;PNhO{(7+C zlp`+&2D$GY)1=nDu=#7-7VS$O+H=_72H$b`)YqSf3YCeIS1cRskALvJOTWsVw=UuO zAzkcCM!!(lf9FSwUjFWhrF$P6xbV%is@

N4!^4ee;Ml3tRLnd$D!=wOf|FdbZR3 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

B(yzz!Y<1;zw?#D! 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⪥u(H6`_){ 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 Cvk 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

~E#*9%nuD*v6e`E-MsRjr2uhY8!C;U?V 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 l+Z2q^LGA42TR~MJt~ykw`%PnMQ>UAhjEcrN(Q - - - -ASCOM.Astrometry - - - - -

- A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Exception thrown when an attempt is made to read from the transform component before it has had co-ordinates - set once by SetJ2000 or SetJNow. - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an incompatible component is encountered that prevents an Astrometric compoent - from functioning correctly. - correctly. - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an attempt is made to read a value that has not yet been set. - - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an attempt is made to read a value that has not yet been calculated. - - This probably occurs because another variable has not been set or a required method has not been called. - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when a NOVAS function returns a non-zero, error completion code. - - This probably occurs because another variable has not been set or a required method has not been called. - - - - Create a new exception with message, function name and error code - - Message to be reported by the exception - Name of the NOVAS function giving rise to the exception - Error code returned by the NOVAS function - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an iterative Transform function fails to converge. - - - - - - Create a new exception with the message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Class providing a suite of tested astronomy support functions to save develpment effort and provide consistant behaviour. - - - A number of these routines are provided to support migration from the Astro32.dll. Unlike Astro32, these routines will work in - both 32bit and 64bit applications. - - - - - Releases all resources owned by the AstroUtils component and readies it for disposal - - - - - - Flexible routine to range a number into a given range between a lower and an higher bound. - - Value to be ranged - Lowest value of the range - Boolean flag indicating whether the ranged value can have the lower bound value - Highest value of the range - Boolean flag indicating whether the ranged value can have the upper bound value - The ranged nunmber as a double - Thrown if the lower bound is greater than the upper bound. - Thrown if LowerEqual and UpperEqual are both false and the ranged value equals - one of these values. This is impossible to handle as the algorithm will always violate one of the rules! - - UpperEqual and LowerEqual switches control whether the ranged value can be equal to either the upper and lower bounds. So, - to range an hour angle into the range 0 to 23.999999.. hours, use this call: - RangedValue = Range(InputValue, 0.0, True, 24.0, False) - The input value will be returned in the range where 0.0 is an allowable value and 24.0 is not i.e. in the range 0..23.999999.. - It is not permissible for both LowerEqual and UpperEqual to be false because it will not be possible to return a value that is exactly equal - to either lower or upper bounds. An exception is thrown if this scenario is requested. - - - - - Conditions an hour angle to be in the range -12.0 to +12.0 by adding or subtracting 24.0 hours - - Hour angle to condition - Hour angle in the range -12.0 to +12.0 - - - - - Conditions a Right Ascension value to be in the range 0 to 23.999999.. hours - - Right ascension to be conditioned - Right ascension in the range 0 to 23.999999... - - - - - Returns the current DeltaT value in seconds - - DeltaT in seconds - DeltaT is the difference between terrestrial time and the UT1 variant of universal time. ie.e TT = UT1 + DeltaT - - - - Current Julian date based on the UTC time scale - - Julian day - - - - - - Current Julian date based on the terrestrial time (TT) time scale - - Current value for Delta-UT1, the difference between UTC and UT1; always in the range -0.9 to +0.9 seconds. - Use 0.0 to calculate TT through TAI. Delta-UT1 varies irregularly throughout the year. - Double - Julian date on the UT1 timescale. - When Delta-UT1 is provided, Terrestrial time is calculated as TT = UTC + DeltaUT1 + DeltaT. Otherwise, when Delta-UT1 is 0.0, - TT is calculated as TT = UTC + ΔAT + 32.184s, where ΔAT is the current number of leap seconds applied to UTC (34 at April 2012, with - the 35th being added at the end of June 2012). The resulting TT value is then converted to a Julian date and returned. - Forecast values of Delta-UT1 are published by IERS Bulletin A at http://maia.usno.navy.mil/ser7/ser7.dat - - - - - Current Julian date based on the UT1 time scale - - Current value for Delta-UT1, the difference between UTC and UT1; always in the range -0.9 to +0.9 seconds. - Use 0.0 if you do not know this value; it varies irregularly throughout the year. - Double - Julian date on the UT1 timescale. - UT1 time is calculated as UT1 = UTC + DeltaUT1 when DeltaUT1 is non zero. otherwise it is calaulcated through TAI and DeltaT. - This value is then converted to a Julian date and returned. - When Delta-UT1 is provided, UT1 is calculated as UT1 = UTC + DeltaUT1. Otherwise, when Delta-UT1 is 0.0, - DeltaUT1 is calculated as DeltaUT1 = TT - DeltaT = UTC + ΔAT + 32.184s - DeltaT, where ΔAT is the current number of leap seconds applied - to UTC (34 at April 2012, with the 35th being added at the end of June 2012). - Forecast values of DUT1 are published by IERS Bulletin A at http://maia.usno.navy.mil/ser7/ser7.dat - - - - - Computes atmospheric refraction in zenith distance. - - Structure containing observer's location. - 1 ... Use 'standard' atmospheric conditions; 2 ... Use atmospheric - parameters input in the 'Location' structure. - Observed zenith distance, in degrees. - Unrefracted zenith distance in degrees. - This version computes approximate refraction for optical wavelengths. This function - can be used for planning observations or telescope pointing, but should not be used for the - reduction of precise observations. - Note: Unlike the NOVAS Refract method, Unrefract returns the unrefracted zenith distance itself rather than - the difference between the refracted and unrefracted zenith distances. - - - - Converts a calendar day, month, year to a modified Julian date - - Integer day of ther month - Integer month of the year - Integer year - Double modified julian date - - - - - Translates a modified Julian date to a VB ole automation date, presented as a double - - Modified Julian date - Date as a VB ole automation date - - - - - Translates a modified Julian date to a date - - Modified Julian date - Date representing the modified Julian date - - - - - Returns a modified Julian date as a string formatted acording to the supplied presentation format - - Mofified julian date - Format representation - Date string - Thrown if the provided PresentationFormat is not valid. - This expects the standard Microsoft date and time formatting characters as described - in http://msdn.microsoft.com/en-us/library/362btx8f(v=VS.90).aspx - - - - - Proivides an estimates of DeltaUT1, the difference between UTC and UT1. DeltaUT1 = UT1 - UTC - - Julian date when DeltaUT is required - Double DeltaUT in seconds - DeltaUT varies only slowly, so the Julian date can be based on UTC, UT1 or Terrestrial Time. - - - - Returns a Julian date as a string formatted according to the supplied presentation format - - Julian date - Format representation - Date as a string - This expects the standard Microsoft date and time formatting characters as described - in http://msdn.microsoft.com/en-us/library/362btx8f(v=VS.90).aspx - - - - - Sets or returns the number of leap seconds used in ASCOM Astrometry functions - - Integer number of seconds - Current number of leap seconds - The property value is stored in the ASCOM Profile under the name \Astrometry\Leap Seconds. Any change made to this property - will be persisted to the ASCOM Profile store and will be immediately availble to this and all future instances of AstroUtils. - The current value and any announced but not yet actioned change are listed - here: ftp://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat - - - - Function that returns a list of rise and set events of a particular type that occur on a particular day at a given latitude, longitude and time zone - - Type of event e.g. Sunrise or Astronomical twilight - Integer Day number - Integer Month number - Integer Year number - Site latitude - Site longitude (West of Greenwich is negative) - Site time zone offset (West of Greenwich is negative) - An arraylist of event information (see Remarks for arraylist structure). - - If the combination of day, month and year is invalid e.g. 31st September. - - The definitions of sunrise, sunset and the various twilights that are used in this method are taken from the - US Naval Observatory Definitions. - - The dynamics of the sun, Earth and Moon can result at some latitudes in days where there may be no, 1 or 2 rise or set events during - a 24 hour period; in consequence, results are returned in the flexible form of arraylist. - The returned zero based arraylist has the following values: - - Arraylist(0) - Boolean - True if the body is above the event limit at midnight (the beginning of the 24 hour day), false if it is below the event limit - Arraylist(1) - Integer - Number of rise events in this 24 hour period - Arraylist(2) - Integer - Number of set events in this 24 hour period - Arraylist(3) onwards - Double - Values of rise events in hours - Arraylist(3 + NumberOfRiseEvents) onwards - Double - Values of set events in hours - - If the number of rise events is zero the first double value will be the first set event. If the numbers of both rise and set events - are zero, there will be no double values and the arraylist will just contain elements 0, 1 and 2, the above/below horizon flag and the integer count values. - The algorithm employed in this method is taken from Astronomy on the Personal Computer (Montenbruck and Pfleger) pp 46..56, - Springer Fourth Edition 2000, Fourth Printing 2009. The day is divided into twelve two hour intervals and a quadratic equation is fitted - to the altitudes at the beginning, middle and end of each interval. The resulting equation coefficients are then processed to determine - the number of roots within the interval (each of which corresponds to a rise or set event) and their sense (rise or set). - These results are are then aggregated over the day and the resultant list of values returned as the function result. - - High precision ephemeredes for the Sun, Moon and Earth and other planets from the JPL DE421 series are employed as delivered by the - ASCOM NOVAS 3.1 component rather than using the lower precision ephemeredes employed by Montenbruck and Pfleger. - - Accuracy Whole year almanacs for Sunrise/Sunset, Moonrise/Moonset and the various twilights every 5 degrees from the - North pole to the South Pole at a variety of longitudes, timezones and dates have been compared to data from - the US Naval Observatory Astronomical Data web site. The RMS error has been found to be - better than 0.5 minute over the latitude range 80 degrees North to 80 degrees South and better than 5 minutes from 80 degrees to the relevant pole. - Most returned values are within 1 minute of the USNO values although some very infrequent grazing event times at lattiudes from 67 to 90 degrees North and South can be up to - 10 minutes different. - - An Almanac program that creates a year's worth of information for a given event, lattitude, longitude and timezone is included in the - developer code examples elsewhere in this help file. This creates an output file with an almost identical format to that used by the USNO web site - and allows comprehensive checking of acccuracy for a given set of parameters. - - - - - Returns the altitude of the body given the input parameters - - Type of event to be calaculated - UTC Julian date - Hour of Julian day - Site Latitude - Site Longitude - The altitude of the body (degrees) - - - - - Returns the fraction of the Moon's surface that is illuminated - - Julian day (UTC) for which the Moon illumination is required - Percentage illumination of the Moon - The algorithm used is that given in Astronomical Algorithms (Second Edition, Corrected to August 2009) - Chapter 48 p345 by Jean Meeus (Willmann-Bell 1991). The Sun and Moon positions are calculated by high precision NOVAS 3.1 library using JPL DE 421 ephemeredes. - - - - - Returns the Moon phase as an angle - - Julian day (UTC) for which the Moon phase is required - Moon phase as an angle between -180.0 amd +180.0 (see Remarks for further description) - To allow maximum freedom in displaying the Moon phase, this function returns the excess of the apparent geocentric longitude - of the Moon over the apparent geocentric longitude of the Sun, expressed as an angle in the range -180.0 to +180.0 degrees. - This definition is taken from Astronomical Algorithms (Second Edition, Corrected to August 2009) Chapter 49 p349 - by Jean Meeus (Willmann-Bell 1991). - The frequently used eight phase description for phases of the Moon can be easily constructed from the results of this function - using logic similar to the following: - -Select Case MoonPhase - Case -180.0 To -135.0 - Phase = "Full Moon" - Case -135.0 To -90.0 - Phase = "Waning Gibbous" - Case -90.0 To -45.0 - Phase = "Last Quarter" - Case -45.0 To 0.0 - Phase = "Waning Crescent" - Case 0.0 To 45.0 - Phase = "New Moon" - Case 45.0 To 90.0 - Phase = "Waxing Crescent" - Case 90.0 To 135.0 - Phase = "First Quarter" - Case 135.0 To 180.0 - Phase = "Waxing Gibbous" -End Select - - Other representations can be easily constructed by changing the angle ranges and text descriptors as desired. The result range -180 to +180 - was chosen so that negative values represent the Moon waning and positive values represent the Moon waxing. - - - - - Refresh to parameter values and invalidate caches in the parameters object so that any new values wil be used - - - - - Flexible routine to range a number between a lower and an higher bound. Switches control whether the ranged value can be equal to either the - lower or upper bounds. - - Value to be ranged - Lowest value of the range - Boolean flag indicating whether the ranged value can have the lower bound value - Highest value of the range - Boolean flag indicating whether the ranged value can have the upper bound value - The ranged nunmber as a double - Thrown if the lower bound is greater than the upper bound. - Thrown if LowerEqual and UpperEqual are both false and the ranged value equals - one of these values. This is impossible to handle as the algorithm will always violate one of the rules! - - - - - Converts a calendar day, month, year to a modified Julian date - - Integer day of ther month - Integer month of the year - Integer year - Double modified julian date - - - - - Translates a modified Julian date to a VB ole automation date, presented as a double - - Modified Julian date - Date as a VB ole automation date - - - - - Translates a modified Julian date to a date - - Modified Julian date - Date representing the modified Julian date - - - - - Returns a modified Julian date as a string formatted according to the supplied presentation format - - Mofified julian date - Format representation - Date string - Thrown if the provided PresentationFormat is not valid. - This expects the standard Microsoft date and time formatting characters as described - in http://msdn.microsoft.com/en-us/library/362btx8f(v=VS.90).aspx - - - - - Proivides an estimates of DeltaUT1, the difference between UTC and UT1. DeltaUT1 = UT1 - UTC - - Julian date when DeltaUT is required - Double DeltaUT in seconds - DeltaUT varies only slowly, so the Julian date can be based on UTC, UT1 or Terrestrial Time. - - - - Returns a Julian date as a string formatted according to the supplied presentation format - - Julian date - Format representation - Date as a string - This expects the standard Microsoft date and time formatting characters as described - in http://msdn.microsoft.com/en-us/library/362btx8f(v=VS.90).aspx - - - - - Sets or returns the number of leap seconds used in ASCOM Astrometry functions - - Integer number of seconds - Current number of leap seconds - The property value is stored in the ASCOM Profile under the name \Astrometry\Leap Seconds. Any change made to this property - will be persisted to the ASCOM Profile store and will be immediately availble to this and all future instances of AstroUtils. - The current value and any announced but not yet actioned change are listed - here: ftp://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat - - - - Function that returns a list of rise and set events of a particular type that occur on a particular day at a given latitude, longitude and time zone - - Type of event e.g. Sunrise or Astronomical twilight - Integer Day number - Integer Month number - Integer Year number - Site latitude - Site longitude (West of Greenwich is negative) - Site time zone offset (West of Greenwich is negative) - An arraylist of event information (see Remarks for arraylist structure). - - If the combination of day, month and year is invalid e.g. 31st September. - - The definitions of sunrise, sunset and the various twilights that are used in this method are taken from the - US Naval Observatory Definitions. - - The dynamics of the sun, Earth and Moon can result at some latitudes in days where there may be no, 1 or 2 rise or set events during - a 24 hour period; in consequence, results are returned in the flexible form of arraylist. - The returned zero based arraylist has the following values: - - Arraylist(0) - Boolean - True if the body is above the event limit at midnight (the beginning of the 24 hour day), false if it is below the event limit - Arraylist(1) - Integer - Number of rise events in this 24 hour period - Arraylist(2) - Integer - Number of set events in this 24 hour period - Arraylist(3) onwards - Double - Values of rise events in hours - Arraylist(3 + NumberOfRiseEvents) onwards - Double - Values of set events in hours - - If the number of rise events is zero the first double value will be the first set event. If the numbers of both rise and set events - are zero, there will be no double values and the arraylist will just contain elements 0, 1 and 2, the above/below horizon flag and the integer count values. - The algorithm employed in this method is taken from Astronomy on the Personal Computer (Montenbruck and Pfleger) pp 46..56, - Springer Fourth Edition 2000, Fourth Printing 2009. The day is divided into twelve two hour intervals and a quadratic equation is fitted - to the altitudes at the beginning, middle and end of each interval. The resulting equation coefficients are then processed to determine - the number of roots within the interval (each of which corresponds to a rise or set event) and their sense (rise or set). - These results are are then aggregated over the day and the resultant list of values returned as the function result. - - High precision ephemeredes for the Sun, Moon and Earth and other planets from the JPL DE421 series are employed as delivered by the - ASCOM NOVAS 3.1 component rather than using the lower precision ephemeredes employed by Montenbruck and Pfleger. - - Accuracy Whole year almanacs for Sunrise/Sunset, Moonrise/Moonset and the various twilights every 5 degrees from the - North pole to the South Pole at a variety of longitudes, timezones and dates have been compared to data from - the US Naval Observatory Astronomical Data web site. The RMS error has been found to be - better than 0.5 minute over the latitude range 80 degrees North to 80 degrees South and better than 5 minutes from 80 degrees to the relevant pole. - Most returned values are within 1 minute of the USNO values although some very infrequent grazing event times at lattiudes from 67 to 90 degrees North and South can be up to - 10 minutes different. - - An Almanac program that creates a year's worth of information for a given event, lattitude, longitude and timezone is included in the - developer code examples elsewhere in this help file. This creates an output file with an almost identical format to that used by the USNO web site - and allows comprehensive checking of acccuracy for a given set of parameters. - - - - - Returns the fraction of the Moon's surface that is illuminated - - Julian day (UTC) for which the Moon illumination is required - Percentage illumination of the Moon - The algorithm used is that given in Astronomical Algorithms (Second Edition, Corrected to August 2009) - Chapter 48 p345 by Jean Meeus (Willmann-Bell 1991). The Sun and Moon positions are calculated by high precision NOVAS 3.1 library using JPL DE 421 ephemeredes. - - - - - Returns the Moon phase as an angle - - Julian day (UTC) for which the Moon phase is required - Moon phase as an angle between -180.0 amd +180.0 (see Remarks for further description) - To allow maximum freedom in displaying the Moon phase, this function returns the excess of the apparent geocentric longitude - of the Moon over the apparent geocentric longitude of the Sun, expressed as an angle in the range -180.0 to +180.0 degrees. - This definition is taken from Astronomical Algorithms (Second Edition, Corrected to August 2009) Chapter 49 p349 - by Jean Meeus (Willmann-Bell 1991). - The frequently used eight phase description for phases of the Moon can be easily constructed from the results of this function - using logic similar to the following: - -Select Case MoonPhase - Case -180.0 To -135.0 - Phase = "Full Moon" - Case -135.0 To -90.0 - Phase = "Waning Gibbous" - Case -90.0 To -45.0 - Phase = "Last Quarter" - Case -45.0 To 0.0 - Phase = "Waning Crescent" - Case 0.0 To 45.0 - Phase = "New Moon" - Case 45.0 To 90.0 - Phase = "Waxing Crescent" - Case 90.0 To 135.0 - Phase = "First Quarter" - Case 135.0 To 180.0 - Phase = "Waxing Gibbous" -End Select - - Other representations can be easily constructed by changing the angle ranges and text descriptors as desired. The result range -180 to +180 - was chosen so that negative values represent the Moon waning and positive values represent the Moon waxing. - - - - - Return today's number of leap seconds - - Current leap seconds as a double - - - - Return the specified Julian day's number of leap seconds - - - Leap seconds as a double - - - - Return today's DeltaT value - - DeltaT value as a double - - - - Return the specified Julian day's DeltaT value - - - DeltaT value as a double - - - - Return today's DeltaUT1 value - - DeltaUT1 value as a double - - - - Return the specified Julian day'DeltaUT1 value - - - DeltaUT1 value as a double - - - - Type of event for which an ephemeris is required - - - - - - Type of body, Major Planet, Moon, Sun or Minor Planet - - - - - - Luna - - - - - - The Sun - - - - - - Major planet - - - - - - Minor planet - - - - - - Comet - - - - - - Co-ordinate origin: centre of Sun or solar system barycentre - - - - - - Centre of mass of the solar system - - - - - - Centre of mass of the Sun - - - - - - Body number starting with Mercury = 1 - - - - - - Mercury - - - - - - Venus - - - - - - Earth - - - - - - Mars - - - - - - Jupiter - - - - - - Saturn - - - - - - Uranus - - - - - - Neptune - - - - - - Pluto - - - - - - Sun - - - - - - Moon - - - - - - Type of refraction correction - - - - - - No refraction correction will be applied - - - - - - Refraction will be applied based on "standard" weather values of temperature = 10.0C and sea level pressure = 1010 millibar - - - - - - Refraction will be applied based on the temperature and pressure supplied in the site location structure - - - - - - Type of transformation: Epoch, Equator and Equinox or all three - - - - - - Change epoch only - - - - - - Change equator and equinox - - - - - - Change equator, equinox and epoch - - - - - - Direction of nutation correction - - - - - - Convert mean equator and equinox to true equator and equinox - - - - - - Convert true equator and equinox to mean equator and equinox - - - - - - Direction of transformation: ITRS to Terrestrial Intermediate or vice versa - - - - - - Location of observer - - - - - - Observer at centre of the earth - - - - - - Observer on earth's surface - - - - - - Observer in near-earth spacecraft - - - - - - Calculation accuracy - - - In full-accuracy mode, - -nutation calculations use the IAU 2000A model [iau2000a, nutation_angles]; -gravitational deflection is calculated using three bodies: Sun, Jupiter, and Saturn [grav_def]; -the equation of the equinoxes includes the entire series when computing the “complementary terms" [ee_ct]; -geocentric positions of solar system bodies are adjusted for light travel time using split, or two-part, - Julian dates in calls to ephemeris and iterate with a convergence tolerance of 10-12 days [light_time, ephemeris]; -ephemeris calls the appropriate solar system ephemeris using split, or two-part, Julian dates primarily to support - light-time calculations [ephemeris, solarsystem_hp, light_time]. - -In reduced-accuracy mode, - - nutation calculations use the 2000K model, which is the default for this mode; - gravitational deflection is calculated using only one body, the Sun [grav_def]; - the equation of the equinoxes excludes terms smaller than 2 microarcseconds when computing the "complementary terms" [ee_ct]; - geocentric positions of solar system bodies are adjusted for light travel time using single-value Julian dates - in calls to ephemeris and iterate with a convergence tolerance of 10-9 days [light-time, ephemeris, solarsystem]; - ephemeris calls the appropriate solar system ephemeris using single-value Julian dates [ephemeris, solarsystem]. - - In full-accuracy mode, the IAU 2000A nutation series (1,365 terms) is used [iau2000a]. Evaluating the series for nutation is - usually the main computational burden in NOVAS, so using reduced-accuracy mode improves execution time, often noticeably. - In reduced-accuracy mode, the NOVAS 2000K nutation series (488 terms) is used by default [nu2000k]. This mode can be used - when the accuracy requirements are not better than 0.1 milliarcsecond for stars or 3.5 milliarcseconds for solar system bodies. - Selecting this approach can reduce the time required for Earth-rotation computations by about two-thirds. - - - - - Full accuracy - - Suitable when precision of better than 0.1 milliarcsecond for stars or 3.5 milliarcseconds for solar system bodies is required. - - - - Reduced accuracy - - Suitable when precision of less than 0.1 milliarcsecond for stars or 3.5 milliarcseconds for solar system bodies is required. - - - - Coordinate system of the output position - - Used by function Place - - - - GCRS or "local GCRS" - - - - - - True equator and equinox of date - - - - - - True equator and CIO of date - - - - - - Astrometric coordinates, i.e., without light deflection or aberration. - - - - - - Type of sidereal time - - - - - - Greenwich mean sidereal time - - - - - - Greenwich apparent sidereal time - - - - - - Computation method - - - - - - Based on CIO - - - - - - Based on equinox - - - - - - Output vector reference system - - - - - - Referred to GCRS axes - - - - - - Referred to the equator and equinox of date - - - - - - Type of pole ofset - - Used by CelPole. - - - - For corrections to angular coordinates of modeled pole referred to mean ecliptic of date, that is, delta-delta-psi - and delta-delta-epsilon. - - - - - - For corrections to components of modeled pole unit vector referred to GCRS axes, that is, dx and dy. - - - - - - Direction of frame conversion - - Used by FrameTie method. - - - - Dynamical to ICRS transformation. - - - - - - ICRS to dynamical transformation. - - - - - - Location of observer, determining whether the gravitational deflection due to the earth itself is applied. - - Used by GravDef method. - - - - No earth deflection (normally means observer is at geocenter) - - - - - - Add in earth deflection (normally means observer is on or above surface of earth, including earth orbit) - - - - - - Reference system in which right ascension is given - - - - - - GCRS - - - - - - True equator and equinox of date - - - - - - Type of equinox - - - - - - Mean equinox - - - - - - True equinox - - - - - - Type of transformation - - - - - - Change epoch only - - - - - - Change equator and equinox; sane epoch - - - - - - Change equator, equinox and epoch - - - - - - change equator and equinox J2000.0 to ICRS - - - - - - change ICRS to equator and equinox of J2000.0 - - - - - - Type of object - - - - - - Major planet, sun or moon - - - - - - Minor planet - - - - - - Object located outside the solar system - - - - - - Body or location - - This numbering convention is used by ephemeris routines; do not confuse with the Body enum, which is used in most - other places within NOVAS3. - - The numbering convention for 'target' and'center' is: -
-             0  =  Mercury           7 = Neptune
-             1  =  Venus             8 = Pluto
-             2  =  Earth             9 = Moon
-             3  =  Mars             10 = Sun
-             4  =  Jupiter          11 = Solar system bary.
-             5  =  Saturn           12 = Earth-Moon bary.
-             6  =  Uranus           13 = Nutations (long. and obliq.)
-
- - If nutations are desired, set 'target' = 14; 'center' will be ignored on that call. - -
-
- - - Mercury - - - - - - Venus - - - - - - Earth - - - - - - Mars - - - - - - Jupiter - - - - - - Saturn - - - - - - Uranus - - - - - - Neptune - - - - - - Pluto - - - - - - Moon - - - - - - Sun - - - - - - Solar system barycentre - - - - - - Earth moon barycentre - - - - - - Nutations - - - - - - Structure to hold body type, number and name - - Designates a celestial object. - - - - - Type of body - - - 0 = Major planet, Sun, or Moon - 1 = Minor planet - - - - - body number - -
- For 'type' = 0: Mercury = 1, ..., Pluto = 9, Sun = 10, Moon = 11
- For 'type' = 1: minor planet number
- 
-
- - - Name of the body (limited to 99 characters) - - - - - - Structure to hold astrometric catalogue data - - - The astrometric catalog data for a star; equator and equinox and units will depend on the catalog. - While this structure can be used as a generic container for catalog data, all high-level - NOVAS-C functions require J2000.0 catalog data with FK5-type units (shown in square brackets below). - - - - - 3-character catalog designator. - - - - - - Name of star. - - - - - - Integer identifier assigned to star. - - - - - - Mean right ascension [hours]. - - - - - - Mean declination [degrees]. - - - - - - Proper motion in RA [seconds of time per century]. - - - - - - Proper motion in declination [arcseconds per century]. - - - - - - Parallax [arcseconds]. - - - - - - Radial velocity [kilometers per second] - - - - - - Structure to hold site information - - - Data for the observer's location. The atmospheric parameters are used only by the refraction - function called from function 'equ_to_hor'. Additional parameters can be added to this - structure if a more sophisticated refraction model is employed. - - - - - Geodetic latitude in degrees; north positive. - - - - - - Geodetic longitude in degrees; east positive. - - - - - - Height of the observer in meters. - - - - - - Temperature (degrees Celsius). - - - - - - Atmospheric pressure (millibars) - - - - - - Structure to hold a position vector - - Object position vector - - - - - x co-ordinate - - - - - - y co-ordinate - - - - - - z co-ordinate - - - - - - Structure to hold a velocity vector - - Object velocity vector - - - - - x velocity component - - - - - - y velocity component - - - - - - z velocity component - - - - - - Structure to hold Sun and Moon fundamental arguments - - Fundamental arguments, in radians - - - - - l (mean anomaly of the Moon) - - - - - - l' (mean anomaly of the Sun) - - - - - - F (L - omega; L = mean longitude of the Moon) - - - - - - D (mean elongation of the Moon from the Sun) - - - - - - Omega (mean longitude of the Moon's ascending node) - - - - - - Catalogue entry structure - - Basic astrometric data for any celestial object located outside the solar system; the catalog data for a star. - This structure is identical to the NOVAS2 CatEntry structure expect that, for some reason, the StarName and Catalog fields - have been swapped in the NOVAS3 structure. - - Please note that some units have changed from those used in NOVAS2 as follows: - - proper motion in right ascension: from seconds per century to milliarcseconds per year - proper motion in declination: from arcseconds per century to milliarcseconds per year - parallax: from arcseconds to milliarcseconds - - - - - - - Name of celestial object. (maximum 50 characters) - - - - - - 3-character catalog designator. - - - - - - Integer identifier assigned to object. - - - - - - ICRS right ascension (hours) - - - - - - ICRS declination (degrees) - - - - - - ICRS proper motion in right ascension (milliarcseconds/year) - - - - - - ICRS proper motion in declination (milliarcseconds/year) - - - - - - Parallax (milli-arcseconds) - - - - - - Radial velocity (km/s) - - - - - - Celestial object structure - - Designates a celestial object - - - - Type of object - - - - - - Object identification number - - - - - - Name of object(maximum 50 characters) - - - - - - Catalogue entry for the object - - - - - - Celestial object's place in the sky - - - - - - Unit vector toward object (dimensionless) - - - - - - Apparent, topocentric, or astrometric right ascension (hours) - - - - - - Apparent, topocentric, or astrometric declination (degrees) - - - - - - True (geometric, Euclidian) distance to solar system body or 0.0 for star (AU) - - - - - - Radial velocity (km/s) - - - - - - Observer’s position and velocity in a near-Earth spacecraft. - - - - - - Geocentric position vector (x, y, z), components in km with respect to true equator and equinox of date - - - - - - Geocentric velocity vector (x_dot, y_dot, z_dot), components in km/s with respect to true equator and equinox of date - - - - - - Right ascension of the Celestial Intermediate Origin (CIO) with respect to the GCRS. - - - - - - TDB Julian date - - - - - - Right ascension of the CIO with respect to the GCRS (arcseconds) - - - - - - Parameters of observer's location - - This structure is identical to the NOVAS2 SiteInfo structure but is included so that NOVAS3 naming - conventions are maintained, making it easier to relate this code to the NOVAS3 documentation and C code. - - - - Geodetic (ITRS) latitude; north positive (degrees) - - - - - - Geodetic (ITRS) longitude; east positive (degrees) - - - - - - Observer's height above sea level - - - - - - Observer's location's ambient temperature (degrees Celsius) - - - - - - Observer's location's atmospheric pressure (millibars) - - - - - - General specification for the observer's location - - - - - - Code specifying the location of the observer: 0=at geocenter; 1=surface of earth; 2=near-earth spacecraft - - - - - - Data for an observer's location on the surface of the Earth (where = 1) - - - - - - Data for an observer's location on a near-Earth spacecraft (where = 2) - - - - - - Interface to the coordinate transform component; J2000 - apparent - topocentric - - Use this component to transform between J2000, apparent and topocentric coordinates or - vice versa. To use the component, instantiate it, then use one of SetJ2000 or SetJNow or SetApparent to - initialise with known values. Now use the RAJ2000, DECJ200, RAJNow, DECJNow, RAApparent and DECApparent - properties to read off the required transformed values. -The component can be reused simply by setting new co-ordinates with a Set command, there - is no need to create a new component each time a transform is required. - Transforms are effected through the ASCOM NOVAS-COM engine that encapsulates the USNO NOVAS2 library. - The USNO NOVAS reference web page is: - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/novas/novas-fortran/novas-fortran - - - - - - Gets or sets the site latitude - - Site latitude - Latitude in degrees - Positive numbers north of the equator, negative numbers south. - - - - Gets or sets the site longitude - - Site longitude - Longitude in degrees - Positive numbers east of the Greenwich meridian, negative numbes west of the Greenwich meridian. - - - - Gets or sets the site elevation above sea level - - Site elevation - Elevation in metres - - - - - Gets or sets the site ambient temperature - - Site ambient temperature - Temperature in degrees Celsius - - - - - Gets or sets a flag indicating whether refraction is calculated for topocentric co-ordinates - - True / false flag indicating refaction is included / omitted from topocentric co-ordinates - Boolean flag - - - - - Causes the transform component to recalculate values derrived from the last Set command - - Use this when you have set J2000 co-ordinates and wish to ensure that the mount points to the same - co-ordinates allowing for local effects that change with time such as refraction. - - - - Sets the known J2000 Right Ascension and Declination coordinates that are to be transformed - - RA in J2000 co-ordinates - DEC in J2000 co-ordinates - - - - - Sets the known apparent Right Ascension and Declination coordinates that are to be transformed - - RA in apparent co-ordinates - DEC in apparent co-ordinates - - - - - Sets the known topocentric Right Ascension and Declination coordinates that are to be transformed - - RA in topocentric co-ordinates - DEC in topocentric co-ordinates - - - - - Returns the Right Ascension in J2000 co-ordinates - - J2000 Right Ascension - Right Ascension in hours - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Declination in J2000 co-ordinates - - J2000 Declination - J2000 Declination - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Right Ascension in topocentric co-ordinates - - Topocentric Right Ascension - Topocentric Right Ascension - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Declination in topocentric co-ordinates - - Topocentric Declination - Topocentric Declination - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Right Ascension in apparent co-ordinates - - Apparent Right Ascension - Right Ascension in hours - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Declination in apparent co-ordinates - - Apparent Declination - Declination in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the topocentric azimth angle of the target - - Topocentric azimuth angle - Azimuth angle in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the topocentric elevation of the target - - Topocentric elevation angle - Elevation angle in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Sets known Altitude and Azimuth values which are to be transformed - - Object's azimuth in degrees - Object's Elevation in degrees - - - - - Sets or return the Julian date (terrestrial time) for which the transform will be made - - Julian date (terrestrial time) of the transform - Terrestrial time Julian date that will be used by Transform or zero if the PC's current clock value will be used to calculate - the Julian date. - This method was introduced in May 2012. Previously, Transform used the current date-time of the PC when calculating transforms; - this remains the default behaviour for backward compatibility. - The inital value of this parameter is 0 which is a special value that forces Transform to replicate original behaviour by determining the - Julian date from the PC's current date and time. If this property is non zero, that terrestrial time Julian date is used in preference - to the value derrived from the PC's clock. - - - - Sets or return the Julian date (UTC) for which the transform will be made - - Julian date (UTC) of the transform - UTC Julian date that will be used by Transform or zero if the PC's current clock value will be used to calculate - the Julian date. - The inital value of this parameter is 0 which is a special value that forces Transform to replicate original behaviour by determining the - Julian date from the PC's current date and time. If this property is non zero, that UTC Julian date is used in preference - to the value derrived from the PC's clock. - - - - Coordinate transform component; J2000 - apparent - topocentric - - Use this component to transform between J2000, apparent and topocentric (JNow) coordinates or - vice versa. To use the component, instantiate it, then use one of SetJ2000 or SetJNow or SetApparent to - initialise with known values. Now use the RAJ2000, DECJ200, RAJNow, DECJNow, RAApparent and DECApparent etc. - properties to read off the required transformed values. -The component can be reused simply by setting new co-ordinates with a Set command, there - is no need to create a new component each time a transform is required. - Transforms are effected through the ASCOM NOVAS.Net engine that encapsulates the USNO NOVAS 3.1 library. - The USNO NOVAS reference web page is: - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/novas - and the NOVAS 3.1 user guide is included in the ASCOM Developer Components install. - - - - - - Cleans up resources used by the Transform component - - - - - - Gets or sets the site latitude - - Site latitude - Latitude in degrees - Positive numbers north of the equator, negative numbers south. - - - - Gets or sets the site longitude - - Site longitude - Longitude in degrees - Positive numbers east of the Greenwich meridian, negative numbes west of the Greenwich meridian. - - - - Gets or sets the site elevation above sea level - - Site elevation - Elevation in metres - - - - - Gets or sets the site ambient temperature - - Site ambient temperature - Temperature in degrees Celsius - - - - - Gets or sets a flag indicating whether refraction is calculated for topocentric co-ordinates - - True / false flag indicating refaction is included / omitted from topocentric co-ordinates - Boolean flag - - - - - Causes the transform component to recalculate values derrived from the last Set command - - Use this when you have set J2000 co-ordinates and wish to ensure that the mount points to the same - co-ordinates allowing for local effects that change with time such as refraction. - Note: As of Platform 6 SP2 use of this method is not required, refresh is always performed automatically when required. - - - - Sets the known J2000 Right Ascension and Declination coordinates that are to be transformed - - RA in J2000 co-ordinates - DEC in J2000 co-ordinates - - - - - Sets the known apparent Right Ascension and Declination coordinates that are to be transformed - - RA in apparent co-ordinates - DEC in apparent co-ordinates - - - - - Sets the known topocentric Right Ascension and Declination coordinates that are to be transformed - - RA in topocentric co-ordinates - DEC in topocentric co-ordinates - - - - - Sets the topocentric azimuth and elevation - - Topocentric Azimuth in degrees - Topocentric elevation in degrees - - - - - Returns the Right Ascension in J2000 co-ordinates - - J2000 Right Ascension - Right Ascension in hours - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - - Returns the Declination in J2000 co-ordinates - - J2000 Declination - Declination in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Right Ascension in topocentric co-ordinates - - Topocentric Right Ascension - Topocentric Right Ascension in hours - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Declination in topocentric co-ordinates - - Topocentric Declination - Declination in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Right Ascension in apparent co-ordinates - - Apparent Right Ascension - Right Ascension in hours - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the Declination in apparent co-ordinates - - Apparent Declination - Declination in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the topocentric azimth angle of the target - - Topocentric azimuth angle - Azimuth angle in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Returns the topocentric elevation of the target - - Topocentric elevation angle - Elevation angle in degrees - Exception thrown if an attempt is made - to read a value before any of the Set methods has been used or if the value can not be derived from the - information in the last Set method used. E.g. topocentric values will be unavailable if the last Set was - a SetApparent and one of the Site properties has not been set. - - - - - Sets or returns the Julian date on the Terrestrial Time timescale for which the transform will be made - - Julian date (Terrestrial Time) of the transform - Terrestrial Time Julian date that will be used by Transform or zero if the PC's current clock value will be used to calculate the Julian date. - This method was introduced in May 2012. Previously, Transform used the current date-time of the PC when calculating transforms; - this remains the default behaviour for backward compatibility. - The inital value of this parameter is 0.0, which is a special value that forces Transform to replicate original behaviour by determining the - Julian date from the PC's current date and time. If this property is non zero, that particular terrestrial time Julian date is used in preference - to the value derrived from the PC's clock. - Only one of JulianDateTT or JulianDateUTC needs to be set. Use whichever is more readily available, there is no - need to set both values. Transform will use the last set value of either JulianDateTT or JulianDateUTC as the basis for its calculations. - - - - Sets or returns the Julian date on the UTC timescale for which the transform will be made - - Julian date (UTC) of the transform - UTC Julian date that will be used by Transform or zero if the PC's current clock value will be used to calculate the Julian date. - Introduced in April 2014 as an alternative to JulianDateTT. Only one of JulianDateTT or JulianDateUTC needs to be set. Use whichever is more readily available, there is no - need to set both values. Transform will use the last set value of either JulianDateTT or JulianDateUTC as the basis for its calculations. - - - - Interface to the Kepler Ephemeris component - - - The Ephemeris object contains an orbit engine which takes the orbital parameters of a solar system - body, plus a a terrestrial date/time, and produces the heliocentric equatorial position and - velocity vectors of the body in Cartesian coordinates. Orbital parameters are not required for - the major planets, Kepler contains an ephemeris generator for these bodies that is within 0.05 - arc seconds of the JPL DE404 over a wide range of times, Perturbations from major planets are applied - to ephemerides for minor planets. - The results are passed back as an array containing the two vectors. - Note that this is the format expected for the ephemeris generator used by the NOVAS-COM vector - astrometry engine. For more information see the description of Ephemeris.GetPositionAndVelocity(). - - Ephemeris Calculations
- The ephemeris calculations in Kepler draw heavily from the work of - Stephen Moshier moshier@world.std.com. kepler is released as a free software package, further - extending the work of Mr. Moshier.
- Kepler does not integrate orbits to the current epoch. If you want the accuracy resulting from - an integrated orbit, you must integrate separately and supply Kepler with elements of the current - epoch. Orbit integration is on the list of things for the next major version. - Kepler uses polynomial approximations for the major planet ephemerides. The tables - of coefficients were derived by a least squares fit of periodic terms to JPL's DE404 ephemerides. - The periodic frequencies used were determined by spectral analysis and comparison with VSOP87 and - other analytical planetary theories. The least squares fit to DE404 covers the interval from -3000 - to +3000 for the outer planets, and -1350 to +3000 for the inner planets. For details on the - accuracy of the major planet ephemerides, see the Accuracy Tables page. - - Date and Time Systems

- For a detailed explanation of astronomical timekeeping systems, see A Time Tutorial on the NASA - Goddard Spaceflight Center site, and the USNO Systems of Time site. -

ActiveX Date values
- These are the Windows standard "date serial" numbers, and are expressed in local time or - UTC (see below). The fractional part of these numbers represents time within a day. - They are used throughout applications such as Excel, Visual Basic, VBScript, and other - ActiveX capable environments. -

Julian dates
- These are standard Julian "date serial" numbers, and are expressed in UTC time or Terrestrial - time. The fractional part of these numbers represents time within a day. The standard ActiveX - "Double" precision of 15 digits gives a resolution of about one millisecond in a full Julian date. - This is sufficient for the purposes of this program. -

Hourly Time Values
- These are typically used to represent sidereal time and right ascension. They are simple real - numbers in units of hours. -

UTC Time Scale
- Most of the ASCOM methods and properties that accept date/time values (either Date or Julian) - assume that the date/time is in Coordinated Universal Time (UTC). Where necessary, this time - is converted internally to other scales. Note that UTC seconds are based on the Cesium atom, - not planetary motions. In order to keep UTC in sync with planetary motion, leap seconds are - inserted periodically. The error is at most 900 milliseconds. -

UT1 Time Scale
- The UT1 time scale is the planetary equivalent of UTC. It it runs smoothly and varies a bit - with time, but it is never more than 900 milliseconds different from UTC. -

TT Time Scale
- The Terrestrial Dynamical Time (TT) scale is used in solar system orbital calculations. - It is based completely on planetary motions; you can think of the solar system as a giant - TT clock. It differs from UT1 by an amount called "delta-t", which slowly increases with time, - and is about 60 seconds right now (2001).
-
-
- - - Compute rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and - velocity (KM/sec.). - - Terrestrial Julian date/time for which position and velocity is to be computed - Array of 6 values containing rectangular (x/y/z) heliocentric J2000 equatorial - coordinates of position (AU) and velocity (KM/sec.) for the body. - The TJD parameter is the date/time as a Terrestrial Time Julian date. See below for - more info. If you are using ACP, there are functions available to convert between UTC and - Terrestrial time, and for estimating the current value of delta-T. See the Overview page for - the Kepler.Ephemeris class for more information on time keeping systems. - - - - Semi-major axis (AU) - - Semi-major axis in AU - Semi-major axis in AU - - - - - The type of solar system body represented by this instance of the ephemeris engine (enum) - - The type of solar system body represented by this instance of the ephemeris engine (enum) - 0 for major planet, 1 for minot planet and 2 for comet - - - - - Orbital eccentricity - - Orbital eccentricity - Orbital eccentricity - - - - - Epoch of osculation of the orbital elements (terrestrial Julian date) - - Epoch of osculation of the orbital elements - Terrestrial Julian date - - - - - Slope parameter for magnitude - - Slope parameter for magnitude - Slope parameter for magnitude - - - - - Absolute visual magnitude - - Absolute visual magnitude - Absolute visual magnitude - - - - - The J2000.0 inclination (deg.) - - The J2000.0 inclination - Degrees - - - - - Mean anomaly at the epoch - - Mean anomaly at the epoch - Mean anomaly at the epoch - - - - - Mean daily motion (deg/day) - - Mean daily motion - Degrees per day - - - - - The name of the body. - - The name of the body or packed MPC designation - The name of the body or packed MPC designation - If this instance represents an unnumbered minor planet, Ephemeris.Name must be the - packed MPC designation. For other types, this is for display only. - - - - The J2000.0 longitude of the ascending node (deg.) - - The J2000.0 longitude of the ascending node - Degrees - - - - - The major or minor planet number - - The major or minor planet number - Number or zero if not numbered - - - - - Orbital period (years) - - Orbital period - Years - - - - - The J2000.0 argument of perihelion (deg.) - - The J2000.0 argument of perihelion - Degrees - - - - - Perihelion distance (AU) - - Perihelion distance - AU - - - - - Reciprocal semi-major axis (1/AU) - - Reciprocal semi-major axis - 1/AU - - - - - KEPLER: Ephemeris Object - - - The Kepler Ephemeris object contains an orbit engine which takes the orbital parameters of a solar system - body, plus a a terrestrial date/time, and produces the heliocentric equatorial position and - velocity vectors of the body in Cartesian coordinates. Orbital parameters are not required for - the major planets, Kepler contains an ephemeris generator for these bodies that is within 0.05 - arc seconds of the JPL DE404 over a wide range of times, Perturbations from major planets are applied - to ephemerides for minor planets. - The results are passed back as an array containing the two vectors. - Note that this is the format expected for the ephemeris generator used by the NOVAS-COM vector - astrometry engine. For more information see the description of Ephemeris.GetPositionAndVelocity(). - - Ephemeris Calculations
- The ephemeris calculations in Kepler draw heavily from the work of - Stephen Moshier moshier@world.std.com. kepler is released as a free software package, further - extending the work of Mr. Moshier.
- Kepler does not integrate orbits to the current epoch. If you want the accuracy resulting from - an integrated orbit, you must integrate separately and supply Kepler with elements of the current - epoch. Orbit integration is on the list of things for the next major version. - Kepler uses polynomial approximations for the major planet ephemerides. The tables - of coefficients were derived by a least squares fit of periodic terms to JPL's DE404 ephemerides. - The periodic frequencies used were determined by spectral analysis and comparison with VSOP87 and - other analytical planetary theories. The least squares fit to DE404 covers the interval from -3000 - to +3000 for the outer planets, and -1350 to +3000 for the inner planets. For details on the - accuracy of the major planet ephemerides, see the Accuracy Tables page. - - Date and Time Systems

- For a detailed explanation of astronomical timekeeping systems, see A Time Tutorial on the NASA - Goddard Spaceflight Center site, and the USNO Systems of Time site. -

ActiveX Date values
- These are the Windows standard "date serial" numbers, and are expressed in local time or - UTC (see below). The fractional part of these numbers represents time within a day. - They are used throughout applications such as Excel, Visual Basic, VBScript, and other - ActiveX capable environments. -

Julian dates
- These are standard Julian "date serial" numbers, and are expressed in UTC time or Terrestrial - time. The fractional part of these numbers represents time within a day. The standard ActiveX - "Double" precision of 15 digits gives a resolution of about one millisecond in a full Julian date. - This is sufficient for the purposes of this program. -

Hourly Time Values
- These are typically used to represent sidereal time and right ascension. They are simple real - numbers in units of hours. -

UTC Time Scale
- Most of the ASCOM methods and properties that accept date/time values (either Date or Julian) - assume that the date/time is in Coordinated Universal Time (UTC). Where necessary, this time - is converted internally to other scales. Note that UTC seconds are based on the Cesium atom, - not planetary motions. In order to keep UTC in sync with planetary motion, leap seconds are - inserted periodically. The error is at most 900 milliseconds. -

UT1 Time Scale
- The UT1 time scale is the planetary equivalent of UTC. It it runs smoothly and varies a bit - with time, but it is never more than 900 milliseconds different from UTC. -

TT Time Scale
- The Terrestrial Dynamical Time (TT) scale is used in solar system orbital calculations. - It is based completely on planetary motions; you can think of the solar system as a giant - TT clock. It differs from UT1 by an amount called "delta-t", which slowly increases with time, - and is about 60 seconds right now (2001).
-
-
- - - Create a new Ephemeris component and initialise it - - - - - - Semi-major axis (AU) - - Semi-major axis in AU - Semi-major axis in AU - - - - - The type of solar system body represented by this instance of the ephemeris engine (enum) - - The type of solar system body represented by this instance of the ephemeris engine (enum) - 0 for major planet, 1 for minot planet and 2 for comet - - - - - Orbital eccentricity - - Orbital eccentricity - Orbital eccentricity - - - - - Epoch of osculation of the orbital elements (terrestrial Julian date) - - Epoch of osculation of the orbital elements - Terrestrial Julian date - - - - - Slope parameter for magnitude - - Slope parameter for magnitude - Slope parameter for magnitude - - - - - Compute rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and - velocity (KM/sec.). - - Terrestrial Julian date/time for which position and velocity is to be computed - Array of 6 values containing rectangular (x/y/z) heliocentric J2000 equatorial - coordinates of position (AU) and velocity (KM/sec.) for the body. - The TJD parameter is the date/time as a Terrestrial Time Julian date. See below for - more info. If you are using ACP, there are functions available to convert between UTC and - Terrestrial time, and for estimating the current value of delta-T. See the Overview page for - the Kepler.Ephemeris class for more information on time keeping systems. - - - - Absolute visual magnitude - - Absolute visual magnitude - Absolute visual magnitude - - - - - The J2000.0 inclination (deg.) - - The J2000.0 inclination - Degrees - - - - - Mean anomaly at the epoch - - Mean anomaly at the epoch - Mean anomaly at the epoch - - - - - Mean daily motion (deg/day) - - Mean daily motion - Degrees per day - - - - - The name of the body. - - The name of the body or packed MPC designation - The name of the body or packed MPC designation - If this instance represents an unnumbered minor planet, Ephemeris.Name must be the - packed MPC designation. For other types, this is for display only. - - - - The J2000.0 longitude of the ascending node (deg.) - - The J2000.0 longitude of the ascending node - Degrees - - - - - The major or minor planet number - - The major or minor planet number - Number or zero if not numbered - - - - - Orbital period (years) - - Orbital period - Years - - - - - The J2000.0 argument of perihelion (deg.) - - The J2000.0 argument of perihelion - Degrees - - - - - Perihelion distance (AU) - - Perihelion distance - AU - - - - - Reciprocal semi-major axis (1/AU) - - Reciprocal semi-major axis - 1/AU - - - - - Interface to an Earth object that represents the "state" of the Earth at a given Terrestrial Julian date - - Objects of class Earth represent the "state" of the Earth at a given Terrestrial Julian date. - The state includes barycentric and heliocentric position vectors for the earth, plus obliquity, - nutation and the equation of the equinoxes. Unless set by the client, the Earth ephemeris used is - computed using an internal approximation. The client may optionally attach an ephemeris object for - increased accuracy. - Ephemeris Generator
- The ephemeris generator object used with NOVAS-COM must support a single - method GetPositionAndVelocity(tjd). This method must take a terrestrial Julian date (like the - NOVAS-COM methods) as its single parameter, and return an array of Double - containing the rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and velocity - (KM/sec.). In addition, it must support three read/write properties BodyType, Name, and Number, - which correspond to the Type, Name, and Number properties of Novas.Planet. -
-
- - - Initialize the Earth object for given terrestrial Julian date - - Terrestrial Julian date - True if successful, else throws an exception - - - - - Earth barycentric position - - Barycentric position vector - AU (Ref J2000) - - - - - Earth barycentric time - - Barycentric dynamical time for given Terrestrial Julian Date - Julian date - - - - - Earth barycentric velocity - - Barycentric velocity vector - AU/day (ref J2000) - - - - - Ephemeris object used to provide the position of the Earth. - - Earth ephemeris object - Earth ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - Earth equation of equinoxes - - Equation of the equinoxes - Seconds - - - - - Earth heliocentric position - - Heliocentric position vector - AU (ref J2000) - - - - - Earth heliocentric velocity - - Heliocentric velocity - Velocity vector, AU/day (ref J2000) - - - - - Earth mean objiquity - - Mean obliquity of the ecliptic - Degrees - - - - - Earth nutation in longitude - - Nutation in longitude - Degrees - - - - - Earth nutation in obliquity - - Nutation in obliquity - Degrees - - - - - Earth true obliquity - - True obliquity of the ecliptic - Degrees - - - - - Interface to a Planet component that provides characteristics of a solar system body - - Objects of class Planet hold the characteristics of a solar system body. Properties are - type (major or minor planet), number (for major and numbered minor planets), name (for unnumbered - minor planets and comets), the ephemeris object to be used for orbital calculations, an optional - ephemeris object to use for barycenter calculations, and an optional value for delta-T. - The high-level NOVAS astrometric functions are implemented as methods of Planet: - GetTopocentricPosition(), GetLocalPosition(), GetApparentPosition(), GetVirtualPosition(), - and GetAstrometricPosition(). These methods operate on the properties of the Planet, and produce - a PositionVector object. For example, to get the topocentric coordinates of a planet, create and - initialize a planet, create initialize and attach an ephemeris object, then call - Planet.GetTopocentricPosition(). The resulting PositionVector's right ascension and declination - properties are the topocentric equatorial coordinates, at the same time, the (optionally - refracted) alt-az coordinates are calculated, and are also contained within the returned - PositionVector. Note that Alt/Az is available in PositionVectors returned from calling - GetTopocentricPosition(). The accuracy of these calculations is typically dominated by the accuracy - of the attached ephemeris generator. - Ephemeris Generator
- By default, Kepler instances are attached for both Earth and Planet objects so it is - not necessary to create and attach these in order to get Kepler accuracy from this - component
- The ephemeris generator object used with NOVAS-COM must support a single - method GetPositionAndVelocity(tjd). This method must take a terrestrial Julian date (like the - NOVAS-COM methods) as its single parameter, and return an array of Double - containing the rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and velocity - (KM/sec.). In addition, it must support three read/write properties BodyType, Name, and Number, - which correspond to the Type, Name, and Number properties of Novas.Planet. - -
-
- - - Get an apparent position for given time - - Terrestrial Julian Date for the position - PositionVector for the apparent place. - - - - - Get an astrometric position for given time - - Terrestrial Julian Date for the position - PositionVector for the astrometric place. - - - - - Get an local position for given time - - Terrestrial Julian Date for the position - The observing site - PositionVector for the local place. - - - - - Get a topocentric position for given time - - Terrestrial Julian Date for the position - The observing site - Apply refraction correction - PositionVector for the topocentric place. - - - - - Get a virtual position for given time - - Terrestrial Julian Date for the position - PositionVector for the virtual place. - - - - - Planet delta-T - - The value of delta-T (TT - UT1) to use for reductions - Seconds - Setting this value is optional. If no value is set, an internal delta-T generator is used. - - - - Ephemeris object used to provide the position of the Earth. - - Earth ephemeris object - Earth ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - The Ephemeris object used to provide positions of solar system bodies. - - Body ephemeris object - Body ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - - Planet name - - For unnumbered minor planets, (Type=nvMinorPlanet and Number=0), the packed designation - for the minor planet. For other types, this is not significant, but may be used to store - a name. - Name of planet - - - - - Planet number - - For major planets (Type=nvMajorPlanet), a PlanetNumber value. For minor planets - (Type=nvMinorPlanet), the number of the minor planet or 0 for unnumbered minor planet. - Planet number - The major planet number is its number out from the sun starting with Mercury = 1 - - - - The type of solar system body - - The type of solar system body - Value from the BodyType enum - - - - - Interface to the NOVAS-COM PositionVector Class - - Objects of class PositionVector contain vectors used for positions (earth, sites, - stars and planets) throughout NOVAS-COM. Of course, its properties include the x, y, and z - components of the position. Additional properties are right ascension and declination, distance, - and light time (applicable to star positions), and Alt/Az (available only in PositionVectors - returned by Star or Planet methods GetTopocentricPosition()). You can initialize a PositionVector - from a Star object (essentially an FK5 or HIP catalog entry) or a Site (lat/long/height). - PositionVector has methods that can adjust the coordinates for precession, aberration and - proper motion. Thus, a PositionVector object gives access to some of the lower-level NOVAS functions. - Note: The equatorial coordinate properties of this object are dependent variables, and thus are read-only. Changing any cartesian coordinate will cause the equatorial coordinates to be recalculated. - - - - - Adjust the position vector of an object for aberration of light - - The velocity vector of the observer - The algorithm includes relativistic terms - - - - Adjust the position vector for precession of equinoxes between two given epochs - - The first epoch (Terrestrial Julian Date) - The second epoch (Terrestrial Julian Date) - The coordinates are referred to the mean equator and equinox of the two respective epochs. - - - - Adjust the position vector for proper motion (including foreshortening effects) - - The velocity vector of the object - The first epoch (Terrestrial Julian Date) - The second epoch (Terrestrial Julian Date) - True if successful or throws an exception. - - If the position vector x, y or z values has not been set - If the supplied velocity vector does not have valid x, y and z components - - - - Initialize the PositionVector from a Site object and Greenwich apparent sidereal time. - - The Site object from which to initialize - Greenwich Apparent Sidereal Time - True if successful or throws an exception - The GAST parameter must be for Greenwich, not local. The time is rotated through the - site longitude. See SetFromSiteJD() for an equivalent method that takes UTC Julian Date and - Delta-T (eliminating the need for calculating hyper-accurate GAST yourself). - - - - Initialize the PositionVector from a Site object using UTC Julian date and Delta-T - - The Site object from which to initialize - UTC Julian Date - The value of Delta-T (TT - UT1) to use for reductions (seconds) - True if successful or throws an exception - The Julian date must be UTC Julian date, not terrestrial. - - - - - Initialize the PositionVector from a Star object. - - The Star object from which to initialize - True if successful or throws an exception - - If Parallax, RightAScension or Declination is not available in the supplied star object. - - - - The azimuth coordinate (degrees, + east) - - The azimuth coordinate - Degrees, + East - - - - - Declination coordinate - - Declination coordinate - Degrees - - - - - Distance/Radius coordinate - - Distance/Radius coordinate - AU - - - - - The elevation (altitude) coordinate (degrees, + up) - - The elevation (altitude) coordinate (degrees, + up) - (Degrees, + up - Elevation is available only in PositionVectors returned from calls to - Star.GetTopocentricPosition() and/or Planet.GetTopocentricPosition(). - When the position vector has not been - initialised from Star.GetTopoCentricPosition and Planet.GetTopocentricPosition - - - - Light time from body to origin, days. - - Light time from body to origin - Days - - - - - RightAscension coordinate, hours - - RightAscension coordinate - Hours - - - - - Position cartesian x component - - Cartesian x component - Cartesian x component - - - - - Position cartesian y component - - Cartesian y component - Cartesian y component - - - - - Position cartesian z component - - Cartesian z component - Cartesian z component - - - - - Interface for PositionVector methods that are only accessible through .NET and not through COM - - - - - - Initialize the PositionVector from a Site object using UTC Julian date - - The Site object from which to initialize - UTC Julian Date - True if successful or throws an exception - The Julian date must be UTC Julian date, not terrestrial. Calculations will use the internal delta-T tables and estimator to get - delta-T. - This overload is not available through COM, please use - "SetFromSiteJD(ByVal site As Site, ByVal ujd As Double, ByVal delta_t As Double)" - with delta_t set to 0.0 to achieve this effect. - - - - - Interface to the NOVAS-COM Site Class - - Objects of class Site contain the specifications for an observer's location on the Earth - ellipsoid. Properties are latitude, longitude, height above mean sea level, the ambient temperature - and the sea-level barmetric pressure. The latter two are used only for optional refraction corrections. - Latitude and longitude are (common) geodetic, not geocentric. - - - - Set all site properties in one method call - - The geodetic latitude (degrees, + north) - The geodetic longitude (degrees, +east) - Height above sea level (meters) - - - - - Height above mean sea level - - Height above mean sea level - Meters - - - - - Geodetic latitude (degrees, + north) - - Geodetic latitude - Degrees, + north - - - - - Geodetic longitude (degrees, + east) - - Geodetic longitude - Degrees, + east - - - - - Barometric pressure (millibars) - - Barometric pressure - Millibars - - - - - Ambient temperature (deg. Celsius) - - Ambient temperature - Degrees Celsius) - - - - - Interface to the NOVAS-COM Star Class - - Objects of class Site contain the specifications for a star's catalog position in either FK5 or Hipparcos units (both must be J2000). Properties are right ascension and declination, proper motions, parallax, radial velocity, catalog type (FK5 or HIP), catalog number, optional ephemeris engine to use for barycenter calculations, and an optional value for delta-T. Unless you specifically set the DeltaT property, calculations performed by this class which require the value of delta-T (TT - UT1) rely on an internal function to estimate delta-T. -The high-level NOVAS astrometric functions are implemented as methods of Star: - GetTopocentricPosition(), GetLocalPosition(), GetApparentPosition(), GetVirtualPosition(), - and GetAstrometricPosition(). These methods operate on the properties of the Star, and produce - a PositionVector object. For example, to get the topocentric coordinates of a star, simply create - and initialize a Star, then call Star.GetTopocentricPosition(). The resulting vaPositionVector's - right ascension and declination properties are the topocentric equatorial coordinates, at the same - time, the (optionally refracted) alt-az coordinates are calculated, and are also contained within - the returned PositionVector. Note that Alt/Az is available in PositionVectors returned from calling - GetTopocentricPosition(). - - - - Initialize all star properties with one call - - Catalog mean right ascension (hours) - Catalog mean declination (degrees) - Catalog mean J2000 proper motion in right ascension (sec/century) - Catalog mean J2000 proper motion in declination (arcsec/century) - Catalog mean J2000 parallax (arcsec) - Catalog mean J2000 radial velocity (km/sec) - Assumes positions are FK5. If Parallax is set to zero, NOVAS-COM assumes the object - is on the "celestial sphere", which has a distance of 10 megaparsecs. - - - - Initialise all star properties in one call using Hipparcos data. Transforms to FK5 standard used by NOVAS. - - Catalog mean right ascension (hours) - Catalog mean declination (degrees) - Catalog mean J2000 proper motion in right ascension (sec/century) - Catalog mean J2000 proper motion in declination (arcsec/century) - Catalog mean J2000 parallax (arcsec) - Catalog mean J2000 radial velocity (km/sec) - Assumes positions are Hipparcos standard and transforms to FK5 standard used by NOVAS. - If Parallax is set to zero, NOVAS-COM assumes the object is on the "celestial sphere", - which has a distance of 10 megaparsecs. - - - - - Get an apparent position for a given time - - Terrestrial Julian Date for the position - PositionVector for the apparent place. - - - - - Get an astrometric position for a given time - - Terrestrial Julian Date for the position - PositionVector for the astrometric place. - - - - - Get a local position for a given site and time - - Terrestrial Julian Date for the position - A Site object representing the observing site - PositionVector for the local place. - - - - - Get a topocentric position for a given site and time - - Terrestrial Julian Date for the position - A Site object representing the observing site - True to apply atmospheric refraction corrections - PositionVector for the topocentric place. - - - - - Get a virtual position at a given time - - Terrestrial Julian Date for the position - PositionVector for the virtual place. - - - - - Three character catalog code for the star's data - - Three character catalog code for the star's data - Three character catalog code for the star's data - Typically "FK5" but may be "HIP". For information only. - - - - Mean catalog J2000 declination coordinate (degrees) - - Mean catalog J2000 declination coordinate - Degrees - - - - - The value of delta-T (TT - UT1) to use for reductions. - - The value of delta-T (TT - UT1) to use for reductions. - Seconds - If this property is not set, calculations will use an internal function to estimate delta-T. - - - - Ephemeris object used to provide the position of the Earth. - - Ephemeris object used to provide the position of the Earth. - Ephemeris object - If this value is not set, an internal Kepler object will be used to determine - Earth ephemeris - - - - The catalog name of the star (50 char max) - - The catalog name of the star - Name (50 char max) - - - - - The catalog number of the star - - The catalog number of the star - The catalog number of the star - - - - - Catalog mean J2000 parallax (arcsec) - - Catalog mean J2000 parallax - Arc seconds - - - - - Catalog mean J2000 proper motion in declination (arcsec/century) - - Catalog mean J2000 proper motion in declination - Arc seconds per century - - - - - Catalog mean J2000 proper motion in right ascension (sec/century) - - Catalog mean J2000 proper motion in right ascension - Seconds per century - - - - - Catalog mean J2000 radial velocity (km/sec) - - Catalog mean J2000 radial velocity - Kilometers per second - - - - - Catalog mean J2000 right ascension coordinate (hours) - - Catalog mean J2000 right ascension coordinate - Hours - - - - - interface to the NOVAS_COM VelocityVector Class - - Objects of class VelocityVector contain vectors used for velocities (earth, sites, - planets, and stars) throughout NOVAS-COM. Of course, its properties include the x, y, and z - components of the velocity. Additional properties are the velocity in equatorial coordinates of - right ascension dot, declination dot and radial velocity. You can initialize a PositionVector from - a Star object (essentially an FK5 or HIP catalog entry) or a Site (lat/long/height). For the star - object the proper motions, distance and radial velocity are used, for a site, the velocity is that - of the observer with respect to the Earth's center of mass. - - - - Initialize the VelocityVector from a Site object and Greenwich Apparent Sdereal Time. - - The Site object from which to initialize - Greenwich Apparent Sidereal Time - True if OK or throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The GAST parameter must be for Greenwich, not local. The time is rotated through - the site longitude. See SetFromSiteJD() for an equivalent method that takes UTC Julian - Date and optionally Delta-T (eliminating the need for calculating hyper-accurate GAST yourself). - - - - Initialize the VelocityVector from a Site object using UTC Julian Date and Delta-T - - The Site object from which to initialize - UTC Julian Date - The optional value of Delta-T (TT - UT1) to use for reductions (seconds) - True if OK otherwise throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The Julian date must be UTC Julian date, not terrestrial. - - - - Initialize the VelocityVector from a Star object. - - The Star object from which to initialize - True if OK otherwise throws an exception - The proper motions, distance and radial velocity are used in the velocity calculation. - If any of: Parallax, RightAscension, Declination, - ProperMotionRA, ProperMotionDec or RadialVelocity are not available in the star object - - - - Linear velocity along the declination direction (AU/day) - - Linear velocity along the declination direction - AU/day - This is not the proper motion (which is an angular rate and is dependent on the distance to the object). - - - - Linear velocity along the radial direction (AU/day) - - Linear velocity along the radial direction - AU/day - - - - - Linear velocity along the right ascension direction (AU/day) - - Linear velocity along the right ascension direction - AU/day - - - - - Cartesian x component of velocity (AU/day) - - Cartesian x component of velocity - AU/day - - - - - Cartesian y component of velocity (AU/day) - - Cartesian y component of velocity - AU/day - - - - - Cartesian z component of velocity (AU/day) - - Cartesian z component of velocity - AU/day - - - - - Interface for VelocityVector methods that are only accessible through .NET and not through COM - - - - - - Initialize the VelocityVector from a Site object using UTC Julian Date - - The Site object from which to initialize - UTC Julian Date - True if OK otherwise throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The Julian date must be UTC Julian date, not terrestrial. This call will use - the internal tables and estimator to get delta-T. - This overload is not available through COM, please use - "SetFromSiteJD(ByVal site As Site, ByVal ujd As Double, ByVal delta_t As Double)" - with delta_t set to 0.0 to achieve this effect. - - - - - NOVAS-COM: Represents the "state" of the Earth at a given Terrestrial Julian date - - NOVAS-COM objects of class Earth represent the "state" of the Earth at a given Terrestrial Julian date. - The state includes barycentric and heliocentric position vectors for the earth, plus obliquity, - nutation and the equation of the equinoxes. Unless set by the client, the Earth ephemeris used is - computed using an internal approximation. The client may optionally attach an ephemeris object for - increased accuracy. - Ephemeris Generator
- The ephemeris generator object used with NOVAS-COM must support a single - method GetPositionAndVelocity(tjd). This method must take a terrestrial Julian date (like the - NOVAS-COM methods) as its single parameter, and return an array of Double - containing the rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and velocity - (KM/sec.). In addition, it must support three read/write properties BodyType, Name, and Number, - which correspond to the Type, Name, and Number properties of Novas.Planet. -
-
- - - Create a new instance of the Earth object - - - - - - Earth barycentric position - - Barycentric position vector - AU (Ref J2000) - - - - - Earth barycentric time - - Barycentric dynamical time for given Terrestrial Julian Date - Julian date - - - - - Earth barycentric velocity - - Barycentric velocity vector - AU/day (ref J2000) - - - - - Ephemeris object used to provide the position of the Earth. - - Earth ephemeris object - Earth ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - Earth equation of equinoxes - - Equation of the equinoxes - Seconds - - - - - Earth heliocentric position - - Heliocentric position vector - AU (ref J2000) - - - - - Earth heliocentric velocity - - Heliocentric velocity - Velocity vector, AU/day (ref J2000) - - - - - Earth mean objiquity - - Mean obliquity of the ecliptic - Degrees - - - - - Earth nutation in longitude - - Nutation in longitude - Degrees - - - - - Earth nutation in obliquity - - Nutation in obliquity - Degrees - - - - - Initialize the Earth object for given terrestrial Julian date - - Terrestrial Julian date - True if successful, else throws an exception - - - - - Earth true obliquity - - True obliquity of the ecliptic - Degrees - - - - - NOVAS-COM: Provide characteristics of a solar system body - - NOVAS-COM objects of class Planet hold the characteristics of a solar system body. Properties are - type (major or minor planet), number (for major and numbered minor planets), name (for unnumbered - minor planets and comets), the ephemeris object to be used for orbital calculations, an optional - ephemeris object to use for barycenter calculations, and an optional value for delta-T. - The number values for major planets are 1 to 9 for Mercury to Pluto, 10 for Sun and 11 for Moon. The last two obviously - aren't planets, but this numbering is a NOVAS convention that enables us to retrieve useful information about these bodies. - - The high-level NOVAS astrometric functions are implemented as methods of Planet: - GetTopocentricPosition(), GetLocalPosition(), GetApparentPosition(), GetVirtualPosition(), - and GetAstrometricPosition(). These methods operate on the properties of the Planet, and produce - a PositionVector object. For example, to get the topocentric coordinates of a planet, create and - initialize a planet then call - Planet.GetTopocentricPosition(). The resulting PositionVector's right ascension and declination - properties are the topocentric equatorial coordinates, at the same time, the (optionally - refracted) alt-az coordinates are calculated, and are also contained within the returned - PositionVector. Note that Alt/Az is available in PositionVectors returned from calling - GetTopocentricPosition(). The accuracy of these calculations is typically dominated by the accuracy - of the attached ephemeris generator. - Ephemeris Generator
- By default, Kepler instances are attached for both Earth and Planet objects so it is - not necessary to create and attach these in order to get Kepler accuracy from this - component
- The ephemeris generator object used with NOVAS-COM must support a single - method GetPositionAndVelocity(tjd). This method must take a terrestrial Julian date (like the - NOVAS-COM methods) as its single parameter, and return an array of Double - containing the rectangular (x/y/z) heliocentric J2000 equatorial coordinates of position (AU) and velocity - (KM/sec.). In addition, it must support three read/write properties BodyType, Name, and Number, - which correspond to the Type, Name, and Number properties of Novas.Planet. - -
-
- - - Create a new instance of the Plant class - - This assigns default Kepler instances for the Earth and Planet objects so it is - not necessary to create and attach Kepler objects in order to get Kepler accuracy from this - component - - - - Planet delta-T - - The value of delta-T (TT - UT1) to use for reductions - Seconds - Setting this value is optional. If no value is set, an internal delta-T generator is used. - - - - Ephemeris object used to provide the position of the Earth. - - Earth ephemeris object - Earth ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - The Ephemeris object used to provide positions of solar system bodies. - - Body ephemeris object - Body ephemeris object - - Setting this is optional, if not set, the internal Kepler engine will be used. - - - - - Get an apparent position for given time - - Terrestrial Julian Date for the position - PositionVector for the apparent place. - - - - - Get an astrometric position for given time - - Terrestrial Julian Date for the position - PositionVector for the astrometric place. - - - - - Get an local position for given time - - Terrestrial Julian Date for the position - The observing site - PositionVector for the local place. - - - - - Get a topocentric position for given time - - Terrestrial Julian Date for the position - The observing site - Apply refraction correction - PositionVector for the topocentric place. - - - - - Get a virtual position for given time - - Terrestrial Julian Date for the position - PositionVector for the virtual place. - - - - - Planet name - - For unnumbered minor planets, (Type=nvMinorPlanet and Number=0), the packed designation - for the minor planet. For other types, this is not significant, but may be used to store - a name. - Name of planet - - - - - Planet number - - For major planets (Type = , a PlanetNumber value from 1 to 11. For minor planets - (Type = , the number of the minor planet or 0 for unnumbered minor planet. - Planet number - The major planet number is its number out from the sun starting with Mercury = 1, ending at Pluto = 9. Planet 10 gives - values for the Sun and planet 11 gives values for the Moon - - - - The type of solar system body - - The type of solar system body - Value from the BodyType enum - - - - - NOVAS-COM: PositionVector Class - - NOVAS-COM objects of class PositionVector contain vectors used for positions (earth, sites, - stars and planets) throughout NOVAS-COM. Of course, its properties include the x, y, and z - components of the position. Additional properties are right ascension and declination, distance, - and light time (applicable to star positions), and Alt/Az (available only in PositionVectors - returned by Star or Planet methods GetTopocentricPosition()). You can initialize a PositionVector - from a Star object (essentially an FK5 or HIP catalog entry) or a Site (lat/long/height). - PositionVector has methods that can adjust the coordinates for precession, aberration and - proper motion. Thus, a PositionVector object gives access to some of the lower-level NOVAS functions. - Note: The equatorial coordinate properties of this object are dependent variables, and thus are read-only. Changing any cartesian coordinate will cause the equatorial coordinates to be recalculated. - - - - - Create a new, uninitialised position vector - - - - - - Create a new position vector with supplied initial values - - Position vector x co-ordinate - Position vector y co-ordinate - Position vector z co-ordinate - Right ascension (hours) - Declination (degrees) - Distance to object - Light-time to object - Object azimuth - Object altitude - - - - - Create a new position vector with supplied initial values - - Position vector x co-ordinate - Position vector y co-ordinate - Position vector z co-ordinate - Right ascension (hours) - Declination (degrees) - Distance to object - Light-time to object - - - - - Adjust the position vector of an object for aberration of light - - The velocity vector of the observer - The algorithm includes relativistic terms - - - - The azimuth coordinate (degrees, + east) - - The azimuth coordinate - Degrees, + East - - - - - Declination coordinate - - Declination coordinate - Degrees - - - - - Distance/Radius coordinate - - Distance/Radius coordinate - AU - - - - - The elevation (altitude) coordinate (degrees, + up) - - The elevation (altitude) coordinate (degrees, + up) - (Degrees, + up - Elevation is available only in PositionVectors returned from calls to - Star.GetTopocentricPosition() and/or Planet.GetTopocentricPosition(). - When the position vector has not been - initialised from Star.GetTopoCentricPosition and Planet.GetTopocentricPosition - - - - Light time from body to origin, days. - - Light time from body to origin - Days - - - - - Adjust the position vector for precession of equinoxes between two given epochs - - The first epoch (Terrestrial Julian Date) - The second epoch (Terrestrial Julian Date) - The coordinates are referred to the mean equator and equinox of the two respective epochs. - - - - Adjust the position vector for proper motion (including foreshortening effects) - - The velocity vector of the object - The first epoch (Terrestrial Julian Date) - The second epoch (Terrestrial Julian Date) - True if successful or throws an exception. - - If the position vector x, y or z values has not been set - If the supplied velocity vector does not have valid x, y and z components - - - - RightAscension coordinate, hours - - RightAscension coordinate - Hours - - - - - Initialize the PositionVector from a Site object and Greenwich apparent sidereal time. - - The Site object from which to initialize - Greenwich Apparent Sidereal Time - True if successful or throws an exception - The GAST parameter must be for Greenwich, not local. The time is rotated through the - site longitude. See SetFromSiteJD() for an equivalent method that takes UTC Julian Date and - Delta-T (eliminating the need for calculating hyper-accurate GAST yourself). - - - - Initialize the PositionVector from a Site object using UTC Julian date - - The Site object from which to initialize - UTC Julian Date - True if successful or throws an exception - The Julian date must be UTC Julian date, not terrestrial. Calculations will use the internal delta-T tables and estimator to get - delta-T. - This overload is not available through COM, please use - "SetFromSiteJD(ByVal site As Site, ByVal ujd As Double, ByVal delta_t As Double)" - with delta_t set to 0.0 to achieve this effect. - - - - - Initialize the PositionVector from a Site object using UTC Julian date and Delta-T - - The Site object from which to initialize - UTC Julian Date - The value of Delta-T (TT - UT1) to use for reductions (seconds) - True if successful or throws an exception - The Julian date must be UTC Julian date, not terrestrial. - - - - Initialize the PositionVector from a Star object. - - The Star object from which to initialize - True if successful or throws an exception - - If Parallax, RightAScension or Declination is not available in the supplied star object. - - - - Position cartesian x component - - Cartesian x component - Cartesian x component - - - - - Position cartesian y component - - Cartesian y component - Cartesian y component - - - - - Position cartesian z component - - Cartesian z component - Cartesian z component - - - - - NOVAS-COM: Site Class - - NOVAS-COM objects of class Site contain the specifications for an observer's location on the Earth - ellipsoid. Properties are latitude, longitude, height above mean sea level, the ambient temperature - and the sea-level barmetric pressure. The latter two are used only for optional refraction corrections. - Latitude and longitude are (common) geodetic, not geocentric. - - - - Initialises a new site object - - - - - - Height above mean sea level - - Height above mean sea level - Meters - - - - - Geodetic latitude (degrees, + north) - - Geodetic latitude - Degrees, + north - - - - - Geodetic longitude (degrees, + east) - - Geodetic longitude - Degrees, + east - - - - - Barometric pressure (millibars) - - Barometric pressure - Millibars - - - - - Set all site properties in one method call - - The geodetic latitude (degrees, + north) - The geodetic longitude (degrees, +east) - Height above sea level (meters) - - - - - Ambient temperature (deg. Celsius) - - Ambient temperature - Degrees Celsius) - - - - - NOVAS-COM: Star Class - - NOVAS-COM objects of class Star contain the specifications for a star's catalog position in either FK5 or Hipparcos units (both must be J2000). Properties are right ascension and declination, proper motions, parallax, radial velocity, catalog type (FK5 or HIP), catalog number, optional ephemeris engine to use for barycenter calculations, and an optional value for delta-T. Unless you specifically set the DeltaT property, calculations performed by this class which require the value of delta-T (TT - UT1) rely on an internal function to estimate delta-T. -The high-level NOVAS astrometric functions are implemented as methods of Star: - GetTopocentricPosition(), GetLocalPosition(), GetApparentPosition(), GetVirtualPosition(), - and GetAstrometricPosition(). These methods operate on the properties of the Star, and produce - a PositionVector object. For example, to get the topocentric coordinates of a star, simply create - and initialize a Star, then call Star.GetTopocentricPosition(). The resulting vaPositionVector's - right ascension and declination properties are the topocentric equatorial coordinates, at the same - time, the (optionally refracted) alt-az coordinates are calculated, and are also contained within - the returned PositionVector. Note that Alt/Az is available in PositionVectors returned from calling - GetTopocentricPosition(). - - - - Initialise a new instance of the star class - - - - - - Three character catalog code for the star's data - - Three character catalog code for the star's data - Three character catalog code for the star's data - Typically "FK5" but may be "HIP". For information only. - - - - Mean catalog J2000 declination coordinate (degrees) - - Mean catalog J2000 declination coordinate - Degrees - - - - - The value of delta-T (TT - UT1) to use for reductions. - - The value of delta-T (TT - UT1) to use for reductions. - Seconds - If this property is not set, calculations will use an internal function to estimate delta-T. - - - - Ephemeris object used to provide the position of the Earth. - - Ephemeris object used to provide the position of the Earth. - Ephemeris object - If this value is not set, an internal Kepler object will be used to determine - Earth ephemeris - - - - Get an apparent position for a given time - - Terrestrial Julian Date for the position - PositionVector for the apparent place. - - - - - Get an astrometric position for a given time - - Terrestrial Julian Date for the position - PositionVector for the astrometric place. - - - - - Get a local position for a given site and time - - Terrestrial Julian Date for the position - A Site object representing the observing site - PositionVector for the local place. - - - - - Get a topocentric position for a given site and time - - Terrestrial Julian Date for the position - A Site object representing the observing site - True to apply atmospheric refraction corrections - PositionVector for the topocentric place. - - - - - Get a virtual position at a given time - - Terrestrial Julian Date for the position - PositionVector for the virtual place. - - - - - The catalog name of the star (50 char max) - - The catalog name of the star - Name (50 char max) - - - - - The catalog number of the star - - The catalog number of the star - The catalog number of the star - - - - - Catalog mean J2000 parallax (arcsec) - - Catalog mean J2000 parallax - Arc seconds - - - - - Catalog mean J2000 proper motion in declination (arcsec/century) - - Catalog mean J2000 proper motion in declination - Arc seconds per century - - - - - Catalog mean J2000 proper motion in right ascension (sec/century) - - Catalog mean J2000 proper motion in right ascension - Seconds per century - - - - - Catalog mean J2000 radial velocity (km/sec) - - Catalog mean J2000 radial velocity - Kilometers per second - - - - - Catalog mean J2000 right ascension coordinate (hours) - - Catalog mean J2000 right ascension coordinate - Hours - - - - - Initialize all star properties with one call - - Catalog mean right ascension (hours) - Catalog mean declination (degrees) - Catalog mean J2000 proper motion in right ascension (sec/century) - Catalog mean J2000 proper motion in declination (arcsec/century) - Catalog mean J2000 parallax (arcsec) - Catalog mean J2000 radial velocity (km/sec) - Assumes positions are FK5. If Parallax is set to zero, NOVAS-COM assumes the object - is on the "celestial sphere", which has a distance of 10 megaparsecs. - - - - Initialise all star properties in one call using Hipparcos data. Transforms to FK5 standard used by NOVAS. - - Catalog mean right ascension (hours) - Catalog mean declination (degrees) - Catalog mean J2000 proper motion in right ascension (sec/century) - Catalog mean J2000 proper motion in declination (arcsec/century) - Catalog mean J2000 parallax (arcsec) - Catalog mean J2000 radial velocity (km/sec) - Assumes positions are Hipparcos standard and transforms to FK5 standard used by NOVAS. - If Parallax is set to zero, NOVAS-COM assumes the object is on the "celestial sphere", - which has a distance of 10 megaparsecs. - - - - - NOVAS-COM: VelocityVector Class - - NOVAS-COM objects of class VelocityVector contain vectors used for velocities (earth, sites, - planets, and stars) throughout NOVAS-COM. Of course, its properties include the x, y, and z - components of the velocity. Additional properties are the velocity in equatorial coordinates of - right ascension dot, declination dot and radial velocity. You can initialize a PositionVector from - a Star object (essentially an FK5 or HIP catalog entry) or a Site (lat/long/height). For the star - object the proper motions, distance and radial velocity are used, for a site, the velocity is that - of the observer with respect to the Earth's center of mass. - - - - Creates a new velocity vector object - - - - - - Linear velocity along the declination direction (AU/day) - - Linear velocity along the declination direction - AU/day - This is not the proper motion (which is an angular rate and is dependent on the distance to the object). - - - - Linear velocity along the radial direction (AU/day) - - Linear velocity along the radial direction - AU/day - - - - - Linear velocity along the right ascension direction (AU/day) - - Linear velocity along the right ascension direction - AU/day - - - - - Initialize the VelocityVector from a Site object and Greenwich Apparent Sdereal Time. - - The Site object from which to initialize - Greenwich Apparent Sidereal Time - True if OK or throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The GAST parameter must be for Greenwich, not local. The time is rotated through - the site longitude. See SetFromSiteJD() for an equivalent method that takes UTC Julian - Date and optionally Delta-T (eliminating the need for calculating hyper-accurate GAST yourself). - - - - Initialize the VelocityVector from a Site object using UTC Julian Date - - The Site object from which to initialize - UTC Julian Date - True if OK otherwise throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The Julian date must be UTC Julian date, not terrestrial. This call will use - the internal tables and estimator to get delta-T. - This overload is not available through COM, please use - "SetFromSiteJD(ByVal site As Site, ByVal ujd As Double, ByVal delta_t As Double)" - with delta_t set to 0.0 to achieve this effect. - - - - - Initialize the VelocityVector from a Site object using UTC Julian Date and Delta-T - - The Site object from which to initialize - UTC Julian Date - The optional value of Delta-T (TT - UT1) to use for reductions (seconds) - True if OK otherwise throws an exception - The velocity vector is that of the observer with respect to the Earth's center - of mass. The Julian date must be UTC Julian date, not terrestrial. - - - - Initialize the VelocityVector from a Star object. - - The Star object from which to initialize - True if OK otherwise throws an exception - The proper motions, distance and radial velocity are used in the velocity calculation. - If any of: Parallax, RightAscension, Declination, - ProperMotionRA, ProperMotionDec or RadialVelocity are not available in the star object - - - - Cartesian x component of velocity (AU/day) - - Cartesian x component of velocity - AU/day - - - - - Cartesian y component of velocity (AU/day) - - Cartesian y component of velocity - AU/day - - - - - Cartesian z component of velocity (AU/day) - - Cartesian z component of velocity - AU/day - - - - - Interface to the NOVAS2 component - - Implemented by the NOVAS2COM component - - - - Computes the apparent place of a star - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the earth - Catalog entry structure containing J2000.0 catalog data with FK5-style units (defined in novas.h). - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK
- >0...Error code from function 'solarsystem'.
- -
- - - Computes the topocentric place of a star - - TT (or TDT) Julian date for topocentric place. - Structure containing the body designation for the Earth. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Catalog entry structure containing J2000.0 catalog data with FK5-style units. - Structure containing observer's location - OUT: Topocentric right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Topocentric declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- -
- - - Compute the apparent place of a planet or other solar system body. - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the solar system body - Structure containing the body designation for the Earth - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the topocentric place of a planet, given the location of the observer. - - TT (or TDT) Julian date for topocentric place. - structure containing the body designation for the solar system body - structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - structure containing observer's location - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the virtual place of a star - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the Earth. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'
- 
- - Computes the virtual place of a star at date 'tjd', given its - mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Computes the local place of a star - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - Computes the virtual place of a planet or other solar system body. - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the local place of a planet or other solar system body, given the location of the observer. - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the astrometric place of a star - - TT (or TDT) Julian date for astrometric place. - Pointer to structure containing the body designation for the Earth - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- 
- Computes the astrometric place of a star, given its mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Computes the astrometric place of a planet or other solar system body. - - TT (or TDT) Julian date for calculation. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Transform apparent equatorial coordinates to horizon coordinates - - TT (or TDT) Julian date. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Conventionally-defined x coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option - OUT: Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric azimuth (measured east from north) in degrees. - OUT: Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms apparent equatorial coordinates (right - ascension and declination) to horizon coordinates (zenith - distance and azimuth). It uses a method that properly accounts - for polar motion, which is significant at the sub-arcsecond - level. This function can also adjust coordinates for atmospheric - refraction. - - - - To convert Hipparcos data at epoch J1991.25 to epoch J2000.0 and FK5-style units. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0, with all members having FK5 catalog units. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. -
- 1. Hipparcos epoch and units:
-    Epoch: J1991.25
-    Right ascension (RA): degrees
-    Declination (Dec): degrees
-    Proper motion in RA * cos (Dec): milliarcseconds per year
-    Proper motion in Dec: milliarcseconds per year
-    Parallax: milliarcseconds
-    Radial velocity: kilometers per second (not in catalog)
- 
- 2. FK5 epoch and units:
-    Epoch: J2000.0
-    Right ascension: hours
-    Declination: degrees
-    Proper motion in RA: seconds of time per Julian century
-    Proper motion in Dec: arcseconds per Julian century
-    Parallax: arcseconds
-    Radial velocity: kilometers per second
-
-
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option
-    = 1 ... change epoch; same equator and equinox
-    = 2 ... change equator and equinox; same epoch
-    = 3 ... change equator and equinox and epoch
-
- TT Julian date, or year, of input catalog data. - An entry from the input catalog - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - OUT: The transformed catalog entry -
- 1. 'date_incat' and 'date_newcat' may be specified either as a 
-    Julian date (e.g., 2433282.5) or a Julian year and fraction 
-    (e.g., 1950.0).  Values less than 10000 are assumed to be years.
- 
- 2. option = 1 updates the star's data to account for the star's space motion between 
-               the first and second dates, within a fixed reference frame.
-    option = 2 applies a rotation of the reference frame corresponding to precession 
-               between the first and second dates, but leaves the star fixed in space.
-    option = 3 provides both transformations.
- 
- 3. This subroutine cannot be properly used to bring data from 
-    old (pre-FK5) star catalogs into the modern system, because old 
-    catalogs were compiled using a set of constants that are 
-    incompatible with the IAU (1976) system.
- 
- 4. This function uses TDB Julian dates internally, but no 
-    distinction between TDB and TT is necessary.
-
-
- - - Computes the Greenwich apparent sidereal time, at Julian date 'jd_high' + 'jd_low'. - - Julian date, integral part. - Julian date, fractional part. - Equation of the equinoxes (seconds of time). [Note: this quantity is computed by function 'earthtilt'.] - Greenwich apparent sidereal time, in hours. - - - - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of first epoch. - TDB Julian date of second epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of second epoch. - The coordinates are referred to the mean equator and equinox of the two respective epochs. - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'tjd'. - - TDB Julian date of the desired time - OUT: Mean obliquity of the ecliptic in degrees at 'tjd'. - OUT: True obliquity of the ecliptic in degrees at 'tjd'. - OUT: Equation of the equinoxes in seconds of time at 'tjd'. - OUT: Nutation in longitude in arcseconds at 'tjd'. - OUT: Nutation in obliquity in arcseconds at 'tjd'. - - - - - This function allows for the specification of celestial pole offsets for high-precision applications. - - Value of offset in delta psi (dpsi) in arcseconds. - Value of offset in delta epsilon (deps) in arcseconds. - These are added to the nutation parameters delta psi and delta epsilon. - 1. This function sets the values of global variables 'PSI_COR'and 'EPS_COR' declared at the top of file 'novas.c'. These global variables are used only in NOVAS function 'earthtilt'. - 2. This function, if used, should be called before any other NOVAS functions for a given date. Values of the pole offsets specified via a call to this function will be used until explicitly changed. - 3. Daily values of the offsets are published, for example, in IERS Bulletins A and B. - 4. This function is the "C" version of Fortran NOVAS routine "celpol". - - - - - Retrieves the position and velocity of a body from a fundamental ephemeris. - - TDB Julian date. - Structure containing the designation of the body of interest - Origin point (solar system barycentre or centre of mass of the Sun - OUT: Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at tjd; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0    ... Everything OK.
- 1    ... Invalid value of 'origin'.
- 2    ... Invalid value of 'type' in 'cel_obj'.
- 3    ... Unable to allocate memory.
- 10+n ... where n is the error code from 'solarsystem'.
- 20+n ... where n is the error code from 'readeph'.
- -
- - - Provides the position and velocity of the Earth - - TDB Julian date. - Body identification number. -
- Set 'body' = 0 or 'body' = 1 or 'body' = 10 for the Sun.
- Set 'body' = 2 or 'body' = 3 for the Earth.
-
- Required origin: solar system barycenter or center of mass of the Sun - OUT: Position vector of 'body' at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0...Everything OK.
- 1...Input Julian date ('tjd') out of range.
- 2...Invalid value of 'body'.
-
- Provides the position and velocity of the Earth at epoch 'tjd' by evaluating a closed-form theory without reference to an external file. This function can also provide the position and velocity of the Sun. -
- - - Converts an vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - OUT: Right ascension in hours. - OUT: Declination in degrees. -
- 0...Everything OK.
- 1...All vector components are zero; 'ra' and 'dec' are indeterminate.
- 2...Both vec[0] and vec[1] are zero, but vec[2] is nonzero; 'ra' is indeterminate.
-
- -
- - - Converts angular quanities for stars to vectors. - - Catalog entry structure containing J2000.0 catalog data with FK5-style units - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance - Position vector, equatorial rectangular coordinates (AU). - - - - - Obtains the barycentric and heliocentric positions and velocities of the Earth from the solar system ephemeris. - - TT (or TDT) Julian date. - Structure containing the body designation for the Earth. - OUT: TDB Julian date corresponding to 'tjd'. - OUT: Barycentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Barycentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. - OUT: Heliocentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Heliocentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - Computes the mean place of a star for J2000.0 - - TT (or TDT) Julian date of apparent place. - Pointer to structure containing the body designation for the Earth - Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: Mean right ascension J2000.0 in hours. - OUT: Mean declination J2000.0 in degrees. -
-   0...Everything OK.
-   1...Iterative process did not converge after 20 iterations.
- >10...Error from function 'app_star'.
- Computes the mean place of a star for J2000.0, given its apparent - place at date 'tjd'. Proper motion, parallax and radial velocity - are assumed to be zero. - -
- - - Transforms a vector from an Earth-fixed geographic system to a space-fixed system - - TT (or TDT) Julian date - Greenwich apparent sidereal time, in hours. - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular space-fixed system, referred to mean equator and equinox of J2000.0. - Transforms a vector from an Earth-fixed geographic system to a space-fixed system based on mean equator and equinox of J2000.0; applies rotations for wobble, spin, nutation, and precession. - - - - Transforms geocentric rectangular coordinates from rotating system to non-rotating system - - Local apparent sidereal time at reference meridian, in hours. - Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal reference meridian. - OUT: Vector in geocentric rectangular non-rotating system, referred to true equator and equinox of date. - Transforms geocentric rectangular coordinates from rotating system based on rotational equator and orthogonal reference meridian to non-rotating system based on true equator and equinox of date. - - - - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. - - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal Greenwich meridian - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. Transforms a vector from Earth-fixed geographic system to rotating system based on rotational equator and orthogonal Greenwich meridian through axis of rotation. - - - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Longitude, latitude and height of the observer (in a SiteInfoStruct) - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU/Day. - - - - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - OUT: Position vector at second epoch. - - - - - Moves the origin of coordinates from the barycenter of the solar system to the center of mass of the Earth - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU. - OUT: Position vector, referred to origin at center of mass of the Earth, components in AU. - OUT: Light time from body to Earth in days. - This corrects for parallax. - - - - Corrects position vector for the deflection of light in the gravitational field of the Sun. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Position vector of center of mass of the Earth, referred to origin at center of mass of the Sun, components in AU. - Position vector, referred to origin at center of mass of the Earth, corrected for gravitational deflection, components in AU. - 0...Everything OK. - This function is valid for bodies within the solar system as well as for stars. - - - - Corrects position vector for aberration of light. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from body to Earth in days. - OUT: Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - 0...Everything OK. - Algorithm includes relativistic terms. - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB julian date of epoch. - Flag determining 'direction' of transformation;
-    fn  = 0 transformation applied, mean to true.
-    fn != 0 inverse transformation applied, true to mean.
- Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to true equator and equinox of epoch. - 0...Everything OK. - Inverse transformation may be applied by setting flag 'fn'. -
- - - Provides fast evaluation of the nutation components according to the 1980 IAU Theory of Nutation. - - TDB time in Julian centuries since J2000.0 - OUT: Nutation in longitude in arcseconds. - OUT: Nutation in obliquity in arcseconds. - 0...Everything OK. - - - - - To compute the fundamental arguments. - - TDB time in Julian centuries since J2000.0 - OUT: FundamentalArgsStruct containing:
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (L - omega; L = mean longitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = omega (mean longitude of the Moon's ascending node)
- -
- - - Converts TDB to TT or TDT - - TDB Julian date. - OUT: TT (or TDT) Julian date. - OUT: Difference tdbjd-tdtjd, in seconds. - Computes the terrestrial time (TT) or terrestrial dynamical time (TDT) Julian date corresponding to a barycentric dynamical time (TDB) Julian date. - - - - Sets up a structure of type 'body' - defining a celestial object- based on the input parameters. - - Type of body - Body number - Name of the body. - OUT: Structure containg the body definition -
- = 0 ... everything OK
- = 1 ... invalid value of 'type'
- = 2 ... 'number' out of range
-
- -
- - - To create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Three-character catalog identifier (e.g. HIP = Hipparcos, FK5 = FK5). This identifier also specifies the reference system and units of the data; i.e. they are the same as the specified catalog. - Object name (50 characters maximum). - Object number in the catalog. - Right ascension of the object. - Declination of the object. - Proper motion in right ascension. - Proper motion in declination. - Parallax. - Radial velocity. - OUT: Structure containing the input data - - - - - Computes atmospheric refraction in zenith distance. - - structure containing observer's location - refraction option - bserved zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. - - - - This function will compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number. - Day number - Time in hours - OUT: Julian date. - - - - - Compute a date on the Gregorian calendar given the Julian date. - - Julian date. - OUT: Year number - OUT: Month number. - OUT: Day number - OUT: Time in hours - - - - - Compute equatorial spherical coordinates of Sun referred to the mean equator and equinox of date. - - Julian date on TDT or ET time scale. - OUT: Right ascension referred to mean equator and equinox of date (hours). - OUT: Declination referred to mean equator and equinox of date (degrees). - OUT: Geocentric distance (AU). - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - Interface to the NOVAS3 component - - Implemented by the NOVAS3 component - Note: This interface is now deprecated, please use INOVAS31 instead. - - - - - Get position and velocity of target with respect to the centre object. - - Two-element array containing the Julian date, which may be split any way (although the first - element is usually the "integer" part, and the second element is the "fractional" part). Julian date is in the - TDB or "T_eph" time scale. - Target object - Centre object - Position vector array of target relative to center, measured in AU. - Velocity vector array of target relative to center, measured in AU/day. -
- 0   ...everything OK.
- 1,2 ...error returned from State.
-
- This function accesses the JPL planetary ephemeris to give the position and velocity of the target - object with respect to the center object. -
- - - Read object ephemeris - - The number of the asteroid for which the position in desired. - The name of the asteroid. - The Julian date on which to find the position and velocity. - Error code; always set equal to 9 (see note below). - 6-element array of double cotaining position and velocity vector values, with all elements set to zero. - This is a dummy version of function 'ReadEph'. It serves as a stub for the "real" 'ReadEph' - (part of the USNO/AE98 minor planet ephemerides) when NOVAS-C is used without the minor planet ephemerides. - - This dummy function is not intended to be called. It merely serves as a stub for the "real" 'ReadEph' - when NOVAS-C is used without the minor planet ephemerides. If this function is called, an error of 9 will be returned. - - - - - - Interface between the JPL direct-access solar system ephemerides and NOVAS-C. - - Julian date of the desired time, on the TDB time scale. - Body identification number for the solar system object of interest; - Mercury = 1, ..., Pluto= 9, Sun= 10, Moon = 11. - Origin code; solar system barycenter= 0, center of mass of the Sun = 1, center of Earth = 2. - Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of 'body' at tjd; equatorial rectangular system referred to the ICRS. - Always returns 0 - - - - - Read and interpolate the JPL planetary ephemeris file. - - 2-element Julian date (TDB) at which interpolation is wanted. Any combination of jed[0]+jed[1] which falls within the time span on the file is a permissible epoch. See Note 1 below. - The requested body to get data for from the ephemeris file. - The barycentric position vector array of the requested object, in AU. (If target object is the Moon, then the vector is geocentric.) - The barycentric velocity vector array of the requested object, in AU/Day. - -
- 0 ...everything OK
- 1 ...error reading ephemeris file
- 2 ...epoch out of range.
- 
- - The target number designation of the astronomical bodies is: -
-         = 0: Mercury,               1: Venus, 
-         = 2: Earth-Moon barycenter, 3: Mars, 
-         = 4: Jupiter,               5: Saturn, 
-         = 6: Uranus,                7: Neptune, 
-         = 8: Pluto,                 9: geocentric Moon, 
-         =10: Sun.
- 
- - NOTE 1. For ease in programming, the user may put the entire epoch in jed[0] and set jed[1] = 0. - For maximum interpolation accuracy, set jed[0] = the most recent midnight at or before interpolation epoch, - and set jed[1] = fractional part of a day elapsed between jed[0] and epoch. As an alternative, it may prove - convenient to set jed[0] = some fixed epoch, such as start of the integration and jed[1] = elapsed interval - between then and epoch. - -
-
- - - Corrects position vector for aberration of light. Algorithm includes relativistic terms. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from object to Earth in days. - Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - If 'lighttime' = 0 on input, this function will compute it. - - - - Compute the apparent place of a planet or other solar system body. - - TT Julian date for apparent place. - Pointer to structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the apparent place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for apparent place. - Catalog entry structure containing catalog data forthe object in the ICRS - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Apparent declination in degrees, referred to true equator and equinox of date 'JdTt'. - -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Compute the astrometric place of a planet or other solar system body. - - TT Julian date for astrometric place. - structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). - True distance from Earth to planet in AU. - -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the astrometric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for astrometric place. - Catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Move the origin of coordinates from the barycenter of the solar system to the observer (or the geocenter); i.e., this function accounts for parallax (annual+geocentric or justannual). - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Position vector, referred to origin at center of mass of the Earth, components in AU. - Light time from object to Earth in days. - - - - - This function will compute a date on the Gregorian calendar given the Julian date. - - Julian date. - Year - Month number - day number - Fractional hour of the day - - - - - This function allows for the specification of celestial pole offsets for high-precision applications. Each set of offsets is a correction to the modeled position of the pole for a specific date, derived from observations and published by the IERS. - - TDB or TT Julian date for pole offsets. - Type of pole offset. 1 for corrections to angular coordinates of modeled pole referred to mean ecliptic of date, that is, delta-delta-psi and delta-delta-epsilon. 2 for corrections to components of modeled pole unit vector referred to GCRS axes, that is, dx and dy. - Value of celestial pole offset in first coordinate, (delta-delta-psi or dx) in milliarcseconds. - Value of celestial pole offset in second coordinate, (delta-delta-epsilon or dy) in milliarcseconds. -
- 0 ... Everything OK
- 1 ... Invalid value of 'Type'.
- 
- -
- - - Calaculate an array of CIO RA values around a given date - - TDB Julian date. - Number of Julian dates and right ascension values requested (not less than 2 or more than 20). - An arraylist of RaOfCIO structures containing a time series of the right ascension of the - Celestial Intermediate Origin (CIO) with respect to the GCRS. -
- 0 ... everything OK
- 1 ... error opening the 'cio_ra.bin' file
- 2 ... 'JdTdb' not in the range of the CIO file; 
- 3 ... 'NPts' out of range
- 4 ... unable to allocate memory for the internal 't' array; 
- 5 ... unable to allocate memory for the internal 'ra' array; 
- 6 ... 'JdTdb' is too close to either end of the CIO file; unable to put 'NPts' data points into the output object.
- 
- - - Given an input TDB Julian date and the number of data points desired, this function returns a set of - Julian dates and corresponding values of the GCRS right ascension of the celestial intermediate origin (CIO). - The range of dates is centered (at least approximately) on the requested date. The function obtains - the data from an external data file. - How to create and retrieve values from the arraylist - - Dim CioList As New ArrayList, Nov3 As New ASCOM.Astrometry.NOVAS3 - - rc = Nov3.CioArray(2455251.5, 20, CioList) ' Get 20 values around date 00:00:00 February 24th 2010 - MsgBox("Nov3 RC= " rc) - - For Each CioA As ASCOM.Astrometry.RAOfCio In CioList - MsgBox("CIO Array " CioA.JdTdb " " CioA.RACio) - Next - - - -
- - - Compute the orthonormal basis vectors of the celestial intermediate system. - - TDB Julian date of epoch. - Right ascension of the CIO at epoch (hours). - Reference system in which right ascension is given. 1 ... GCRS; 2 ... True equator and equinox of date. - Accuracy - Unit vector toward the CIO, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward the y-direction, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward north celestial pole (CIP), equatorial rectangular coordinates, referred to the GCRS. -
- 0 ... everything OK
- 1 ... invalid value of input variable 'RefSys'.
- 
- - To compute the orthonormal basis vectors, with respect to the GCRS (geocentric ICRS), of the celestial - intermediate system defined by the celestial intermediate pole (CIP) (in the z direction) and - the celestial intermediate origin (CIO) (in the x direction). A TDB Julian date and the - right ascension of the CIO at that date is required as input. The right ascension of the CIO - can be with respect to either the GCRS origin or the true equinox of date -- different algorithms - are used in the two cases. -
- - - Returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension - - TDB Julian date. - Selection for accuracy - Right ascension of the CIO, in hours. - Reference system in which right ascension is given -
-    0 ... everything OK
-    1 ... unable to allocate memory for the 'cio' array
- > 10 ... 10 + the error code from function 'CioArray'.
- 
- This function returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension with respect to either the GCRS (geocentric ICRS) origin or the true equinox of date. The CIO is always located on the true equator (= intermediate equator) of date. -
- - - Computes the true right ascension of the celestial intermediate origin (CIO) at a given TT Julian date. This is -(equation of the origins). - - TT Julian date - Selection for accuracy - Right ascension of the CIO, with respect to the true equinox of date, in hours (+ or -). - -
-   0  ... everything OK
-   1  ... invalid value of 'Accuracy'
- > 10 ... 10 + the error code from function 'CioLocation'
- > 20 ... 20 + the error code from function 'CioBasis'.
- 
- -
- - - Returns the difference in light-time, for a star, between the barycenter of the solar system and the observer (or the geocenter). - - Position vector of star, with respect to origin at solar system barycenter. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Difference in light time, in the sense star to barycenter minus star to earth, in days. - - Alternatively, this function returns the light-time from the observer (or the geocenter) to a point on a - light ray that is closest to a specific solar system body. For this purpose, 'Pos1' is the position - vector toward observed object, with respect to origin at observer (or the geocenter); 'PosObs' is - the position vector of solar system body, with respect to origin at observer (or the geocenter), - components in AU; and the returned value is the light time to point on line defined by 'Pos1' - that is closest to solar system body (positive if light passes body before hitting observer, i.e., if - 'Pos1' is within 90 degrees of 'PosObs'). - - - - - Converts an ecliptic position vector to an equatorial position vector. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system selection. 0 ... mean equator and equinox of date; 1 ... true equator and equinox of date; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified ecliptic and equinox of date. If 'CoordSys' = 2, 'pos1' must be on mean ecliptic and equinox of J2000.0; see Note 1 below. - Position vector, referred to specified equator and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert an ecliptic vector (mean ecliptic and equinox of J2000.0 only) to an ICRS vector, - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the output from this case, all vectors are assumed to be with respect to a dynamical system. - -
- - - Compute the "complementary terms" of the equation of the equinoxes consistent with IAU 2000 resolutions. - - High-order part of TT Julian date. - Low-order part of TT Julian date. - Selection for accuracy - Complementary terms, in radians. - - Series from IERS Conventions (2003), Chapter 5, Table 5.2C, with some adjustments to coefficient values - copied from IERS function 'eect2000', which has a more complete series. - - - - - Retrieves the position and velocity of a solar system body from a fundamental ephemeris. - - TDB Julian date split into two parts, where the sum jd[0] + jd[1] is the TDB Julian date. - Structure containing the designation of the body of interest - Origin code; solar system barycenter = 0, center of mass of the Sun = 1. - Slection for accuracy - Position vector of the body at 'Jd'; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of the body at 'Jd'; equatorial rectangular system referred to the mean equator and equinox of the ICRS, in AU/Day. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Origin'
-    2 ... Invalid value of 'Type' in 'CelObj'; 
-    3 ... Unable to allocate memory
- 10+n ... where n is the error code from 'SolarSystem'; 
- 20+n ... where n is the error code from 'ReadEph'.
- 
- It is recommended that the input structure 'cel_obj' be created using function 'MakeObject' in file novas.c. -
- - - To convert right ascension and declination to ecliptic longitude and latitude. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system: 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Right ascension in hours, referred to specified equator and equinox of date. - Declination in degrees, referred to specified equator and equinox of date. - Ecliptic longitude in degrees, referred to specified ecliptic and equinox of date. - Ecliptic latitude in degrees, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert ICRS RA and dec to ecliptic coordinates (mean ecliptic and equinox of J2000.0), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the input to this case, all input coordinates are dynamical. - -
- - - Converts an equatorial position vector to an ecliptic position vector. - - TT Julian date of equator, equinox, and ecliptic used for - Coordinate system selection. 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified equator and equinox of date. - Position vector, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- To convert an ICRS vector to an ecliptic vector (mean ecliptic and equinox of J2000.0 only), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. Except for - the input to this case, all vectors are assumed to be with respect to a dynamical system. -
- - - Converts ICRS right ascension and declination to galactic longitude and latitude. - - ICRS right ascension in hours. - ICRS declination in degrees. - Galactic longitude in degrees. - Galactic latitude in degrees. - - - - - Transforms topocentric right ascension and declination to zenith distance and azimuth. - - UT1 Julian date. - Difference TT-UT1 at 'jd_ut1', in seconds. - Selection for accuracy - onventionally-defined x coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option. 0 ... no refraction; 1 ... include refraction, using 'standard' atmospheric conditions; - 2 ... include refraction, using atmospheric parametersinput in the 'Location' structure. - Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - Topocentric azimuth (measured east from north) in degrees. - Topocentric right ascension of object of interest, in hours, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - Topocentric declination of object of interest, in degrees, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms topocentric right ascension and declination to zenith distance and azimuth. - It uses a method that properly accounts for polar motion, which is significant at the sub-arcsecond level. - This function can also adjust coordinates for atmospheric refraction. - - - - Returns the value of the Earth Rotation Angle (theta) for a given UT1 Julian date. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - The Earth Rotation Angle (theta) in degrees. - The expression used is taken from the note to IAU Resolution B1.8 of 2000. 1. The algorithm used - here is equivalent to the canonical theta = 0.7790572732640 + 1.00273781191135448 * t, where t is the time - in days from J2000 (t = JdHigh + JdLow - T0), but it avoids many two-PI 'wraps' that - decrease precision (adopted from SOFA Fortran routine iau_era00; see also expression at top - of page 35 of IERS Conventions (1996)). - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'JdTdb'. - - TDB Julian Date. - Selection for accuracy - Mean obliquity of the ecliptic in degrees at 'JdTdb'. - True obliquity of the ecliptic in degrees at 'JdTdb'. - Equation of the equinoxes in seconds of time at 'JdTdb'. - Nutation in longitude in arcseconds at 'JdTdb'. - Nutation in obliquity in arcseconds at 'JdTdb'. - Values of the celestial pole offsets 'PSI_COR' and 'EPS_COR' are set using function 'cel_pole', - if desired. See the prolog of 'cel_pole' for details. - - - - To transform a vector from the dynamical reference system to the International Celestial Reference System (ICRS), or vice versa. - - Position vector, equatorial rectangular coordinates. - Set 'direction' 0 for dynamical to ICRS transformation. Set 'direction' =]]> 0 for - ICRS to dynamical transformation. - Position vector, equatorial rectangular coordinates. - - - - - To compute the fundamental arguments (mean elements) of the Sun and Moon. - - TDB time in Julian centuries since J2000.0 - Double array of fundamental arguments - - Fundamental arguments, in radians: -
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (mean argument of the latitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = a[4] (mean longitude of the Moon's ascending node);
-                from Simon section 3.4(b.3),
-                precession = 5028.8200 arcsec/cy)
- 
-
-
- - - Converts GCRS right ascension and declination to coordinates with respect to the equator of date (mean or true). - - TT Julian date of equator to be used for output coordinates. - Coordinate system selection for output coordinates.; 0 ... mean equator and - equinox of date; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date - Selection for accuracy - GCRS right ascension in hours. - GCRS declination in degrees. - Right ascension in hours, referred to specified equator and right ascension origin of date. - Declination in degrees, referred to specified equator of date. - -
-    0 ... everything OK
- >  0 ... error from function 'Vector2RaDec'' 
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
>
- For coordinates with respect to the true equator of date, the origin of right ascension can be either the true equinox or the celestial intermediate origin (CIO). - This function only supports the CIO-based method. -
- - - This function computes the geocentric position and velocity of an observer on - the surface of the earth or on a near-earth spacecraft. - TT Julian date. - Value of Delta T (= TT - UT1) at 'JdTt'. - Selection for accuracy - Data specifying the location of the observer - Position vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU. - Velocity vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU/day. - -
- 0 ... everything OK
- 1 ... invalid value of 'Accuracy'.
- 
- The final vectors are expressed in the GCRS. -
- - - Computes the total gravitational deflection of light for the observed object due to the major gravitating bodies in the solar system. - - TDB Julian date of observation. - Code for location of observer, determining whether the gravitational deflection due to the earth itself is applied. - Selection for accuracy - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar - system barycenter, referred to ICRS axes, components in AU. - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, corrected for gravitational deflection, components in AU. -
-    0 ... Everything OK
-  30 ... Error from function 'Ephemeris'; 
- > 30 ... Error from function 'MakeObject'.
- 
- This function valid for an observed body within the solar system as well as for a star. - - If 'Accuracy' is set to zero (full accuracy), three bodies (Sun, Jupiter, and Saturn) are - used in the calculation. If the reduced-accuracy option is set, only the Sun is used in the - calculation. In both cases, if the observer is not at the geocenter, the deflection due to the Earth is included. - - -
- - - Corrects position vector for the deflection of light in the gravitational field of an arbitrary body. - - Position vector of observed object, with respect to origin at observer - (or the geocenter), components in AU. - Position vector of observer (or the geocenter), with respect to origin at - solar system barycenter, components in AU. - Position vector of gravitating body, with respect to origin at solar system - barycenter, components in AU. - Reciprocal mass of gravitating body in solar mass units, that is, - Sun mass / body mass. - Position vector of observed object, with respect to origin at observer - (or the geocenter), corrected for gravitational deflection, components in AU. - This function valid for an observed body within the solar system as well as for a star. - - - - Compute the intermediate right ascension of the equinox at the input Julian date - - TDB Julian date. - Equinox selection flag: mean pr true - Selection for accuracy - Intermediate right ascension of the equinox, in hours (+ or -). If 'equinox' = 1 - (i.e true equinox), then the returned value is the equation of the origins. - - - - - Compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number - Day number - Fractional hour of the day - Computed Julian date. - This function makes no checks for a valid input calendar date. The input calendar date - must be Gregorian. The input time value can be based on any UT-like time scale (UTC, UT1, TT, etc.) - - output Julian date will have the same basis. - - - - Computes the geocentric position of a solar system body, as antedated for light-time. - - TDB Julian date of observation. - Structure containing the designation for thesolar system body - Position vector of observer (or the geocenter), with respect to origin - at solar system barycenter, referred to ICRS axes, components in AU. - First approximation to light-time, in days (can be set to 0.0 if unknown) - Selection for accuracy - Position vector of body, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Final light-time, in days. -
-    0 ... everything OK
-    1 ... algorithm failed to converge after 10 iterations
- ]]> 10 ... error is 10 + error from function 'SolarSystem'.
- 
- -
- - - Determines the angle of an object above or below the Earth's limb (horizon). - - Position vector of observed object, with respect to origin at - geocenter, components in AU. - Position vector of observer, with respect to origin at geocenter, - components in AU. - Angle of observed object above (+) or below (-) limb in degrees. - Nadir angle of observed object as a fraction of apparent radius of limb: 1.0 ... - below the limb; = 1.0 ... on the limb; ]]> 1.0 ... above the limb - The geometric limb is computed, assuming the Earth to be an airless sphere (no - refraction or oblateness is included). The observer can be on or above the Earth. - For an observer on the surface of the Earth, this function returns the approximate unrefracted - altitude. - - - - Computes the local place of a solar system body. - - TT Julian date for local place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Specifies accuracy level - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. - True distance from Earth to planet in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'; 
- ]]> 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the local place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for local place. delta_t (double) - Difference TT-UT1 at 'JdTt', in seconds of time. - catalog entry structure containing catalog data for the object in the ICRS - Structure specifying the position of the observer - Specifies accuracy level. - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Object name (50 characters maximum). - Three-character catalog identifier (e.g. HIP = Hipparcos, TY2 = Tycho-2) - Object number in the catalog. - Right ascension of the object (hours). - Declination of the object (degrees). - Proper motion in right ascension (milliarcseconds/year). - Proper motion in declination (milliarcseconds/year). - Parallax (milliarcseconds). - Radial velocity (kilometers/second). - CatEntry3 structure containing the input data - - - - - Makes a structure of type 'InSpace' - specifying the position and velocity of an observer situated - on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric velocity vector (x_dot, y_dot, z_dot) in km/s. - InSpace structure containing the position and velocity of an observer situated - on a near-Earth spacecraft - - - - - Makes a structure of type 'object' - specifying a celestial object - based on the input parameters. - - Type of object: 0 ... major planet, Sun, or Moon; 1 ... minor planet; - 2 ... object located outside the solar system (e.g. star, galaxy, nebula, etc.) - Body number: For 'Type' = 0: Mercury = 1,...,Pluto = 9, Sun = 10, Moon = 11; - For 'Type' = 1: minor planet numberFor 'Type' = 2: set to 0 (zero) - Name of the object (50 characters maximum). - Structure containing basic astrometric data for any celestial object - located outside the solar system; the catalog data for a star - Structure containing the object definition -
- 0 ... everything OK
- 1 ... invalid value of 'Type'
- 2 ... 'Number' out of range
- 
- -
- - - Makes a structure of type 'observer' - specifying the location of the observer. - - Integer code specifying location of observer: 0: observer at geocenter; - 1: observer on surface of earth; 2: observer on near-earth spacecraft - Structure containing data for an observer's location on the surface - of the Earth; used when 'Where' = 1 - Structure containing an observer's location on a near-Earth spacecraft; - used when 'Where' = 2 - Structure specifying the location of the observer -
- 0 ... everything OK
- 1 ... input value of 'Where' is out-of-range.
- 
- -
- - - Makes a structure of type 'observer' specifying an observer at the geocenter. - - Structure specifying the location of the observer at the geocenter - - - - - Makes a structure of type 'observer' specifying the position and velocity of an observer - situated on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric position vector (x, y, z) in km. - Structure containing the position and velocity of an observer - situated on a near-Earth spacecraft - Both input vectors are with respect to true equator and equinox of date. - - - - Makes a structure of type 'observer' specifying the location of and weather for an observer - on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) longitude in degrees; east positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an observer on - the surface of the Earth - - - - - Makes a structure of type 'on_surface' - specifying the location of and weather for an - observer on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) latitude in degrees; north positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an - observer on the surface of the Earth. - - - - - Compute the mean obliquity of the ecliptic. - - TDB Julian Date. - Mean obliquity of the ecliptic in arcseconds. - - - - - Computes the ICRS position of a star, given its apparent place at date 'JdTt'. - Proper motion, parallax and radial velocity are assumed to be zero. - - TT Julian date of apparent place. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - Specifies accuracy level - ICRS right ascension in hours. - ICRS declination in degrees. -
-    0 ... Everything OK
-    1 ... Iterative process did not converge after 30 iterations; 
- > 10 ... Error from function 'Vector2RaDec'
- > 20 ... Error from function 'AppStar'.
- 
- -
- - - Normalize angle into the range 0 angle (2 * pi). - - Input angle (radians). - The input angle, normalized as described above (radians). - - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB Julian date of epoch. - Flag determining 'direction' of transformation; direction = 0 - transformation applied, mean to true; direction != 0 inverse transformation applied, true to mean. - Selection for accuracy - Position vector, geocentric equatorial rectangular coordinates, referred to - mean equator and equinox of epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to - true equator and equinox of epoch. - Inverse transformation may be applied by setting flag 'direction' - - - - Returns the values for nutation in longitude and nutation in obliquity for a given TDB Julian date. - - TDB time in Julian centuries since J2000.0 - Selection for accuracy - Nutation in longitude in arcseconds. - Nutation in obliquity in arcseconds. - The nutation model selected depends upon the input value of 'Accuracy'. See notes below for important details. - - This function selects the nutation model depending first upon the input value of 'Accuracy'. - If 'Accuracy' = 0 (full accuracy), the IAU 2000A nutation model is used. If 'Accuracy' = 1 - a specially truncated (and therefore faster) version of IAU 2000A, called 'NU2000K' is used. - - - - - - Computes the apparent direction of a star or solar system body at a specified time - and in a specified coordinate system. - - TT Julian date for place. - Specifies the celestial object of interest - Specifies the location of the observer - Difference TT-UT1 at 'JdTt', in seconds of time. - Code specifying coordinate system of the output position. 0 ... GCRS or - "local GCRS"; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date; - 3 ... astrometric coordinates, i.e., without light deflection or aberration. - Selection for accuracy - Structure specifying object's place on the sky at time 'JdTt', - with respect to the specified output coordinate system - -
- = 0         ... No problems.
- = 1         ... invalid value of 'CoordSys'
- = 2         ... invalid value of 'Accuracy'
- = 3         ... Earth is the observed object, and the observer is either at the geocenter or on the Earth's surface (not permitted)
- > 10,  40  ... 10 + error from function 'Ephemeris'
- > 40,  50  ... 40 + error from function 'GeoPosVel'
- > 50,  70  ... 50 + error from function 'LightTime'
- > 70,  80  ... 70 + error from function 'GravDef'
- > 80,  90  ... 80 + error from function 'CioLocation'
- > 90,  100 ... 90 + error from function 'CioBasis'
- 
-
- Values of 'location->where' and 'CoordSys' dictate the various standard kinds of place: -
-     Location->Where = 0 and CoordSys = 1: apparent place
-     Location->Where = 1 and CoordSys = 1: topocentric place
-     Location->Where = 0 and CoordSys = 0: virtual place
-     Location->Where = 1 and CoordSys = 0: local place
-     Location->Where = 0 and CoordSys = 3: astrometric place
-     Location->Where = 1 and CoordSys = 3: topocentric astrometric place
- 
- Input value of 'DeltaT' is used only when 'Location->Where' equals 1 or 2 (observer is - on surface of Earth or in a near-Earth satellite). - - -
- - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of first epoch. - TDB Julian date of second epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of second epoch. -
- 0 ... everything OK
- 1 ... Precession not to or from J2000.0; 'JdTdb1' or 'JdTdb2' not 2451545.0.
- 
- One of the two epochs must be J2000.0. The coordinates are referred to the mean dynamical equator and equinox of the two respective epochs. -
- - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - Position vector at second epoch. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance in AU - Position vector, equatorial rectangular coordinates (AU). - - - - - Predicts the radial velocity of the observed object as it would be measured by spectroscopic means. - - Specifies the celestial object of interest - Geometric position vector of object with respect to observer, corrected for light-time, in AU. - Velocity vector of object with respect to solar system barycenter, in AU/day. - Velocity vector of observer with respect to solar system barycenter, in AU/day. - Distance from observer to geocenter, in AU. - Distance from observer to Sun, in AU. - Distance from object to Sun, in AU. - The observed radial velocity measure times the speed of light, in kilometers/second. - Radial velocity is here defined as the radial velocity measure (z) times the speed of light. - For a solar system body, it applies to a fictitious emitter at the center of the observed object, - assumed massless (no gravitational red shift), and does not in general apply to reflected light. - For stars, it includes all effects, such as gravitational red shift, contained in the catalog - barycentric radial velocity measure, a scalar derived from spectroscopy. Nearby stars with a known - kinematic velocity vector (obtained independently of spectroscopy) can be treated like - solar system objects. - - - - Computes atmospheric refraction in zenith distance. - - Structure containing observer's location. - 1 ... Use 'standard' atmospheric conditions; 2 ... Use atmospheric - parameters input in the 'Location' structure. - Observed zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. This function - can be used for planning observations or telescope pointing, but should not be used for the - reduction of precise observations. - - - - Computes the Greenwich apparent sidereal time, at Julian date 'JdHigh' + 'JdLow'. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Difference TT-UT1 at 'JdHigh'+'JdLow', in seconds of time. - 0 ... compute Greenwich mean sidereal time; 1 ... compute Greenwich apparent sidereal time - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - Greenwich apparent sidereal time, in hours. -
-          0 ... everything OK
-          1 ... invalid value of 'Accuracy'
-          2 ... invalid value of 'Method'
- > 10,  30 ... 10 + error from function 'CioRai'
- 
- The Julian date may be split at any point, but for highest precision, set 'JdHigh' - to be the integral part of the Julian date, and set 'JdLow' to be the fractional part. -
- - - Transforms a vector from one coordinate system to another with same origin and axes rotated about the z-axis. - - Angle of coordinate system rotation, positive counterclockwise when viewed from +z, in degrees. - Position vector. - Position vector expressed in new coordinate system rotated about z by 'angle'. - - - - - Converts angular quantities for stars to vectors. - - Catalog entry structure containing ICRS catalog data - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Computes the Terrestrial Time (TT) or Terrestrial Dynamical Time (TDT) Julian date corresponding - to a Barycentric Dynamical Time (TDB) Julian date. - - TDB Julian date. - TT Julian date. - Difference 'tdb_jd'-'tt_jd', in seconds. - Expression used in this function is a truncated form of a longer and more precise - series given in: Explanatory Supplement to the Astronomical Almanac, pp. 42-44 and p. 316. - The result is good to about 10 microseconds. - - - - This function rotates a vector from the terrestrial to the celestial system. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, referred to ITRF - axes (terrestrial system) in the normal case where 'option' = 0. - Position vector, geocentric equatorial rectangular coordinates, referred to GCRS - axes (celestial system) or with respect to the equator and equinox of date, depending on 'Option'. -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- 'x' = 'y' = 0 means no polar motion transformation. - - The 'option' flag only works for the equinox-based method. - -
- - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Structure containing observer's location - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial - rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular - coordinates, referred to true equator and equinox of date, components in AU/day. - - If reference meridian is Greenwich and st=0, 'pos' is effectively referred to equator and Greenwich. - This function ignores polar motion, unless the observer's longitude and latitude have been - corrected for it, and variation in the length of day (angular velocity of earth). - The true equator and equinox of date do not form an inertial system. Therefore, with respect - to an inertial system, the very small velocity component (several meters/day) due to the precession - and nutation of the Earth's axis is not accounted for here. - - - - - Computes the topocentric place of a solar system body. - - TT Julian date for topocentric place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Selection for accuracy - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'Place'.
-
- -
- - - Computes the topocentric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for topocentric place. - Difference TT-UT1 at 'JdTt', in seconds of time. - Catalog entry structure containing catalog data for the object in the ICRS - Specifies the position of the observer - Code specifying the relative accuracy of the output position. - Topocentric right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Topocentric declination in degrees, referred to true equator and equinox of date 'JdTt'. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'.
- 
- -
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option - TT Julian date, or year, of input catalog data. - An entry from the input catalog, with units as given in the struct definition - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - The transformed catalog entry, with units as given in the struct definition - -
- = 0 ... Everything OK.
- = 1 ... Invalid value of an input date for option 2 or 3 (see Note 1 below).
- 
- Also used to rotate catalog quantities on the dynamical equator and equinox of J2000.0 to the ICRS or vice versa. - 1. 'DateInCat' and 'DateNewCat' may be specified either as a Julian date (e.g., 2433282.5) or - a Julian year and fraction (e.g., 1950.0). Values less than 10000 are assumed to be years. - For 'TransformOption' = 2 or 'TransformOption' = 3, either 'DateInCat' or 'DateNewCat' must be 2451545.0 or - 2000.0 (J2000.0). For 'TransformOption' = 4 and 'TransformOption' = 5, 'DateInCat' and 'DateNewCat' are ignored. - 2. 'TransformOption' = 1 updates the star's data to account for the star's space motion between the first - and second dates, within a fixed reference frame. 'TransformOption' = 2 applies a rotation of the reference - frame corresponding to precession between the first and second dates, but leaves the star fixed in - space. 'TransformOption' = 3 provides both transformations. 'TransformOption' = 4 and 'TransformOption' = 5 provide a a - fixed rotation about very small angles (0.1 arcsecond) to take data from the dynamical system - of J2000.0 to the ICRS ('TransformOption' = 4) or vice versa ('TransformOption' = 5). -3. For 'TransformOption' = 1, input data can be in any fixed reference system. for 'TransformOption' = 2 or - 'TransformOption' = 3, this function assumes the input data is in the dynamical system and produces output - in the dynamical system. for 'TransformOption' = 4, the input data must be on the dynamical equator and - equinox of J2000.0. for 'TransformOption' = 5, the input data must be in the ICRS. -4. This function cannot be properly used to bring data from old star catalogs into the - modern system, because old catalogs were compiled using a set of constants that are incompatible - with modern values. In particular, it should not be used for catalogs whose positions and - proper motions were derived by assuming a precession constant significantly different from - the value implicit in function 'precession'. -
- - - Convert Hipparcos catalog data at epoch J1991.25 to epoch J2000.0, for use within NOVAS. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members - having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. Both input and - output data is in the ICRS. - - 1. Input (Hipparcos catalog) epoch and units: - - Epoch: J1991.25 - Right ascension (RA): degrees - Declination (Dec): degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second (not in catalog) - - - - 2. Output (modified Hipparcos) epoch and units: - - Epoch: J2000.0 - Right ascension: hours - Declination: degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second - > - - - - - - Converts a vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - Right ascension in hours. - Declination in degrees. - -
- = 0 ... Everything OK.
- = 1 ... All vector components are zero; 'Ra' and 'Dec' are indeterminate.
- = 2 ... Both Pos[0] and Pos[1] are zero, but Pos[2] is nonzero; 'Ra' is indeterminate.
- 
- -
- - - Compute the virtual place of a planet or other solar system body. - - TT Julian date for virtual place. - structure containing the body designation for the solar system body( - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - True distance from Earth to planet in AU. - -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Type' in structure 'SsBody'.
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the virtual place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for virtual place. - catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - -
- =  0 ... Everything OK.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'
- 
- -
- - - Corrects a vector in the ITRF (rotating Earth-fixed system) for polar motion, and also corrects - the longitude origin (by a tiny amount) to the Terrestrial Intermediate Origin (TIO). - - TT or UT1 Julian date. - Conventionally-defined X coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRF axes. - Position vector, geocentric equatorial rectangular coordinates, - referred to true equator and TIO. - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - Interface to the NOVAS31 component - - Implemented by the NOVAS31 component - - - - Get position and velocity of target with respect to the centre object. - - Two-element array containing the Julian date, which may be split any way (although the first - element is usually the "integer" part, and the second element is the "fractional" part). Julian date is in the - TDB or "T_eph" time scale. - Target object - Centre object - Position vector array of target relative to center, measured in AU. - Velocity vector array of target relative to center, measured in AU/day. -
- 0   ...everything OK.
- 1,2 ...error returned from State.
-
- This function accesses the JPL planetary ephemeris to give the position and velocity of the target - object with respect to the center object. -
- - - Read object ephemeris - - The number of the asteroid for which the position in desired. - The name of the asteroid. - The Julian date on which to find the position and velocity. - Error code; always set equal to 9 (see note below). - 6-element array of double cotaining position and velocity vector values, with all elements set to zero. - This is a dummy version of function 'ReadEph'. It serves as a stub for the "real" 'ReadEph' - (part of the USNO/AE98 minor planet ephemerides) when NOVAS-C is used without the minor planet ephemerides. - - This dummy function is not intended to be called. It merely serves as a stub for the "real" 'ReadEph' - when NOVAS-C is used without the minor planet ephemerides. If this function is called, an error of 9 will be returned. - - - - - - Interface between the JPL direct-access solar system ephemerides and NOVAS-C. - - Julian date of the desired time, on the TDB time scale. - Body identification number for the solar system object of interest; - Mercury = 1, ..., Pluto= 9, Sun= 10, Moon = 11. - Origin code; solar system barycenter= 0, center of mass of the Sun = 1, center of Earth = 2. - Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of 'body' at tjd; equatorial rectangular system referred to the ICRS. - Always returns 0 - - - - - Read and interpolate the JPL planetary ephemeris file. - - 2-element Julian date (TDB) at which interpolation is wanted. Any combination of jed[0]+jed[1] which falls within the time span on the file is a permissible epoch. See Note 1 below. - The requested body to get data for from the ephemeris file. - The barycentric position vector array of the requested object, in AU. (If target object is the Moon, then the vector is geocentric.) - The barycentric velocity vector array of the requested object, in AU/Day. - -
- 0 ...everything OK
- 1 ...error reading ephemeris file
- 2 ...epoch out of range.
- 
- - The target number designation of the astronomical bodies is: -
-         = 0: Mercury,               1: Venus, 
-         = 2: Earth-Moon barycenter, 3: Mars, 
-         = 4: Jupiter,               5: Saturn, 
-         = 6: Uranus,                7: Neptune, 
-         = 8: Pluto,                 9: geocentric Moon, 
-         =10: Sun.
- 
- - NOTE 1. For ease in programming, the user may put the entire epoch in jed[0] and set jed[1] = 0. - For maximum interpolation accuracy, set jed[0] = the most recent midnight at or before interpolation epoch, - and set jed[1] = fractional part of a day elapsed between jed[0] and epoch. As an alternative, it may prove - convenient to set jed[0] = some fixed epoch, such as start of the integration and jed[1] = elapsed interval - between then and epoch. - -
-
- - - Corrects position vector for aberration of light. Algorithm includes relativistic terms. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from object to Earth in days. - Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - If 'lighttime' = 0 on input, this function will compute it. - - - - Compute the apparent place of a planet or other solar system body. - - TT Julian date for apparent place. - Pointer to structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the apparent place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for apparent place. - Catalog entry structure containing catalog data forthe object in the ICRS - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Apparent declination in degrees, referred to true equator and equinox of date 'JdTt'. - -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Compute the astrometric place of a planet or other solar system body. - - TT Julian date for astrometric place. - structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). - True distance from Earth to planet in AU. - -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the astrometric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for astrometric place. - Catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Move the origin of coordinates from the barycenter of the solar system to the observer (or the geocenter); i.e., this function accounts for parallax (annual+geocentric or justannual). - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Position vector, referred to origin at center of mass of the Earth, components in AU. - Light time from object to Earth in days. - - - - - This function will compute a date on the Gregorian calendar given the Julian date. - - Julian date. - Year - Month number - day number - Fractional hour of the day - - - - - This function rotates a vector from the celestial to the terrestrial system. Specifically, it transforms a vector in the - GCRS (a local space-fixed system) to the ITRS (a rotating earth-fixed system) by applying rotations for the GCRS-to-dynamical - frame tie, precession, nutation, Earth rotation, and polar motion. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. (See note 2 below) - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRS pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRS pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to GCRS axes (celestial system) or with respect to - the equator and equinox of date, depending on 'option'. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRS axes (terrestrial system). -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- Note 1: 'x' = 'y' = 0 means no polar motion transformation. - - Note2: 'option' = 1 only works for the equinox-based method. - -
- - - This function allows for the specification of celestial pole offsets for high-precision applications. Each set of offsets is a correction to the modeled position of the pole for a specific date, derived from observations and published by the IERS. - - TDB or TT Julian date for pole offsets. - Type of pole offset. 1 for corrections to angular coordinates of modeled pole referred to mean ecliptic of date, that is, delta-delta-psi and delta-delta-epsilon. 2 for corrections to components of modeled pole unit vector referred to GCRS axes, that is, dx and dy. - Value of celestial pole offset in first coordinate, (delta-delta-psi or dx) in milliarcseconds. - Value of celestial pole offset in second coordinate, (delta-delta-epsilon or dy) in milliarcseconds. -
- 0 ... Everything OK
- 1 ... Invalid value of 'Type'.
- 
- -
- - - Calaculate an array of CIO RA values around a given date - - TDB Julian date. - Number of Julian dates and right ascension values requested (not less than 2 or more than 20). - An arraylist of RaOfCIO structures containing a time series of the right ascension of the - Celestial Intermediate Origin (CIO) with respect to the GCRS. -
- 0 ... everything OK
- 1 ... error opening the 'cio_ra.bin' file
- 2 ... 'JdTdb' not in the range of the CIO file; 
- 3 ... 'NPts' out of range
- 4 ... unable to allocate memory for the internal 't' array; 
- 5 ... unable to allocate memory for the internal 'ra' array; 
- 6 ... 'JdTdb' is too close to either end of the CIO file; unable to put 'NPts' data points into the output object.
- 
- - - Given an input TDB Julian date and the number of data points desired, this function returns a set of - Julian dates and corresponding values of the GCRS right ascension of the celestial intermediate origin (CIO). - The range of dates is centered (at least approximately) on the requested date. The function obtains - the data from an external data file. - How to create and retrieve values from the arraylist - - Dim CioList As New ArrayList, Nov3 As New ASCOM.Astrometry.NOVAS3 - - rc = Nov3.CioArray(2455251.5, 20, CioList) ' Get 20 values around date 00:00:00 February 24th 2010 - MsgBox("Nov3 RC= " rc) - - For Each CioA As ASCOM.Astrometry.RAOfCio In CioList - MsgBox("CIO Array " CioA.JdTdb " " CioA.RACio) - Next - - - -
- - - Compute the orthonormal basis vectors of the celestial intermediate system. - - TDB Julian date of epoch. - Right ascension of the CIO at epoch (hours). - Reference system in which right ascension is given. 1 ... GCRS; 2 ... True equator and equinox of date. - Accuracy - Unit vector toward the CIO, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward the y-direction, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward north celestial pole (CIP), equatorial rectangular coordinates, referred to the GCRS. -
- 0 ... everything OK
- 1 ... invalid value of input variable 'RefSys'.
- 
- - To compute the orthonormal basis vectors, with respect to the GCRS (geocentric ICRS), of the celestial - intermediate system defined by the celestial intermediate pole (CIP) (in the z direction) and - the celestial intermediate origin (CIO) (in the x direction). A TDB Julian date and the - right ascension of the CIO at that date is required as input. The right ascension of the CIO - can be with respect to either the GCRS origin or the true equinox of date -- different algorithms - are used in the two cases. -
- - - Returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension - - TDB Julian date. - Selection for accuracy - Right ascension of the CIO, in hours. - Reference system in which right ascension is given -
-    0 ... everything OK
-    1 ... unable to allocate memory for the 'cio' array
- > 10 ... 10 + the error code from function 'CioArray'.
- 
- This function returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension with respect to either the GCRS (geocentric ICRS) origin or the true equinox of date. The CIO is always located on the true equator (= intermediate equator) of date. -
- - - Computes the true right ascension of the celestial intermediate origin (CIO) at a given TT Julian date. This is -(equation of the origins). - - TT Julian date - Selection for accuracy - Right ascension of the CIO, with respect to the true equinox of date, in hours (+ or -). - -
-   0  ... everything OK
-   1  ... invalid value of 'Accuracy'
- > 10 ... 10 + the error code from function 'CioLocation'
- > 20 ... 20 + the error code from function 'CioBasis'.
- 
- -
- - - Returns the difference in light-time, for a star, between the barycenter of the solar system and the observer (or the geocenter). - - Position vector of star, with respect to origin at solar system barycenter. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Difference in light time, in the sense star to barycenter minus star to earth, in days. - - Alternatively, this function returns the light-time from the observer (or the geocenter) to a point on a - light ray that is closest to a specific solar system body. For this purpose, 'Pos1' is the position - vector toward observed object, with respect to origin at observer (or the geocenter); 'PosObs' is - the position vector of solar system body, with respect to origin at observer (or the geocenter), - components in AU; and the returned value is the light time to point on line defined by 'Pos1' - that is closest to solar system body (positive if light passes body before hitting observer, i.e., if - 'Pos1' is within 90 degrees of 'PosObs'). - - - - - Converts an ecliptic position vector to an equatorial position vector. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system selection. 0 ... mean equator and equinox of date; 1 ... true equator and equinox of date; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified ecliptic and equinox of date. If 'CoordSys' = 2, 'pos1' must be on mean ecliptic and equinox of J2000.0; see Note 1 below. - Position vector, referred to specified equator and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert an ecliptic vector (mean ecliptic and equinox of J2000.0 only) to an ICRS vector, - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the output from this case, all vectors are assumed to be with respect to a dynamical system. - -
- - - Compute the "complementary terms" of the equation of the equinoxes consistent with IAU 2000 resolutions. - - High-order part of TT Julian date. - Low-order part of TT Julian date. - Selection for accuracy - Complementary terms, in radians. - - 1. The series used in this function was derived from Series from IERS Conventions (2003), Chapter 5, Table 5.2C. - This same series was also adopted for use in the IAU's Standards of Fundamental Astronomy (SOFA) software (i.e., subroutine - eect00.for and function eect00.c). - 2. The low-accuracy series used in this function is a simple implementation derived from the first reference, in which terms - smaller than 2 microarcseconds have been omitted. - 3. This function is based on NOVAS Fortran routine 'eect2000', with the low-accuracy formula taken from NOVAS Fortran routine 'etilt'. - - - - - Retrieves the position and velocity of a solar system body from a fundamental ephemeris. - - TDB Julian date split into two parts, where the sum jd[0] + jd[1] is the TDB Julian date. - Structure containing the designation of the body of interest - Origin code; solar system barycenter = 0, center of mass of the Sun = 1. - Slection for accuracy - Position vector of the body at 'Jd'; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of the body at 'Jd'; equatorial rectangular system referred to the mean equator and equinox of the ICRS, in AU/Day. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Origin'
-    2 ... Invalid value of 'Type' in 'CelObj'; 
-    3 ... Unable to allocate memory
- 10+n ... where n is the error code from 'SolarSystem'; 
- 20+n ... where n is the error code from 'ReadEph'.
- 
- It is recommended that the input structure 'cel_obj' be created using function 'MakeObject' in file novas.c. -
- - - To convert right ascension and declination to ecliptic longitude and latitude. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system: 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Right ascension in hours, referred to specified equator and equinox of date. - Declination in degrees, referred to specified equator and equinox of date. - Ecliptic longitude in degrees, referred to specified ecliptic and equinox of date. - Ecliptic latitude in degrees, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert ICRS RA and dec to ecliptic coordinates (mean ecliptic and equinox of J2000.0), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the input to this case, all input coordinates are dynamical. - -
- - - Converts an equatorial position vector to an ecliptic position vector. - - TT Julian date of equator, equinox, and ecliptic used for - Coordinate system selection. 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified equator and equinox of date. - Position vector, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- To convert an ICRS vector to an ecliptic vector (mean ecliptic and equinox of J2000.0 only), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. Except for - the input to this case, all vectors are assumed to be with respect to a dynamical system. -
- - - Converts ICRS right ascension and declination to galactic longitude and latitude. - - ICRS right ascension in hours. - ICRS declination in degrees. - Galactic longitude in degrees. - Galactic latitude in degrees. - - - - - Transforms topocentric right ascension and declination to zenith distance and azimuth. - - UT1 Julian date. - Difference TT-UT1 at 'jd_ut1', in seconds. - Selection for accuracy - onventionally-defined x coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option. 0 ... no refraction; 1 ... include refraction, using 'standard' atmospheric conditions; - 2 ... include refraction, using atmospheric parametersinput in the 'Location' structure. - Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - Topocentric azimuth (measured east from north) in degrees. - Topocentric right ascension of object of interest, in hours, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - Topocentric declination of object of interest, in degrees, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms topocentric right ascension and declination to zenith distance and azimuth. - It uses a method that properly accounts for polar motion, which is significant at the sub-arcsecond level. - This function can also adjust coordinates for atmospheric refraction. - - - - Returns the value of the Earth Rotation Angle (theta) for a given UT1 Julian date. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - The Earth Rotation Angle (theta) in degrees. - The expression used is taken from the note to IAU Resolution B1.8 of 2000. 1. The algorithm used - here is equivalent to the canonical theta = 0.7790572732640 + 1.00273781191135448 * t, where t is the time - in days from J2000 (t = JdHigh + JdLow - T0), but it avoids many two-PI 'wraps' that - decrease precision (adopted from SOFA Fortran routine iau_era00; see also expression at top - of page 35 of IERS Conventions (1996)). - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'JdTdb'. - - TDB Julian Date. - Selection for accuracy - Mean obliquity of the ecliptic in degrees at 'JdTdb'. - True obliquity of the ecliptic in degrees at 'JdTdb'. - Equation of the equinoxes in seconds of time at 'JdTdb'. - Nutation in longitude in arcseconds at 'JdTdb'. - Nutation in obliquity in arcseconds at 'JdTdb'. - Values of the celestial pole offsets 'PSI_COR' and 'EPS_COR' are set using function 'cel_pole', - if desired. See the prolog of 'cel_pole' for details. - - - - To transform a vector from the dynamical reference system to the International Celestial Reference System (ICRS), or vice versa. - - Position vector, equatorial rectangular coordinates. - Set 'direction' 0 for dynamical to ICRS transformation. Set 'direction' =]]> 0 for - ICRS to dynamical transformation. - Position vector, equatorial rectangular coordinates. - - - - - To compute the fundamental arguments (mean elements) of the Sun and Moon. - - TDB time in Julian centuries since J2000.0 - Double array of fundamental arguments - - Fundamental arguments, in radians: -
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (mean argument of the latitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = a[4] (mean longitude of the Moon's ascending node);
-                from Simon section 3.4(b.3),
-                precession = 5028.8200 arcsec/cy)
- 
-
-
- - - Converts GCRS right ascension and declination to coordinates with respect to the equator of date (mean or true). - - TT Julian date of equator to be used for output coordinates. - Coordinate system selection for output coordinates.; 0 ... mean equator and - equinox of date; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date - Selection for accuracy - GCRS right ascension in hours. - GCRS declination in degrees. - Right ascension in hours, referred to specified equator and right ascension origin of date. - Declination in degrees, referred to specified equator of date. - -
-    0 ... everything OK
- >  0 ... error from function 'Vector2RaDec'' 
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
>
- For coordinates with respect to the true equator of date, the origin of right ascension can be either the true equinox or the celestial intermediate origin (CIO). - This function only supports the CIO-based method. -
- - - This function computes the geocentric position and velocity of an observer on - the surface of the earth or on a near-earth spacecraft. - TT Julian date. - Value of Delta T (= TT - UT1) at 'JdTt'. - Selection for accuracy - Data specifying the location of the observer - Position vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU. - Velocity vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU/day. - -
- 0 ... everything OK
- 1 ... invalid value of 'Accuracy'.
- 
- The final vectors are expressed in the GCRS. -
- - - Computes the total gravitational deflection of light for the observed object due to the major gravitating bodies in the solar system. - - TDB Julian date of observation. - Code for location of observer, determining whether the gravitational deflection due to the earth itself is applied. - Selection for accuracy - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar - system barycenter, referred to ICRS axes, components in AU. - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, corrected for gravitational deflection, components in AU. -
-    0 ... Everything OK
-  30 ... Error from function 'Ephemeris'; 
- > 30 ... Error from function 'MakeObject'.
- 
- This function valid for an observed body within the solar system as well as for a star. - - If 'Accuracy' is set to zero (full accuracy), three bodies (Sun, Jupiter, and Saturn) are - used in the calculation. If the reduced-accuracy option is set, only the Sun is used in the - calculation. In both cases, if the observer is not at the geocenter, the deflection due to the Earth is included. - - -
- - - Corrects position vector for the deflection of light in the gravitational field of an arbitrary body. - - Position vector of observed object, with respect to origin at observer - (or the geocenter), components in AU. - Position vector of observer (or the geocenter), with respect to origin at - solar system barycenter, components in AU. - Position vector of gravitating body, with respect to origin at solar system - barycenter, components in AU. - Reciprocal mass of gravitating body in solar mass units, that is, - Sun mass / body mass. - Position vector of observed object, with respect to origin at observer - (or the geocenter), corrected for gravitational deflection, components in AU. - This function valid for an observed body within the solar system as well as for a star. - - - - Compute the intermediate right ascension of the equinox at the input Julian date - - TDB Julian date. - Equinox selection flag: mean pr true - Selection for accuracy - Intermediate right ascension of the equinox, in hours (+ or -). If 'equinox' = 1 - (i.e true equinox), then the returned value is the equation of the origins. - - - - - Compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number - Day number - Fractional hour of the day - Computed Julian date. - This function makes no checks for a valid input calendar date. The input calendar date - must be Gregorian. The input time value can be based on any UT-like time scale (UTC, UT1, TT, etc.) - - output Julian date will have the same basis. - - - - Computes the geocentric position of a solar system body, as antedated for light-time. - - TDB Julian date of observation. - Structure containing the designation for thesolar system body - Position vector of observer (or the geocenter), with respect to origin - at solar system barycenter, referred to ICRS axes, components in AU. - First approximation to light-time, in days (can be set to 0.0 if unknown) - Selection for accuracy - Position vector of body, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Final light-time, in days. -
-    0 ... everything OK
-    1 ... algorithm failed to converge after 10 iterations
- ]]> 10 ... error is 10 + error from function 'SolarSystem'.
- 
- -
- - - Determines the angle of an object above or below the Earth's limb (horizon). - - Position vector of observed object, with respect to origin at - geocenter, components in AU. - Position vector of observer, with respect to origin at geocenter, - components in AU. - Angle of observed object above (+) or below (-) limb in degrees. - Nadir angle of observed object as a fraction of apparent radius of limb: 1.0 ... - below the limb; = 1.0 ... on the limb; ]]> 1.0 ... above the limb - The geometric limb is computed, assuming the Earth to be an airless sphere (no - refraction or oblateness is included). The observer can be on or above the Earth. - For an observer on the surface of the Earth, this function returns the approximate unrefracted - altitude. - - - - Computes the local place of a solar system body. - - TT Julian date for local place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Specifies accuracy level - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. - True distance from Earth to planet in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'; 
- ]]> 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the local place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for local place. delta_t (double) - Difference TT-UT1 at 'JdTt', in seconds of time. - catalog entry structure containing catalog data for the object in the ICRS - Structure specifying the position of the observer - Specifies accuracy level. - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Object name (50 characters maximum). - Three-character catalog identifier (e.g. HIP = Hipparcos, TY2 = Tycho-2) - Object number in the catalog. - Right ascension of the object (hours). - Declination of the object (degrees). - Proper motion in right ascension (milliarcseconds/year). - Proper motion in declination (milliarcseconds/year). - Parallax (milliarcseconds). - Radial velocity (kilometers/second). - CatEntry3 structure containing the input data - - - - - Makes a structure of type 'InSpace' - specifying the position and velocity of an observer situated - on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric velocity vector (x_dot, y_dot, z_dot) in km/s. - InSpace structure containing the position and velocity of an observer situated - on a near-Earth spacecraft - - - - - Makes a structure of type 'object' - specifying a celestial object - based on the input parameters. - - Type of object: 0 ... major planet, Sun, or Moon; 1 ... minor planet; - 2 ... object located outside the solar system (e.g. star, galaxy, nebula, etc.) - Body number: For 'Type' = 0: Mercury = 1,...,Pluto = 9, Sun = 10, Moon = 11; - For 'Type' = 1: minor planet numberFor 'Type' = 2: set to 0 (zero) - Name of the object (50 characters maximum). - Structure containing basic astrometric data for any celestial object - located outside the solar system; the catalog data for a star - Structure containing the object definition -
- 0 ... everything OK
- 1 ... invalid value of 'Type'
- 2 ... 'Number' out of range
- 
- -
- - - Makes a structure of type 'observer' - specifying the location of the observer. - - Integer code specifying location of observer: 0: observer at geocenter; - 1: observer on surface of earth; 2: observer on near-earth spacecraft - Structure containing data for an observer's location on the surface - of the Earth; used when 'Where' = 1 - Structure containing an observer's location on a near-Earth spacecraft; - used when 'Where' = 2 - Structure specifying the location of the observer -
- 0 ... everything OK
- 1 ... input value of 'Where' is out-of-range.
- 
- -
- - - Makes a structure of type 'observer' specifying an observer at the geocenter. - - Structure specifying the location of the observer at the geocenter - - - - - Makes a structure of type 'observer' specifying the position and velocity of an observer - situated on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric position vector (x, y, z) in km. - Structure containing the position and velocity of an observer - situated on a near-Earth spacecraft - Both input vectors are with respect to true equator and equinox of date. - - - - Makes a structure of type 'observer' specifying the location of and weather for an observer - on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) longitude in degrees; east positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an observer on - the surface of the Earth - - - - - Makes a structure of type 'on_surface' - specifying the location of and weather for an - observer on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) latitude in degrees; north positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an - observer on the surface of the Earth. - - - - - Compute the mean obliquity of the ecliptic. - - TDB Julian Date. - Mean obliquity of the ecliptic in arcseconds. - - - - - Computes the ICRS position of a star, given its apparent place at date 'JdTt'. - Proper motion, parallax and radial velocity are assumed to be zero. - - TT Julian date of apparent place. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - Specifies accuracy level - ICRS right ascension in hours. - ICRS declination in degrees. -
-    0 ... Everything OK
-    1 ... Iterative process did not converge after 30 iterations; 
- > 10 ... Error from function 'Vector2RaDec'
- > 20 ... Error from function 'AppStar'.
- 
- -
- - - Normalize angle into the range 0 angle (2 * pi). - - Input angle (radians). - The input angle, normalized as described above (radians). - - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB Julian date of epoch. - Flag determining 'direction' of transformation; direction = 0 - transformation applied, mean to true; direction != 0 inverse transformation applied, true to mean. - Selection for accuracy - Position vector, geocentric equatorial rectangular coordinates, referred to - mean equator and equinox of epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to - true equator and equinox of epoch. - Inverse transformation may be applied by setting flag 'direction' - - - - Returns the values for nutation in longitude and nutation in obliquity for a given TDB Julian date. - - TDB time in Julian centuries since J2000.0 - Selection for accuracy - Nutation in longitude in arcseconds. - Nutation in obliquity in arcseconds. - The nutation model selected depends upon the input value of 'Accuracy'. See notes below for important details. - - This function selects the nutation model depending first upon the input value of 'Accuracy'. - If 'Accuracy' = 0 (full accuracy), the IAU 2000A nutation model is used. If 'Accuracy' = 1 - a specially truncated (and therefore faster) version of IAU 2000A, called 'NU2000K' is used. - - - - - - Computes the apparent direction of a star or solar system body at a specified time - and in a specified coordinate system. - - TT Julian date for place. - Specifies the celestial object of interest - Specifies the location of the observer - Difference TT-UT1 at 'JdTt', in seconds of time. - Code specifying coordinate system of the output position. 0 ... GCRS or - "local GCRS"; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date; - 3 ... astrometric coordinates, i.e., without light deflection or aberration. - Selection for accuracy - Structure specifying object's place on the sky at time 'JdTt', - with respect to the specified output coordinate system - -
- = 0         ... No problems.
- = 1         ... invalid value of 'CoordSys'
- = 2         ... invalid value of 'Accuracy'
- = 3         ... Earth is the observed object, and the observer is either at the geocenter or on the Earth's surface (not permitted)
- > 10,  40  ... 10 + error from function 'Ephemeris'
- > 40,  50  ... 40 + error from function 'GeoPosVel'
- > 50,  70  ... 50 + error from function 'LightTime'
- > 70,  80  ... 70 + error from function 'GravDef'
- > 80,  90  ... 80 + error from function 'CioLocation'
- > 90,  100 ... 90 + error from function 'CioBasis'
- 
-
- Values of 'location->where' and 'CoordSys' dictate the various standard kinds of place: -
-     Location->Where = 0 and CoordSys = 1: apparent place
-     Location->Where = 1 and CoordSys = 1: topocentric place
-     Location->Where = 0 and CoordSys = 0: virtual place
-     Location->Where = 1 and CoordSys = 0: local place
-     Location->Where = 0 and CoordSys = 3: astrometric place
-     Location->Where = 1 and CoordSys = 3: topocentric astrometric place
- 
- Input value of 'DeltaT' is used only when 'Location->Where' equals 1 or 2 (observer is - on surface of Earth or in a near-Earth satellite). - - -
- - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of first epoch. - TDB Julian date of second epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of second epoch. -
- 0 ... everything OK
- 1 ... Precession not to or from J2000.0; 'JdTdb1' or 'JdTdb2' not 2451545.0.
- 
- One of the two epochs must be J2000.0. The coordinates are referred to the mean dynamical equator and equinox of the two respective epochs. -
- - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - Position vector at second epoch. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance in AU - Position vector, equatorial rectangular coordinates (AU). - - - - - Predicts the radial velocity of the observed object as it would be measured by spectroscopic means. - - Specifies the celestial object of interest - Geometric position vector of object with respect to observer, corrected for light-time, in AU. - Velocity vector of object with respect to solar system barycenter, in AU/day. - Velocity vector of observer with respect to solar system barycenter, in AU/day. - Distance from observer to geocenter, in AU. - Distance from observer to Sun, in AU. - Distance from object to Sun, in AU. - The observed radial velocity measure times the speed of light, in kilometers/second. - Radial velocity is here defined as the radial velocity measure (z) times the speed of light. - For a solar system body, it applies to a fictitious emitter at the center of the observed object, - assumed massless (no gravitational red shift), and does not in general apply to reflected light. - For stars, it includes all effects, such as gravitational red shift, contained in the catalog - barycentric radial velocity measure, a scalar derived from spectroscopy. Nearby stars with a known - kinematic velocity vector (obtained independently of spectroscopy) can be treated like - solar system objects. - - - - Computes atmospheric refraction in zenith distance. - - Structure containing observer's location. - 1 ... Use 'standard' atmospheric conditions; 2 ... Use atmospheric - parameters input in the 'Location' structure. - Observed zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. This function - can be used for planning observations or telescope pointing, but should not be used for the - reduction of precise observations. - - - - Computes the Greenwich sidereal time, either mean or apparent, at Julian date 'JdHigh' + 'JdLow'. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Difference TT-UT1 at 'JdHigh'+'JdLow', in seconds of time. - 0 ... compute Greenwich mean sidereal time; 1 ... compute Greenwich apparent sidereal time - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - Greenwich apparent sidereal time, in hours. -
-          0 ... everything OK
-          1 ... invalid value of 'Accuracy'
-          2 ... invalid value of 'Method'
- > 10,  30 ... 10 + error from function 'CioRai'
- 
- The Julian date may be split at any point, but for highest precision, set 'JdHigh' - to be the integral part of the Julian date, and set 'JdLow' to be the fractional part. -
- - - Transforms a vector from one coordinate system to another with same origin and axes rotated about the z-axis. - - Angle of coordinate system rotation, positive counterclockwise when viewed from +z, in degrees. - Position vector. - Position vector expressed in new coordinate system rotated about z by 'angle'. - - - - - Converts angular quantities for stars to vectors. - - Catalog entry structure containing ICRS catalog data - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Computes the Terrestrial Time (TT) or Terrestrial Dynamical Time (TDT) Julian date corresponding - to a Barycentric Dynamical Time (TDB) Julian date. - - TDB Julian date. - TT Julian date. - Difference 'tdb_jd'-'tt_jd', in seconds. - Expression used in this function is a truncated form of a longer and more precise - series given in: Explanatory Supplement to the Astronomical Almanac, pp. 42-44 and p. 316. - The result is good to about 10 microseconds. - - - - This function rotates a vector from the terrestrial to the celestial system. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, referred to ITRF - axes (terrestrial system) in the normal case where 'option' = 0. - Position vector, geocentric equatorial rectangular coordinates, referred to GCRS - axes (celestial system) or with respect to the equator and equinox of date, depending on 'Option'. -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- 'x' = 'y' = 0 means no polar motion transformation. - - The 'option' flag only works for the equinox-based method. - -
- - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Structure containing observer's location - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial - rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular - coordinates, referred to true equator and equinox of date, components in AU/day. - - If reference meridian is Greenwich and st=0, 'pos' is effectively referred to equator and Greenwich. - This function ignores polar motion, unless the observer's longitude and latitude have been - corrected for it, and variation in the length of day (angular velocity of earth). - The true equator and equinox of date do not form an inertial system. Therefore, with respect - to an inertial system, the very small velocity component (several meters/day) due to the precession - and nutation of the Earth's axis is not accounted for here. - - - - - Computes the topocentric place of a solar system body. - - TT Julian date for topocentric place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Selection for accuracy - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'Place'.
-
- -
- - - Computes the topocentric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for topocentric place. - Difference TT-UT1 at 'JdTt', in seconds of time. - Catalog entry structure containing catalog data for the object in the ICRS - Specifies the position of the observer - Code specifying the relative accuracy of the output position. - Topocentric right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Topocentric declination in degrees, referred to true equator and equinox of date 'JdTt'. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'.
- 
- -
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option - TT Julian date, or year, of input catalog data. - An entry from the input catalog, with units as given in the struct definition - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - The transformed catalog entry, with units as given in the struct definition - -
- = 0 ... Everything OK.
- = 1 ... Invalid value of an input date for option 2 or 3 (see Note 1 below).
- 
- Also used to rotate catalog quantities on the dynamical equator and equinox of J2000.0 to the ICRS or vice versa. - 1. 'DateInCat' and 'DateNewCat' may be specified either as a Julian date (e.g., 2433282.5) or - a Julian year and fraction (e.g., 1950.0). Values less than 10000 are assumed to be years. - For 'TransformOption' = 2 or 'TransformOption' = 3, either 'DateInCat' or 'DateNewCat' must be 2451545.0 or - 2000.0 (J2000.0). For 'TransformOption' = 4 and 'TransformOption' = 5, 'DateInCat' and 'DateNewCat' are ignored. - 2. 'TransformOption' = 1 updates the star's data to account for the star's space motion between the first - and second dates, within a fixed reference frame. 'TransformOption' = 2 applies a rotation of the reference - frame corresponding to precession between the first and second dates, but leaves the star fixed in - space. 'TransformOption' = 3 provides both transformations. 'TransformOption' = 4 and 'TransformOption' = 5 provide a a - fixed rotation about very small angles (0.1 arcsecond) to take data from the dynamical system - of J2000.0 to the ICRS ('TransformOption' = 4) or vice versa ('TransformOption' = 5). -3. For 'TransformOption' = 1, input data can be in any fixed reference system. for 'TransformOption' = 2 or - 'TransformOption' = 3, this function assumes the input data is in the dynamical system and produces output - in the dynamical system. for 'TransformOption' = 4, the input data must be on the dynamical equator and - equinox of J2000.0. for 'TransformOption' = 5, the input data must be in the ICRS. -4. This function cannot be properly used to bring data from old star catalogs into the - modern system, because old catalogs were compiled using a set of constants that are incompatible - with modern values. In particular, it should not be used for catalogs whose positions and - proper motions were derived by assuming a precession constant significantly different from - the value implicit in function 'precession'. -
- - - Convert Hipparcos catalog data at epoch J1991.25 to epoch J2000.0, for use within NOVAS. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members - having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. Both input and - output data is in the ICRS. - - 1. Input (Hipparcos catalog) epoch and units: - - Epoch: J1991.25 - Right ascension (RA): degrees - Declination (Dec): degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second (not in catalog) - - - - 2. Output (modified Hipparcos) epoch and units: - - Epoch: J2000.0 - Right ascension: hours - Declination: degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second - > - - - - - - Converts a vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - Right ascension in hours. - Declination in degrees. - -
- = 0 ... Everything OK.
- = 1 ... All vector components are zero; 'Ra' and 'Dec' are indeterminate.
- = 2 ... Both Pos[0] and Pos[1] are zero, but Pos[2] is nonzero; 'Ra' is indeterminate.
- 
- -
- - - Compute the virtual place of a planet or other solar system body. - - TT Julian date for virtual place. - structure containing the body designation for the solar system body( - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - True distance from Earth to planet in AU. - -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Type' in structure 'SsBody'.
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the virtual place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for virtual place. - catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - -
- =  0 ... Everything OK.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'
- 
- -
- - - Corrects a vector in the ITRF (rotating Earth-fixed system) for polar motion, and also corrects - the longitude origin (by a tiny amount) to the Terrestrial Intermediate Origin (TIO). - - TT or UT1 Julian date. - direction (short int) - Flag determining 'direction' of transformation; - direction = 0 transformation applied, ITRS to terrestrial intermediate system - direction != 0 inverse transformation applied, terrestrial intermediate system to ITRS - Conventionally-defined X coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRF axes. - Position vector, geocentric equatorial rectangular coordinates, - referred to true equator and TIO. - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - NOVAS: Class presenting the contents of the NOVAS 2 library. - NOVAS was developed by the Astronomical Applications department of the United States Naval - Observatory. The C language version of NOVAS was developed by John Bangert at USNO/AA. - - - The NOVAS class is a STATIC class and is the component of preference for .NET programmers. - This means that you do not have to create an instance of the - class in order to access its members. Instead you reference them directly from the class. So, this works: - rc = ASCOM.Astrometry.NOVAS2.AppStar(tjd, earth, star, ra, dec) - while this does not work: - - Dim Nov as New ASCOM.Astrometry.NOVAS2 - rc = Nov.AppStar(tjd, earth, star, ra, dec) - - Method names are identical to those used in NOVAS2, as are almost all paramaters. There are a few - changes that introduce some new structures but these should be self explanatory. One significant difference - is that position and velocity vectors are returned as structures rather than double arrays. This was done - to make type checking more effective. - Testing of the high level supervisory functions has been carried out using real-time star data from - the USNO web site. Values provided by this NOVAS2 implementation agree on average to about 50 milli - arc-seconds with current USNO web site values. - This class is implemented using a thin layer of .NET code that calls functions in - either a 32 or 64 bit compiled version of the unmodified C code from ther USNO web site. The .NET code - does not carry out calculations itself, it simply handles any interface presentation differences - and calls the relevant 32 or 64bit code according to its environment. - Note: This class only supports Earth in the XXXXPlanet classes, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - - - - - Computes the apparent place of a star - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the earth - Catalog entry structure containing J2000.0 catalog data with FK5-style units (defined in novas.h). - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK
- >0...Error code from function 'solarsystem'.
- -
- - - Computes the topocentric place of a star - - TT (or TDT) Julian date for topocentric place. - Structure containing the body designation for the Earth. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Catalog entry structure containing J2000.0 catalog data with FK5-style units. - Structure containing observer's location - OUT: Topocentric right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Topocentric declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- -
- - - Compute the apparent place of a planet or other solar system body. - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the solar system body - Structure containing the body designation for the Earth - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the topocentric place of a planet, given the location of the observer. - - TT (or TDT) Julian date for topocentric place. - structure containing the body designation for the solar system body - structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - structure containing observer's location - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the virtual place of a star - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the Earth. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'
- 
- - Computes the virtual place of a star at date 'tjd', given its - mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Computes the local place of a star - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - Computes the virtual place of a planet or other solar system body. - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the local place of a planet or other solar system body, given the location of the observer. - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the astrometric place of a star - - TT (or TDT) Julian date for astrometric place. - Pointer to structure containing the body designation for the Earth - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- 
- Computes the astrometric place of a star, given its mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Computes the astrometric place of a planet or other solar system body. - - TT (or TDT) Julian date for calculation. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Transform apparent equatorial coordinates to horizon coordinates - - TT (or TDT) Julian date. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Conventionally-defined x coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option - OUT: Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric azimuth (measured east from north) in degrees. - OUT: Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms apparent equatorial coordinates (right - ascension and declination) to horizon coordinates (zenith - distance and azimuth). It uses a method that properly accounts - for polar motion, which is significant at the sub-arcsecond - level. This function can also adjust coordinates for atmospheric - refraction. - - - - To convert Hipparcos data at epoch J1991.25 to epoch J2000.0 and FK5-style units. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0, with all members having FK5 catalog units. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. -
- 1. Hipparcos epoch and units:
-    Epoch: J1991.25
-    Right ascension (RA): degrees
-    Declination (Dec): degrees
-    Proper motion in RA * cos (Dec): milliarcseconds per year
-    Proper motion in Dec: milliarcseconds per year
-    Parallax: milliarcseconds
-    Radial velocity: kilometers per second (not in catalog)
- 
- 2. FK5 epoch and units:
-    Epoch: J2000.0
-    Right ascension: hours
-    Declination: degrees
-    Proper motion in RA: seconds of time per Julian century
-    Proper motion in Dec: arcseconds per Julian century
-    Parallax: arcseconds
-    Radial velocity: kilometers per second
-
-
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option
-    = 1 ... change epoch; same equator and equinox
-    = 2 ... change equator and equinox; same epoch
-    = 3 ... change equator and equinox and epoch
-
- TT Julian date, or year, of input catalog data. - An entry from the input catalog - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - OUT: The transformed catalog entry -
- 1. 'date_incat' and 'date_newcat' may be specified either as a 
-    Julian date (e.g., 2433282.5) or a Julian year and fraction 
-    (e.g., 1950.0).  Values less than 10000 are assumed to be years.
- 
- 2. option = 1 updates the star's data to account for the star's space motion between 
-               the first and second dates, within a fixed reference frame.
-    option = 2 applies a rotation of the reference frame corresponding to precession 
-               between the first and second dates, but leaves the star fixed in space.
-    option = 3 provides both transformations.
- 
- 3. This subroutine cannot be properly used to bring data from 
-    old (pre-FK5) star catalogs into the modern system, because old 
-    catalogs were compiled using a set of constants that are 
-    incompatible with the IAU (1976) system.
- 
- 4. This function uses TDB Julian dates internally, but no 
-    distinction between TDB and TT is necessary.
-
-
- - - Computes the Greenwich apparent sidereal time, at Julian date 'jd_high' + 'jd_low'. - - Julian date, integral part. - Julian date, fractional part. - Equation of the equinoxes (seconds of time). [Note: this quantity is computed by function 'earthtilt'.] - Greenwich apparent sidereal time, in hours. - - - - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of first epoch. - TDB Julian date of second epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of second epoch. - The coordinates are referred to the mean equator and equinox of the two respective epochs. - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'tjd'. - - TDB Julian date of the desired time - OUT: Mean obliquity of the ecliptic in degrees at 'tjd'. - OUT: True obliquity of the ecliptic in degrees at 'tjd'. - OUT: Equation of the equinoxes in seconds of time at 'tjd'. - OUT: Nutation in longitude in arcseconds at 'tjd'. - OUT: Nutation in obliquity in arcseconds at 'tjd'. - - - - - This function allows for the specification of celestial pole offsets for high-precision applications. - - Value of offset in delta psi (dpsi) in arcseconds. - Value of offset in delta epsilon (deps) in arcseconds. - These are added to the nutation parameters delta psi and delta epsilon. - 1. This function sets the values of global variables 'PSI_COR'and 'EPS_COR' declared at the top of file 'novas.c'. These global variables are used only in NOVAS function 'earthtilt'. - 2. This function, if used, should be called before any other NOVAS functions for a given date. Values of the pole offsets specified via a call to this function will be used until explicitly changed. - 3. Daily values of the offsets are published, for example, in IERS Bulletins A and B. - 4. This function is the "C" version of Fortran NOVAS routine "celpol". - - - - - Retrieves the position and velocity of a body from a fundamental ephemeris. - - TDB Julian date. - Structure containing the designation of the body of interest - Origin point (solar system barycentre or centre of mass of the Sun - OUT: Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at tjd; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0    ... Everything OK.
- 1    ... Invalid value of 'origin'.
- 2    ... Invalid value of 'type' in 'cel_obj'.
- 3    ... Unable to allocate memory.
- 10+n ... where n is the error code from 'solarsystem'.
- 20+n ... where n is the error code from 'readeph'.
- -
- - - Provides the position and velocity of the Earth - - TDB Julian date. - Body identification number. -
- Set 'body' = 0 or 'body' = 1 or 'body' = 10 for the Sun.
- Set 'body' = 2 or 'body' = 3 for the Earth.
-
- Required origin: solar system barycenter or center of mass of the Sun - OUT: Position vector of 'body' at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0...Everything OK.
- 1...Input Julian date ('tjd') out of range.
- 2...Invalid value of 'body'.
-
- Provides the position and velocity of the Earth at epoch 'tjd' by evaluating a closed-form theory without reference to an external file. This function can also provide the position and velocity of the Sun. -
- - - Converts an vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - OUT: Right ascension in hours. - OUT: Declination in degrees. -
- 0...Everything OK.
- 1...All vector components are zero; 'ra' and 'dec' are indeterminate.
- 2...Both vec[0] and vec[1] are zero, but vec[2] is nonzero; 'ra' is indeterminate.
-
- -
- - - Converts angular quanities for stars to vectors. - - Catalog entry structure containing J2000.0 catalog data with FK5-style units - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance - Position vector, equatorial rectangular coordinates (AU). - - - - - Obtains the barycentric and heliocentric positions and velocities of the Earth from the solar system ephemeris. - - TT (or TDT) Julian date. - Structure containing the body designation for the Earth. - OUT: TDB Julian date corresponding to 'tjd'. - OUT: Barycentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Barycentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. - OUT: Heliocentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Heliocentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - Computes the mean place of a star for J2000.0 - - TT (or TDT) Julian date of apparent place. - Pointer to structure containing the body designation for the Earth - Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: Mean right ascension J2000.0 in hours. - OUT: Mean declination J2000.0 in degrees. -
-   0...Everything OK.
-   1...Iterative process did not converge after 20 iterations.
- >10...Error from function 'app_star'.
- Computes the mean place of a star for J2000.0, given its apparent - place at date 'tjd'. Proper motion, parallax and radial velocity - are assumed to be zero. - -
- - - Transforms a vector from an Earth-fixed geographic system to a space-fixed system - - TT (or TDT) Julian date - Greenwich apparent sidereal time, in hours. - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular space-fixed system, referred to mean equator and equinox of J2000.0. - Transforms a vector from an Earth-fixed geographic system to a space-fixed system based on mean equator and equinox of J2000.0; applies rotations for wobble, spin, nutation, and precession. - - - - Transforms geocentric rectangular coordinates from rotating system to non-rotating system - - Local apparent sidereal time at reference meridian, in hours. - Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal reference meridian. - OUT: Vector in geocentric rectangular non-rotating system, referred to true equator and equinox of date. - Transforms geocentric rectangular coordinates from rotating system based on rotational equator and orthogonal reference meridian to non-rotating system based on true equator and equinox of date. - - - - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. - - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal Greenwich meridian - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. Transforms a vector from Earth-fixed geographic system to rotating system based on rotational equator and orthogonal Greenwich meridian through axis of rotation. - - - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Longitude, latitude and height of the observer (in a SiteInfoStruct) - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU/Day. - - - - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - OUT: Position vector at second epoch. - - - - - Moves the origin of coordinates from the barycenter of the solar system to the center of mass of the Earth - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU. - OUT: Position vector, referred to origin at center of mass of the Earth, components in AU. - OUT: Light time from body to Earth in days. - This corrects for parallax. - - - - Corrects position vector for the deflection of light in the gravitational field of the Sun. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Position vector of center of mass of the Earth, referred to origin at center of mass of the Sun, components in AU. - Position vector, referred to origin at center of mass of the Earth, corrected for gravitational deflection, components in AU. - 0...Everything OK. - This function is valid for bodies within the solar system as well as for stars. - - - - Corrects position vector for aberration of light. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from body to Earth in days. - OUT: Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - 0...Everything OK. - Algorithm includes relativistic terms. - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB julian date of epoch. - Flag determining 'direction' of transformation;
-    fn  = 0 transformation applied, mean to true.
-    fn != 0 inverse transformation applied, true to mean.
- Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to true equator and equinox of epoch. - 0...Everything OK. - Inverse transformation may be applied by setting flag 'fn'. -
- - - Provides fast evaluation of the nutation components according to the 1980 IAU Theory of Nutation. - - TDB time in Julian centuries since J2000.0 - OUT: Nutation in longitude in arcseconds. - OUT: Nutation in obliquity in arcseconds. - 0...Everything OK. - - - - - To compute the fundamental arguments. - - TDB time in Julian centuries since J2000.0 - OUT: FundamentalArgsStruct containing:
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (L - omega; L = mean longitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = omega (mean longitude of the Moon's ascending node)
- -
- - - Converts TDB to TT or TDT - - TDB Julian date. - OUT: TT (or TDT) Julian date. - OUT: Difference tdbjd-tdtjd, in seconds. - Computes the terrestrial time (TT) or terrestrial dynamical time (TDT) Julian date corresponding to a barycentric dynamical time (TDB) Julian date. - - - - Sets up a structure of type 'body' - defining a celestial object- based on the input parameters. - - Type of body - Body number - Name of the body. - OUT: Structure containg the body definition -
- = 0 ... everything OK
- = 1 ... invalid value of 'type'
- = 2 ... 'number' out of range
-
- -
- - - To create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Three-character catalog identifier (e.g. HIP = Hipparcos, FK5 = FK5). This identifier also specifies the reference system and units of the data; i.e. they are the same as the specified catalog. - Object name (50 characters maximum). - Object number in the catalog. - Right ascension of the object. - Declination of the object. - Proper motion in right ascension. - Proper motion in declination. - Parallax. - Radial velocity. - OUT: Structure containing the input data - - - - - Computes atmospheric refraction in zenith distance. - - structure containing observer's location - refraction option - bserved zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. - - - - This function will compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number. - Day number - Time in hours - OUT: Julian date. - - - - - Compute a date on the Gregorian calendar given the Julian date. - - Julian date. - OUT: Year number - OUT: Month number. - OUT: Day number - OUT: Time in hours - - - - - Compute equatorial spherical coordinates of Sun referred to the mean equator and equinox of date. - - Julian date on TDT or ET time scale. - OUT: Right ascension referred to mean equator and equinox of date (hours). - OUT: Declination referred to mean equator and equinox of date (degrees). - OUT: Geocentric distance (AU). - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - Get path to a system folder - - SUpply null / nothing to use "current user" - returned string folder path - Folder Number from CSIDL enumeration e.g. CSIDL_PROGRAM_FILES_COMMONX86 = 44 = 0x2c - Indicates whether the folder should be created if it does not already exist. If this value is nonzero, - the folder is created. If this value is zero, the folder is not created - TRUE if successful; otherwise, FALSE. - - - - - NOVAS2COM: Instanciable class presenting the contents of the NOVAS 2 library. - NOVAS was developed by the Astronomical Applications department of the United States Naval - Observatory. The C language version of NOVAS was developed by John Bangert at USNO/AA. - - - The NOVAS2COM class is an instanciable class usable by COM clients. This means that you have to create an instance of the - class in order to access its members. So, this works: - - Dim Nov as New ASCOM.Astrometry.NOVAS2COM - rc = Nov.AppStar(tjd, earth, star, ra, dec) - - while this does not work: - rc = ASCOM.Astrometry.NOVAS2COM.AppStar(tjd, earth, star, ra, dec) - Method names are identical to those used in NOVAS2, as are almost all paramaters. There are a few - changes that introduce some new structures but these should be self explanatory. One significant difference - is that position and velocity vectors are returned as structures rather than double arrays. This was done - to make type checking more effective. - Testing of the high level supervisory functions has been carried out using real-time star data from - the USNO web site. Values provided by this NOVAS2 implementation agree on average to about 50 milli - arc-seconds with current USNO web site values. - This class is implemented using a thin layer of .NET code that calls functions in - either a 32 or 64 bit compiled version of the unmodified C code from ther USNO web site. The .NET code - does not carry out calculations itself, it simply handles any interface presentation differences - and calls the relevant 32 or 64bit code according to its environment. - Note: This class only supports Earth in the XXXXPlanet classes, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - - - - - Corrects position vector for aberration of light. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from body to Earth in days. - OUT: Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - 0...Everything OK. - Algorithm includes relativistic terms. - - - - Compute the apparent place of a planet or other solar system body. - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the solar system body - Structure containing the body designation for the Earth - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the apparent place of a star - - TT (or TDT) Julian date for apparent place. - Structure containing the body designation for the earth - Catalog entry structure containing J2000.0 catalog data with FK5-style units (defined in novas.h). - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK
- >0...Error code from function 'solarsystem'.
- -
- - - Computes the astrometric place of a planet or other solar system body. - - TT (or TDT) Julian date for calculation. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the astrometric place of a star - - TT (or TDT) Julian date for astrometric place. - Pointer to structure containing the body designation for the Earth - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Astrometric right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Astrometric declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- 
- Computes the astrometric place of a star, given its mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Moves the origin of coordinates from the barycenter of the solar system to the center of mass of the Earth - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU. - OUT: Position vector, referred to origin at center of mass of the Earth, components in AU. - OUT: Light time from body to Earth in days. - This corrects for parallax. - - - - Compute a date on the Gregorian calendar given the Julian date. - - Julian date. - OUT: Year number - OUT: Month number. - OUT: Day number - OUT: Time in hours - - - - - This function allows for the specification of celestial pole offsets for high-precision applications. - - Value of offset in delta psi (dpsi) in arcseconds. - Value of offset in delta epsilon (deps) in arcseconds. - These are added to the nutation parameters delta psi and delta epsilon. - 1. This function sets the values of global variables 'PSI_COR'and 'EPS_COR' declared at the top of file 'novas.c'. These global variables are used only in NOVAS function 'earthtilt'. - 2. This function, if used, should be called before any other NOVAS functions for a given date. Values of the pole offsets specified via a call to this function will be used until explicitly changed. - 3. Daily values of the offsets are published, for example, in IERS Bulletins A and B. - 4. This function is the "C" version of Fortran NOVAS routine "celpol". - - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'tjd'. - - TDB Julian date of the desired time - OUT: Mean obliquity of the ecliptic in degrees at 'tjd'. - OUT: True obliquity of the ecliptic in degrees at 'tjd'. - OUT: Equation of the equinoxes in seconds of time at 'tjd'. - OUT: Nutation in longitude in arcseconds at 'tjd'. - OUT: Nutation in obliquity in arcseconds at 'tjd'. - - - - - Retrieves the position and velocity of a body from a fundamental ephemeris. - - TDB Julian date. - Structure containing the designation of the body of interest - Origin point (solar system barycentre or centre of mass of the Sun - OUT: Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at tjd; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0    ... Everything OK.
- 1    ... Invalid value of 'origin'.
- 2    ... Invalid value of 'type' in 'cel_obj'.
- 3    ... Unable to allocate memory.
- 10+n ... where n is the error code from 'solarsystem'.
- 20+n ... where n is the error code from 'readeph'.
- -
- - - Transform apparent equatorial coordinates to horizon coordinates - - TT (or TDT) Julian date. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Conventionally-defined x coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial ephemeris pole with respect to IERS reference pole, in arcseconds. - structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option - OUT: Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric azimuth (measured east from north) in degrees. - OUT: Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - OUT: Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms apparent equatorial coordinates (right - ascension and declination) to horizon coordinates (zenith - distance and azimuth). It uses a method that properly accounts - for polar motion, which is significant at the sub-arcsecond - level. This function can also adjust coordinates for atmospheric - refraction. - - - - To compute the fundamental arguments. - - TDB time in Julian centuries since J2000.0 - OUT: FundamentalArgsStruct containing:
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (L - omega; L = mean longitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = omega (mean longitude of the Moon's ascending node)
- -
- - - Obtains the barycentric and heliocentric positions and velocities of the Earth from the solar system ephemeris. - - TT (or TDT) Julian date. - Structure containing the body designation for the Earth. - OUT: TDB Julian date corresponding to 'tjd'. - OUT: Barycentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Barycentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. - OUT: Heliocentric position vector of Earth at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Heliocentric velocity vector of Earth at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - This function will compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number. - Day number - Time in hours - OUT: Julian date. - - - - - Computes the local place of a planet or other solar system body, given the location of the observer. - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the local place of a star - - TT (or TDT) Julian date for local place. - Pointer to structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - Pointer to structure containing observer's location - OUT: Local right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Local declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
-
- -
- - - To create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Three-character catalog identifier (e.g. HIP = Hipparcos, FK5 = FK5). This identifier also specifies the reference system and units of the data; i.e. they are the same as the specified catalog. - Object name (50 characters maximum). - Object number in the catalog. - Right ascension of the object. - Declination of the object. - Proper motion in right ascension. - Proper motion in declination. - Parallax. - Radial velocity. - OUT: Structure containing the input data - - - - - Computes the mean place of a star for J2000.0 - - TT (or TDT) Julian date of apparent place. - Pointer to structure containing the body designation for the Earth - Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: Mean right ascension J2000.0 in hours. - OUT: Mean declination J2000.0 in degrees. -
-   0...Everything OK.
-   1...Iterative process did not converge after 20 iterations.
- >10...Error from function 'app_star'.
- Computes the mean place of a star for J2000.0, given its apparent - place at date 'tjd'. Proper motion, parallax and radial velocity - are assumed to be zero. - -
- - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB julian date of epoch. - Flag determining 'direction' of transformation;
-    fn  = 0 transformation applied, mean to true.
-    fn != 0 inverse transformation applied, true to mean.
- Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to true equator and equinox of epoch. - 0...Everything OK. - Inverse transformation may be applied by setting flag 'fn'. -
- - - Provides fast evaluation of the nutation components according to the 1980 IAU Theory of Nutation. - - TDB time in Julian centuries since J2000.0 - OUT: Nutation in longitude in arcseconds. - OUT: Nutation in obliquity in arcseconds. - 0...Everything OK. - - - - - Transforms a vector from an Earth-fixed geographic system to a space-fixed system - - TT (or TDT) Julian date - Greenwich apparent sidereal time, in hours. - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular space-fixed system, referred to mean equator and equinox of J2000.0. - Transforms a vector from an Earth-fixed geographic system to a space-fixed system based on mean equator and equinox of J2000.0; applies rotations for wobble, spin, nutation, and precession. - - - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of first epoch. - TDB Julian date of second epoch. - OUT: Position vector, geocentric equatorial rectangular coordinates, referred to mean equator and equinox of second epoch. - The coordinates are referred to the mean equator and equinox of the two respective epochs. - - - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - OUT: Position vector at second epoch. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance - Position vector, equatorial rectangular coordinates (AU). - - - - - Computes atmospheric refraction in zenith distance. - - structure containing observer's location - refraction option - bserved zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. - - - - Sets up a structure of type 'body' - defining a celestial object- based on the input parameters. - - Type of body - Body number - Name of the body. - OUT: Structure containg the body definition -
- = 0 ... everything OK
- = 1 ... invalid value of 'type'
- = 2 ... 'number' out of range
-
- -
- - - Computes the Greenwich apparent sidereal time, at Julian date 'jd_high' + 'jd_low'. - - Julian date, integral part. - Julian date, fractional part. - Equation of the equinoxes (seconds of time). [Note: this quantity is computed by function 'earthtilt'.] - Greenwich apparent sidereal time, in hours. - - - - - Provides the position and velocity of the Earth - - TDB Julian date. - Body identification number. -
- Set 'body' = 0 or 'body' = 1 or 'body' = 10 for the Sun.
- Set 'body' = 2 or 'body' = 3 for the Earth.
-
- Required origin: solar system barycenter or center of mass of the Sun - OUT: Position vector of 'body' at 'tjd'; equatorial rectangular coordinates in AU referred to the mean equator and equinox of J2000.0. - OUT: Velocity vector of 'body' at 'tjd'; equatorial rectangular system referred to the mean equator and equinox of J2000.0, in AU/Day. -
- 0...Everything OK.
- 1...Input Julian date ('tjd') out of range.
- 2...Invalid value of 'body'.
-
- Provides the position and velocity of the Earth at epoch 'tjd' by evaluating a closed-form theory without reference to an external file. This function can also provide the position and velocity of the Sun. -
- - - Transforms geocentric rectangular coordinates from rotating system to non-rotating system - - Local apparent sidereal time at reference meridian, in hours. - Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal reference meridian. - OUT: Vector in geocentric rectangular non-rotating system, referred to true equator and equinox of date. - Transforms geocentric rectangular coordinates from rotating system based on rotational equator and orthogonal reference meridian to non-rotating system based on true equator and equinox of date. - - - - Converts angular quanities for stars to vectors. - - Catalog entry structure containing J2000.0 catalog data with FK5-style units - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Compute equatorial spherical coordinates of Sun referred to the mean equator and equinox of date. - - Julian date on TDT or ET time scale. - OUT: Right ascension referred to mean equator and equinox of date (hours). - OUT: Declination referred to mean equator and equinox of date (degrees). - OUT: Geocentric distance (AU). - - - - - Corrects position vector for the deflection of light in the gravitational field of the Sun. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Position vector of center of mass of the Earth, referred to origin at center of mass of the Sun, components in AU. - Position vector, referred to origin at center of mass of the Earth, corrected for gravitational deflection, components in AU. - 0...Everything OK. - This function is valid for bodies within the solar system as well as for stars. - - - - Converts TDB to TT or TDT - - TDB Julian date. - OUT: TT (or TDT) Julian date. - OUT: Difference tdbjd-tdtjd, in seconds. - Computes the terrestrial time (TT) or terrestrial dynamical time (TDT) Julian date corresponding to a barycentric dynamical time (TDB) Julian date. - - - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Longitude, latitude and height of the observer (in a SiteInfoStruct) - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular coordinates, referred to true equator and equinox of date, components in AU/Day. - - - - - Computes the topocentric place of a planet, given the location of the observer. - - TT (or TDT) Julian date for topocentric place. - structure containing the body designation for the solar system body - structure containing the body designation for the Earth - Difference TT(or TDT)-UT1 at 'tjd', in seconds. - structure containing observer's location - OUT: Apparent right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Apparent declination in degrees, referred to true equator and equinox of date 'tjd'. - OUT: True distance from Earth to planet at 'tjd' in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the topocentric place of a star - - TT (or TDT) Julian date for topocentric place. - Structure containing the body designation for the Earth. - Difference TT (or TDT)-UT1 at 'tjd', in seconds. - Catalog entry structure containing J2000.0 catalog data with FK5-style units. - Structure containing observer's location - OUT: Topocentric right ascension in hours, referred to true equator and equinox of date 'tjd'. - OUT: Topocentric declination in degrees, referred to true equator and equinox of date 'tjd'. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'.
- -
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option
-    = 1 ... change epoch; same equator and equinox
-    = 2 ... change equator and equinox; same epoch
-    = 3 ... change equator and equinox and epoch
-
- TT Julian date, or year, of input catalog data. - An entry from the input catalog - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - OUT: The transformed catalog entry -
- 1. 'date_incat' and 'date_newcat' may be specified either as a 
-    Julian date (e.g., 2433282.5) or a Julian year and fraction 
-    (e.g., 1950.0).  Values less than 10000 are assumed to be years.
- 
- 2. option = 1 updates the star's data to account for the star's space motion between 
-               the first and second dates, within a fixed reference frame.
-    option = 2 applies a rotation of the reference frame corresponding to precession 
-               between the first and second dates, but leaves the star fixed in space.
-    option = 3 provides both transformations.
- 
- 3. This subroutine cannot be properly used to bring data from 
-    old (pre-FK5) star catalogs into the modern system, because old 
-    catalogs were compiled using a set of constants that are 
-    incompatible with the IAU (1976) system.
- 
- 4. This function uses TDB Julian dates internally, but no 
-    distinction between TDB and TT is necessary.
-
-
- - - To convert Hipparcos data at epoch J1991.25 to epoch J2000.0 and FK5-style units. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0, with all members having FK5 catalog units. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. -
- 1. Hipparcos epoch and units:
-    Epoch: J1991.25
-    Right ascension (RA): degrees
-    Declination (Dec): degrees
-    Proper motion in RA * cos (Dec): milliarcseconds per year
-    Proper motion in Dec: milliarcseconds per year
-    Parallax: milliarcseconds
-    Radial velocity: kilometers per second (not in catalog)
- 
- 2. FK5 epoch and units:
-    Epoch: J2000.0
-    Right ascension: hours
-    Declination: degrees
-    Proper motion in RA: seconds of time per Julian century
-    Proper motion in Dec: arcseconds per Julian century
-    Parallax: arcseconds
-    Radial velocity: kilometers per second
-
-
- - - Converts an vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - OUT: Right ascension in hours. - OUT: Declination in degrees. -
- 0...Everything OK.
- 1...All vector components are zero; 'ra' and 'dec' are indeterminate.
- 2...Both vec[0] and vec[1] are zero, but vec[2] is nonzero; 'ra' is indeterminate.
-
- -
- - - Computes the virtual place of a planet or other solar system body. - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the solar system body - Pointer to structure containing the body designation for the Earth - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. - OUT: True distance from Earth to planet in AU. -
-  0...Everything OK.
- >0...See error description in function 'ephemeris'.
- 
- - Note: This function only supports Earth, which is a consequence of the implementation - used. Please use the NOVAS3.1 or later classes in applications that require planetary or moon ephemeredes as these classes - can access the JPL 421 planetary ephemeris data provided as part of the ASCOM distribution. - -
- - - Computes the virtual place of a star - - TT (or TDT) Julian date for virtual place. - Pointer to structure containing the body designation for the Earth. - Pointer to catalog entry structure containing J2000.0 catalog data with FK5-style units - OUT: Virtual right ascension in hours, referred to mean equator and equinox of J2000. - OUT: Virtual declination in degrees, referred to mean equator and equinox of J2000. -
-  0...Everything OK.
- >0...Error code from function 'solarsystem'
- 
- - Computes the virtual place of a star at date 'tjd', given its - mean place, proper motion, parallax, and radial velocity for J2000.0. -
- - - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. - - Conventionally-defined X coordinate of rotational pole with respect to CIO, in arcseconds. - Conventionally-defined Y coordinate of rotational pole with respect to CIO, in arcseconds. - Vector in geocentric rectangular Earth-fixed system, referred to geographic equator and Greenwich meridian. - OUT: Vector in geocentric rectangular rotating system, referred to rotational equator and orthogonal Greenwich meridian - Corrects Earth-fixed geocentric rectangular coordinates for polar motion. Transforms a vector from Earth-fixed geographic system to rotating system based on rotational equator and orthogonal Greenwich meridian through axis of rotation. - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - NOVAS3: Class presenting the contents of the USNO NOVAS 3 library published December 2009. - NOVAS was developed by the Astronomical Applications department of the United States Naval - Observatory. - - If you wish to explore or utilise NOVAS3 please see USNO's extensive help document "NOVAS 3 Users Guide" - (NOVAS C3.0 Guide.pdf) included in the ASCOM Platform Docs start menu folder. The latest revision is also available on the USNO web site at - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/novas - in the "C Edition of NOVAS" link. - If you use NOVAS, please send an e-mail through this page: - http://www.usno.navy.mil/help/astronomy-help as this provides evidence to USNO that justifies further - improvements and developments of NOVAS capabilities. - - Note: This class is now deprecated, please use NOVAS31 instead. - - - - - Creates a new instance of the NOVAS3 component - - Thrown if the NOVAS3 support library DLL cannot be loaded - - - - - Cleans up the NOVAS3 object and releases its open file handle on the JPL planetary ephemeris file - - - - - - Get position and velocity of target with respect to the centre object. - - Two-element array containing the Julian date, which may be split any way (although the first - element is usually the "integer" part, and the second element is the "fractional" part). Julian date is in the - TDB or "T_eph" time scale. - Target object - Centre object - Position vector array of target relative to center, measured in AU. - Velocity vector array of target relative to center, measured in AU/day. -
- 0   ...everything OK.
- 1,2 ...error returned from State.
-
- This function accesses the JPL planetary ephemeris to give the position and velocity of the target - object with respect to the center object. -
- - - Produces the Cartesian heliocentric equatorial coordinates of the asteroid for the J2000.0 epoch - coordinate system from a set of Chebyshev polynomials read from a file. - - The number of the asteroid for which the position in desired. - The name of the asteroid. - The Julian date on which to find the position and velocity. -
- = 0 ( No error )
- = 1 ( Memory allocation error )
- = 2 ( Mismatch between asteroid name and number )
- = 3 ( Julian date out of bounds )
- = 4 ( Cannot find Chebyshev polynomial file )
- 
- - 6-element array of double containing position and velocity vector values. - The file name of the asteroid is taken from the name given. It is assumed that the name - is all in lower case characters. - - This routine will search in the application's current directory for a file of Chebyshev - polynomial coefficients whose name is based on the provided Name parameter: Name.chby - - Further information on using NOVAS with minor planet data is given here: - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/usnoae98 - -
- - - Interface between the JPL direct-access solar system ephemerides and NOVAS-C. - - Julian date of the desired time, on the TDB time scale. - Body identification number for the solar system object of interest; - Mercury = 1, ..., Pluto= 9, Sun= 10, Moon = 11. - Origin code; solar system barycenter= 0, center of mass of the Sun = 1, center of Earth = 2. - Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of 'body' at tjd; equatorial rectangular system referred to the ICRS. - Always returns 0 - - - - - Read and interpolate the JPL planetary ephemeris file. - - 2-element Julian date (TDB) at which interpolation is wanted. Any combination of jed[0]+jed[1] which falls within the time span on the file is a permissible epoch. See Note 1 below. - The requested body to get data for from the ephemeris file. - The barycentric position vector array of the requested object, in AU. (If target object is the Moon, then the vector is geocentric.) - The barycentric velocity vector array of the requested object, in AU/Day. - -
- 0 ...everything OK
- 1 ...error reading ephemeris file
- 2 ...epoch out of range.
- 
- - The target number designation of the astronomical bodies is: -
-         = 0: Mercury,               1: Venus, 
-         = 2: Earth-Moon barycenter, 3: Mars, 
-         = 4: Jupiter,               5: Saturn, 
-         = 6: Uranus,                7: Neptune, 
-         = 8: Pluto,                 9: geocentric Moon, 
-         =10: Sun.
- 
- - NOTE 1. For ease in programming, the user may put the entire epoch in jed[0] and set jed[1] = 0. - For maximum interpolation accuracy, set jed[0] = the most recent midnight at or before interpolation epoch, - and set jed[1] = fractional part of a day elapsed between jed[0] and epoch. As an alternative, it may prove - convenient to set jed[0] = some fixed epoch, such as start of the integration and jed[1] = elapsed interval - between then and epoch. - -
-
- - - Corrects position vector for aberration of light. Algorithm includes relativistic terms. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from object to Earth in days. - Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - If 'lighttime' = 0 on input, this function will compute it. - - - - Compute the apparent place of a planet or other solar system body. - - TT Julian date for apparent place. - Pointer to structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the apparent place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for apparent place. - Catalog entry structure containing catalog data forthe object in the ICRS - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Apparent declination in degrees, referred to true equator and equinox of date 'JdTt'. - -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Compute the astrometric place of a planet or other solar system body. - - TT Julian date for astrometric place. - structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). - True distance from Earth to planet in AU. - -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the astrometric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for astrometric place. - Catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Move the origin of coordinates from the barycenter of the solar system to the observer (or the geocenter); i.e., this function accounts for parallax (annual+geocentric or justannual). - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Position vector, referred to origin at center of mass of the Earth, components in AU. - Light time from object to Earth in days. - - - - - This function will compute a date on the Gregorian calendar given the Julian date. - - Julian date. - Year - Month number - day number - Fractional hour of the day - - - - - This function allows for the specification of celestial pole offsets for high-precision applications. Each set of offsets is a correction to the modeled position of the pole for a specific date, derived from observations and published by the IERS. - - TDB or TT Julian date for pole offsets. - Type of pole offset. 1 for corrections to angular coordinates of modeled pole referred to mean ecliptic of date, that is, delta-delta-psi and delta-delta-epsilon. 2 for corrections to components of modeled pole unit vector referred to GCRS axes, that is, dx and dy. - Value of celestial pole offset in first coordinate, (delta-delta-psi or dx) in milliarcseconds. - Value of celestial pole offset in second coordinate, (delta-delta-epsilon or dy) in milliarcseconds. -
- 0 ... Everything OK
- 1 ... Invalid value of 'Type'.
- 
- -
- - - Calaculate an array of CIO RA values around a given date - - TDB Julian date. - Number of Julian dates and right ascension values requested (not less than 2 or more than 20). - An arraylist of RaOfCIO structures containing a time series of the right ascension of the - Celestial Intermediate Origin (CIO) with respect to the GCRS. -
- 0 ... everything OK
- 1 ... error opening the 'cio_ra.bin' file
- 2 ... 'JdTdb' not in the range of the CIO file; 
- 3 ... 'NPts' out of range
- 4 ... unable to allocate memory for the internal 't' array; 
- 5 ... unable to allocate memory for the internal 'ra' array; 
- 6 ... 'JdTdb' is too close to either end of the CIO file; unable to put 'NPts' data points into the output object.
- 
- - - Given an input TDB Julian date and the number of data points desired, this function returns a set of - Julian dates and corresponding values of the GCRS right ascension of the celestial intermediate origin (CIO). - The range of dates is centered (at least approximately) on the requested date. The function obtains - the data from an external data file. - How to create and retrieve values from the arraylist - - Dim CioList As New ArrayList, Nov3 As New ASCOM.Astrometry.NOVAS3 - - rc = Nov3.CioArray(2455251.5, 20, CioList) ' Get 20 values around date 00:00:00 February 24th 2010 - MsgBox("Nov3 RC= " rc) - - For Each CioA As ASCOM.Astrometry.RAOfCio In CioList - MsgBox("CIO Array " CioA.JdTdb " " CioA.RACio) - Next - - - -
- - - Compute the orthonormal basis vectors of the celestial intermediate system. - - TDB Julian date of epoch. - Right ascension of the CIO at epoch (hours). - Reference system in which right ascension is given. 1 ... GCRS; 2 ... True equator and equinox of date. - Accuracy - Unit vector toward the CIO, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward the y-direction, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward north celestial pole (CIP), equatorial rectangular coordinates, referred to the GCRS. -
- 0 ... everything OK
- 1 ... invalid value of input variable 'RefSys'.
- 
- - To compute the orthonormal basis vectors, with respect to the GCRS (geocentric ICRS), of the celestial - intermediate system defined by the celestial intermediate pole (CIP) (in the z direction) and - the celestial intermediate origin (CIO) (in the x direction). A TDB Julian date and the - right ascension of the CIO at that date is required as input. The right ascension of the CIO - can be with respect to either the GCRS origin or the true equinox of date -- different algorithms - are used in the two cases. -
- - - Returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension - - TDB Julian date. - Selection for accuracy - Right ascension of the CIO, in hours. - Reference system in which right ascension is given -
-    0 ... everything OK
-    1 ... unable to allocate memory for the 'cio' array
- > 10 ... 10 + the error code from function 'CioArray'.
- 
- This function returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension with respect to either the GCRS (geocentric ICRS) origin or the true equinox of date. The CIO is always located on the true equator (= intermediate equator) of date. -
- - - Computes the true right ascension of the celestial intermediate origin (CIO) at a given TT Julian date. This is -(equation of the origins). - - TT Julian date - Selection for accuracy - Right ascension of the CIO, with respect to the true equinox of date, in hours (+ or -). - -
-   0  ... everything OK
-   1  ... invalid value of 'Accuracy'
- > 10 ... 10 + the error code from function 'CioLocation'
- > 20 ... 20 + the error code from function 'CioBasis'.
- 
- -
- - - Returns the difference in light-time, for a star, between the barycenter of the solar system and the observer (or the geocenter). - - Position vector of star, with respect to origin at solar system barycenter. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Difference in light time, in the sense star to barycenter minus star to earth, in days. - - Alternatively, this function returns the light-time from the observer (or the geocenter) to a point on a - light ray that is closest to a specific solar system body. For this purpose, 'Pos1' is the position - vector toward observed object, with respect to origin at observer (or the geocenter); 'PosObs' is - the position vector of solar system body, with respect to origin at observer (or the geocenter), - components in AU; and the returned value is the light time to point on line defined by 'Pos1' - that is closest to solar system body (positive if light passes body before hitting observer, i.e., if - 'Pos1' is within 90 degrees of 'PosObs'). - - - - - Converts an ecliptic position vector to an equatorial position vector. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system selection. 0 ... mean equator and equinox of date; 1 ... true equator and equinox of date; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified ecliptic and equinox of date. If 'CoordSys' = 2, 'pos1' must be on mean ecliptic and equinox of J2000.0; see Note 1 below. - Position vector, referred to specified equator and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert an ecliptic vector (mean ecliptic and equinox of J2000.0 only) to an ICRS vector, - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the output from this case, all vectors are assumed to be with respect to a dynamical system. - -
- - - Compute the "complementary terms" of the equation of the equinoxes consistent with IAU 2000 resolutions. - - High-order part of TT Julian date. - Low-order part of TT Julian date. - Selection for accuracy - Complementary terms, in radians. - - Series from IERS Conventions (2003), Chapter 5, Table 5.2C, with some adjustments to coefficient values - copied from IERS function 'eect2000', which has a more complete series. - - - - - Retrieves the position and velocity of a solar system body from a fundamental ephemeris. - - TDB Julian date split into two parts, where the sum jd[0] + jd[1] is the TDB Julian date. - Structure containing the designation of the body of interest - Origin code; solar system barycenter = 0, center of mass of the Sun = 1. - Slection for accuracy - Position vector of the body at 'Jd'; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of the body at 'Jd'; equatorial rectangular system referred to the mean equator and equinox of the ICRS, in AU/Day. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Origin'
-    2 ... Invalid value of 'Type' in 'CelObj'; 
-    3 ... Unable to allocate memory
- 10+n ... where n is the error code from 'SolarSystem'; 
- 20+n ... where n is the error code from 'ReadEph'.
- 
- It is recommended that the input structure 'cel_obj' be created using function 'MakeObject' in file novas.c. -
- - - To convert right ascension and declination to ecliptic longitude and latitude. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system: 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Right ascension in hours, referred to specified equator and equinox of date. - Declination in degrees, referred to specified equator and equinox of date. - Ecliptic longitude in degrees, referred to specified ecliptic and equinox of date. - Ecliptic latitude in degrees, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert ICRS RA and dec to ecliptic coordinates (mean ecliptic and equinox of J2000.0), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the input to this case, all input coordinates are dynamical. - -
- - - Converts an equatorial position vector to an ecliptic position vector. - - TT Julian date of equator, equinox, and ecliptic used for - Coordinate system selection. 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified equator and equinox of date. - Position vector, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- To convert an ICRS vector to an ecliptic vector (mean ecliptic and equinox of J2000.0 only), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. Except for - the input to this case, all vectors are assumed to be with respect to a dynamical system. -
- - - Converts ICRS right ascension and declination to galactic longitude and latitude. - - ICRS right ascension in hours. - ICRS declination in degrees. - Galactic longitude in degrees. - Galactic latitude in degrees. - - - - - Transforms topocentric right ascension and declination to zenith distance and azimuth. - - UT1 Julian date. - Difference TT-UT1 at 'jd_ut1', in seconds. - Selection for accuracy - onventionally-defined x coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option. 0 ... no refraction; 1 ... include refraction, using 'standard' atmospheric conditions; - 2 ... include refraction, using atmospheric parametersinput in the 'Location' structure. - Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - Topocentric azimuth (measured east from north) in degrees. - Topocentric right ascension of object of interest, in hours, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - Topocentric declination of object of interest, in degrees, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms topocentric right ascension and declination to zenith distance and azimuth. - It uses a method that properly accounts for polar motion, which is significant at the sub-arcsecond level. - This function can also adjust coordinates for atmospheric refraction. - - - - Returns the value of the Earth Rotation Angle (theta) for a given UT1 Julian date. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - The Earth Rotation Angle (theta) in degrees. - The expression used is taken from the note to IAU Resolution B1.8 of 2000. 1. The algorithm used - here is equivalent to the canonical theta = 0.7790572732640 + 1.00273781191135448 * t, where t is the time - in days from J2000 (t = JdHigh + JdLow - T0), but it avoids many two-PI 'wraps' that - decrease precision (adopted from SOFA Fortran routine iau_era00; see also expression at top - of page 35 of IERS Conventions (1996)). - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'JdTdb'. - - TDB Julian Date. - Selection for accuracy - Mean obliquity of the ecliptic in degrees at 'JdTdb'. - True obliquity of the ecliptic in degrees at 'JdTdb'. - Equation of the equinoxes in seconds of time at 'JdTdb'. - Nutation in longitude in arcseconds at 'JdTdb'. - Nutation in obliquity in arcseconds at 'JdTdb'. - Values of the celestial pole offsets 'PSI_COR' and 'EPS_COR' are set using function 'cel_pole', - if desired. See the prolog of 'cel_pole' for details. - - - - To transform a vector from the dynamical reference system to the International Celestial Reference System (ICRS), or vice versa. - - Position vector, equatorial rectangular coordinates. - Set 'direction' 0 for dynamical to ICRS transformation. Set 'direction' =]]> 0 for - ICRS to dynamical transformation. - Position vector, equatorial rectangular coordinates. - - - - - To compute the fundamental arguments (mean elements) of the Sun and Moon. - - TDB time in Julian centuries since J2000.0 - Double array of fundamental arguments - - Fundamental arguments, in radians: -
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (mean argument of the latitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = a[4] (mean longitude of the Moon's ascending node);
-                from Simon section 3.4(b.3),
-                precession = 5028.8200 arcsec/cy)
- 
-
-
- - - Converts GCRS right ascension and declination to coordinates with respect to the equator of date (mean or true). - - TT Julian date of equator to be used for output coordinates. - Coordinate system selection for output coordinates.; 0 ... mean equator and - equinox of date; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date - Selection for accuracy - GCRS right ascension in hours. - GCRS declination in degrees. - Right ascension in hours, referred to specified equator and right ascension origin of date. - Declination in degrees, referred to specified equator of date. - -
-    0 ... everything OK
- >  0 ... error from function 'Vector2RaDec'' 
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
>
- For coordinates with respect to the true equator of date, the origin of right ascension can be either the true equinox or the celestial intermediate origin (CIO). - This function only supports the CIO-based method. -
- - - This function computes the geocentric position and velocity of an observer on - the surface of the earth or on a near-earth spacecraft. - TT Julian date. - Value of Delta T (= TT - UT1) at 'JdTt'. - Selection for accuracy - Data specifying the location of the observer - Position vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU. - Velocity vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU/day. - -
- 0 ... everything OK
- 1 ... invalid value of 'Accuracy'.
- 
- The final vectors are expressed in the GCRS. -
- - - Computes the total gravitational deflection of light for the observed object due to the major gravitating bodies in the solar system. - - TDB Julian date of observation. - Code for location of observer, determining whether the gravitational deflection due to the earth itself is applied. - Selection for accuracy - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar - system barycenter, referred to ICRS axes, components in AU. - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, corrected for gravitational deflection, components in AU. -
-    0 ... Everything OK
-  30 ... Error from function 'Ephemeris'; 
- > 30 ... Error from function 'MakeObject'.
- 
- This function valid for an observed body within the solar system as well as for a star. - - If 'Accuracy' is set to zero (full accuracy), three bodies (Sun, Jupiter, and Saturn) are - used in the calculation. If the reduced-accuracy option is set, only the Sun is used in the - calculation. In both cases, if the observer is not at the geocenter, the deflection due to the Earth is included. - - -
- - - Corrects position vector for the deflection of light in the gravitational field of an arbitrary body. - - Position vector of observed object, with respect to origin at observer - (or the geocenter), components in AU. - Position vector of observer (or the geocenter), with respect to origin at - solar system barycenter, components in AU. - Position vector of gravitating body, with respect to origin at solar system - barycenter, components in AU. - Reciprocal mass of gravitating body in solar mass units, that is, - Sun mass / body mass. - Position vector of observed object, with respect to origin at observer - (or the geocenter), corrected for gravitational deflection, components in AU. - This function valid for an observed body within the solar system as well as for a star. - - - - Compute the intermediate right ascension of the equinox at the input Julian date - - TDB Julian date. - Equinox selection flag: mean pr true - Selection for accuracy - Intermediate right ascension of the equinox, in hours (+ or -). If 'equinox' = 1 - (i.e true equinox), then the returned value is the equation of the origins. - - - - - Compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number - Day number - Fractional hour of the day - Computed Julian date. - This function makes no checks for a valid input calendar date. The input calendar date - must be Gregorian. The input time value can be based on any UT-like time scale (UTC, UT1, TT, etc.) - - output Julian date will have the same basis. - - - - Computes the geocentric position of a solar system body, as antedated for light-time. - - TDB Julian date of observation. - Structure containing the designation for thesolar system body - Position vector of observer (or the geocenter), with respect to origin - at solar system barycenter, referred to ICRS axes, components in AU. - First approximation to light-time, in days (can be set to 0.0 if unknown) - Selection for accuracy - Position vector of body, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Final light-time, in days. -
-    0 ... everything OK
-    1 ... algorithm failed to converge after 10 iterations
- ]]> 10 ... error is 10 + error from function 'SolarSystem'.
- 
- -
- - - Determines the angle of an object above or below the Earth's limb (horizon). - - Position vector of observed object, with respect to origin at - geocenter, components in AU. - Position vector of observer, with respect to origin at geocenter, - components in AU. - Angle of observed object above (+) or below (-) limb in degrees. - Nadir angle of observed object as a fraction of apparent radius of limb: 1.0 ... - below the limb; = 1.0 ... on the limb; ]]> 1.0 ... above the limb - The geometric limb is computed, assuming the Earth to be an airless sphere (no - refraction or oblateness is included). The observer can be on or above the Earth. - For an observer on the surface of the Earth, this function returns the approximate unrefracted - altitude. - - - - Computes the local place of a solar system body. - - TT Julian date for local place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Specifies accuracy level - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. - True distance from Earth to planet in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'; 
- ]]> 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the local place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for local place. delta_t (double) - Difference TT-UT1 at 'JdTt', in seconds of time. - catalog entry structure containing catalog data for the object in the ICRS - Structure specifying the position of the observer - Specifies accuracy level. - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Object name (50 characters maximum). - Three-character catalog identifier (e.g. HIP = Hipparcos, TY2 = Tycho-2) - Object number in the catalog. - Right ascension of the object (hours). - Declination of the object (degrees). - Proper motion in right ascension (milliarcseconds/year). - Proper motion in declination (milliarcseconds/year). - Parallax (milliarcseconds). - Radial velocity (kilometers/second). - CatEntry3 structure containing the input data - - - - - Makes a structure of type 'InSpace' - specifying the position and velocity of an observer situated - on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric velocity vector (x_dot, y_dot, z_dot) in km/s. - InSpace structure containing the position and velocity of an observer situated - on a near-Earth spacecraft - - - - - Makes a structure of type 'object' - specifying a celestial object - based on the input parameters. - - Type of object: 0 ... major planet, Sun, or Moon; 1 ... minor planet; - 2 ... object located outside the solar system (e.g. star, galaxy, nebula, etc.) - Body number: For 'Type' = 0: Mercury = 1,...,Pluto = 9, Sun = 10, Moon = 11; - For 'Type' = 1: minor planet numberFor 'Type' = 2: set to 0 (zero) - Name of the object (50 characters maximum). - Structure containing basic astrometric data for any celestial object - located outside the solar system; the catalog data for a star - Structure containing the object definition -
- 0 ... everything OK
- 1 ... invalid value of 'Type'
- 2 ... 'Number' out of range
- 
- -
- - - Makes a structure of type 'observer' - specifying the location of the observer. - - Integer code specifying location of observer: 0: observer at geocenter; - 1: observer on surface of earth; 2: observer on near-earth spacecraft - Structure containing data for an observer's location on the surface - of the Earth; used when 'Where' = 1 - Structure containing an observer's location on a near-Earth spacecraft; - used when 'Where' = 2 - Structure specifying the location of the observer -
- 0 ... everything OK
- 1 ... input value of 'Where' is out-of-range.
- 
- -
- - - Makes a structure of type 'observer' specifying an observer at the geocenter. - - Structure specifying the location of the observer at the geocenter - - - - - Makes a structure of type 'observer' specifying the position and velocity of an observer - situated on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric position vector (x, y, z) in km. - Structure containing the position and velocity of an observer - situated on a near-Earth spacecraft - Both input vectors are with respect to true equator and equinox of date. - - - - Makes a structure of type 'observer' specifying the location of and weather for an observer - on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) longitude in degrees; east positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an observer on - the surface of the Earth - - - - - Makes a structure of type 'on_surface' - specifying the location of and weather for an - observer on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) latitude in degrees; north positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an - observer on the surface of the Earth. - - - - - Compute the mean obliquity of the ecliptic. - - TDB Julian Date. - Mean obliquity of the ecliptic in arcseconds. - - - - - Computes the ICRS position of a star, given its apparent place at date 'JdTt'. - Proper motion, parallax and radial velocity are assumed to be zero. - - TT Julian date of apparent place. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - Specifies accuracy level - ICRS right ascension in hours. - ICRS declination in degrees. -
-    0 ... Everything OK
-    1 ... Iterative process did not converge after 30 iterations; 
- > 10 ... Error from function 'Vector2RaDec'
- > 20 ... Error from function 'AppStar'.
- 
- -
- - - Normalize angle into the range 0 angle (2 * pi). - - Input angle (radians). - The input angle, normalized as described above (radians). - - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB Julian date of epoch. - Flag determining 'direction' of transformation; direction = 0 - transformation applied, mean to true; direction != 0 inverse transformation applied, true to mean. - Selection for accuracy - Position vector, geocentric equatorial rectangular coordinates, referred to - mean equator and equinox of epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to - true equator and equinox of epoch. - Inverse transformation may be applied by setting flag 'direction' - - - - Returns the values for nutation in longitude and nutation in obliquity for a given TDB Julian date. - - TDB time in Julian centuries since J2000.0 - Selection for accuracy - Nutation in longitude in arcseconds. - Nutation in obliquity in arcseconds. - The nutation model selected depends upon the input value of 'Accuracy'. See notes below for important details. - - This function selects the nutation model depending first upon the input value of 'Accuracy'. - If 'Accuracy' = 0 (full accuracy), the IAU 2000A nutation model is used. If 'Accuracy' = 1 - a specially truncated (and therefore faster) version of IAU 2000A, called 'NU2000K' is used. - - - - - - Computes the apparent direction of a star or solar system body at a specified time - and in a specified coordinate system. - - TT Julian date for place. - Specifies the celestial object of interest - Specifies the location of the observer - Difference TT-UT1 at 'JdTt', in seconds of time. - Code specifying coordinate system of the output position. 0 ... GCRS or - "local GCRS"; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date; - 3 ... astrometric coordinates, i.e., without light deflection or aberration. - Selection for accuracy - Structure specifying object's place on the sky at time 'JdTt', - with respect to the specified output coordinate system - -
- = 0         ... No problems.
- = 1         ... invalid value of 'CoordSys'
- = 2         ... invalid value of 'Accuracy'
- = 3         ... Earth is the observed object, and the observer is either at the geocenter or on the Earth's surface (not permitted)
- > 10,  40  ... 10 + error from function 'Ephemeris'
- > 40,  50  ... 40 + error from function 'GeoPosVel'
- > 50,  70  ... 50 + error from function 'LightTime'
- > 70,  80  ... 70 + error from function 'GravDef'
- > 80,  90  ... 80 + error from function 'CioLocation'
- > 90,  100 ... 90 + error from function 'CioBasis'
- 
-
- Values of 'location->where' and 'CoordSys' dictate the various standard kinds of place: -
-     Location->Where = 0 and CoordSys = 1: apparent place
-     Location->Where = 1 and CoordSys = 1: topocentric place
-     Location->Where = 0 and CoordSys = 0: virtual place
-     Location->Where = 1 and CoordSys = 0: local place
-     Location->Where = 0 and CoordSys = 3: astrometric place
-     Location->Where = 1 and CoordSys = 3: topocentric astrometric place
- 
- Input value of 'DeltaT' is used only when 'Location->Where' equals 1 or 2 (observer is - on surface of Earth or in a near-Earth satellite). - - -
- - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of first epoch. - TDB Julian date of second epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of second epoch. -
- 0 ... everything OK
- 1 ... Precession not to or from J2000.0; 'JdTdb1' or 'JdTdb2' not 2451545.0.
- 
- One of the two epochs must be J2000.0. The coordinates are referred to the mean dynamical equator and equinox of the two respective epochs. -
- - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - Position vector at second epoch. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance in AU - Position vector, equatorial rectangular coordinates (AU). - - - - - Predicts the radial velocity of the observed object as it would be measured by spectroscopic means. - - Specifies the celestial object of interest - Geometric position vector of object with respect to observer, corrected for light-time, in AU. - Velocity vector of object with respect to solar system barycenter, in AU/day. - Velocity vector of observer with respect to solar system barycenter, in AU/day. - Distance from observer to geocenter, in AU. - Distance from observer to Sun, in AU. - Distance from object to Sun, in AU. - The observed radial velocity measure times the speed of light, in kilometers/second. - Radial velocity is here defined as the radial velocity measure (z) times the speed of light. - For a solar system body, it applies to a fictitious emitter at the center of the observed object, - assumed massless (no gravitational red shift), and does not in general apply to reflected light. - For stars, it includes all effects, such as gravitational red shift, contained in the catalog - barycentric radial velocity measure, a scalar derived from spectroscopy. Nearby stars with a known - kinematic velocity vector (obtained independently of spectroscopy) can be treated like - solar system objects. - - - - Computes atmospheric refraction in zenith distance. - - Structure containing observer's location. - 1 ... Use 'standard' atmospheric conditions; 2 ... Use atmospheric - parameters input in the 'Location' structure. - Observed zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. This function - can be used for planning observations or telescope pointing, but should not be used for the - reduction of precise observations. - - - - Computes the Greenwich apparent sidereal time, at Julian date 'JdHigh' + 'JdLow'. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Difference TT-UT1 at 'JdHigh'+'JdLow', in seconds of time. - 0 ... compute Greenwich mean sidereal time; 1 ... compute Greenwich apparent sidereal time - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - Greenwich apparent sidereal time, in hours. -
-          0 ... everything OK
-          1 ... invalid value of 'Accuracy'
-          2 ... invalid value of 'Method'
- > 10,  30 ... 10 + error from function 'CioRai'
- 
- The Julian date may be split at any point, but for highest precision, set 'JdHigh' - to be the integral part of the Julian date, and set 'JdLow' to be the fractional part. -
- - - Transforms a vector from one coordinate system to another with same origin and axes rotated about the z-axis. - - Angle of coordinate system rotation, positive counterclockwise when viewed from +z, in degrees. - Position vector. - Position vector expressed in new coordinate system rotated about z by 'angle'. - - - - - Converts angular quantities for stars to vectors. - - Catalog entry structure containing ICRS catalog data - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Computes the Terrestrial Time (TT) or Terrestrial Dynamical Time (TDT) Julian date corresponding - to a Barycentric Dynamical Time (TDB) Julian date. - - TDB Julian date. - TT Julian date. - Difference 'tdb_jd'-'tt_jd', in seconds. - Expression used in this function is a truncated form of a longer and more precise - series given in: Explanatory Supplement to the Astronomical Almanac, pp. 42-44 and p. 316. - The result is good to about 10 microseconds. - - - - This function rotates a vector from the terrestrial to the celestial system. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, referred to ITRF - axes (terrestrial system) in the normal case where 'option' = 0. - Position vector, geocentric equatorial rectangular coordinates, referred to GCRS - axes (celestial system) or with respect to the equator and equinox of date, depending on 'Option'. -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- 'x' = 'y' = 0 means no polar motion transformation. - - The 'option' flag only works for the equinox-based method. - -
- - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Structure containing observer's location - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial - rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular - coordinates, referred to true equator and equinox of date, components in AU/day. - - If reference meridian is Greenwich and st=0, 'pos' is effectively referred to equator and Greenwich. - This function ignores polar motion, unless the observer's longitude and latitude have been - corrected for it, and variation in the length of day (angular velocity of earth). - The true equator and equinox of date do not form an inertial system. Therefore, with respect - to an inertial system, the very small velocity component (several meters/day) due to the precession - and nutation of the Earth's axis is not accounted for here. - - - - - Computes the topocentric place of a solar system body. - - TT Julian date for topocentric place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Selection for accuracy - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'Place'.
-
- -
- - - Computes the topocentric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for topocentric place. - Difference TT-UT1 at 'JdTt', in seconds of time. - Catalog entry structure containing catalog data for the object in the ICRS - Specifies the position of the observer - Code specifying the relative accuracy of the output position. - Topocentric right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Topocentric declination in degrees, referred to true equator and equinox of date 'JdTt'. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'.
- 
- -
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option - TT Julian date, or year, of input catalog data. - An entry from the input catalog, with units as given in the struct definition - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - The transformed catalog entry, with units as given in the struct definition - -
- = 0 ... Everything OK.
- = 1 ... Invalid value of an input date for option 2 or 3 (see Note 1 below).
- 
- Also used to rotate catalog quantities on the dynamical equator and equinox of J2000.0 to the ICRS or vice versa. - 1. 'DateInCat' and 'DateNewCat' may be specified either as a Julian date (e.g., 2433282.5) or - a Julian year and fraction (e.g., 1950.0). Values less than 10000 are assumed to be years. - For 'TransformOption' = 2 or 'TransformOption' = 3, either 'DateInCat' or 'DateNewCat' must be 2451545.0 or - 2000.0 (J2000.0). For 'TransformOption' = 4 and 'TransformOption' = 5, 'DateInCat' and 'DateNewCat' are ignored. - 2. 'TransformOption' = 1 updates the star's data to account for the star's space motion between the first - and second dates, within a fixed reference frame. 'TransformOption' = 2 applies a rotation of the reference - frame corresponding to precession between the first and second dates, but leaves the star fixed in - space. 'TransformOption' = 3 provides both transformations. 'TransformOption' = 4 and 'TransformOption' = 5 provide a a - fixed rotation about very small angles (0.1 arcsecond) to take data from the dynamical system - of J2000.0 to the ICRS ('TransformOption' = 4) or vice versa ('TransformOption' = 5). -3. For 'TransformOption' = 1, input data can be in any fixed reference system. for 'TransformOption' = 2 or - 'TransformOption' = 3, this function assumes the input data is in the dynamical system and produces output - in the dynamical system. for 'TransformOption' = 4, the input data must be on the dynamical equator and - equinox of J2000.0. for 'TransformOption' = 5, the input data must be in the ICRS. -4. This function cannot be properly used to bring data from old star catalogs into the - modern system, because old catalogs were compiled using a set of constants that are incompatible - with modern values. In particular, it should not be used for catalogs whose positions and - proper motions were derived by assuming a precession constant significantly different from - the value implicit in function 'precession'. -
- - - Convert Hipparcos catalog data at epoch J1991.25 to epoch J2000.0, for use within NOVAS. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members - having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. Both input and - output data is in the ICRS. - - 1. Input (Hipparcos catalog) epoch and units: - - Epoch: J1991.25 - Right ascension (RA): degrees - Declination (Dec): degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second (not in catalog) - - - - 2. Output (modified Hipparcos) epoch and units: - - Epoch: J2000.0 - Right ascension: hours - Declination: degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second - > - - - - - - Converts a vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - Right ascension in hours. - Declination in degrees. - -
- = 0 ... Everything OK.
- = 1 ... All vector components are zero; 'Ra' and 'Dec' are indeterminate.
- = 2 ... Both Pos[0] and Pos[1] are zero, but Pos[2] is nonzero; 'Ra' is indeterminate.
- 
- -
- - - Compute the virtual place of a planet or other solar system body. - - TT Julian date for virtual place. - structure containing the body designation for the solar system body( - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - True distance from Earth to planet in AU. - -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Type' in structure 'SsBody'.
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the virtual place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for virtual place. - catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - -
- =  0 ... Everything OK.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'
- 
- -
- - - Corrects a vector in the ITRF (rotating Earth-fixed system) for polar motion, and also corrects - the longitude origin (by a tiny amount) to the Terrestrial Intermediate Origin (TIO). - - TT or UT1 Julian date. - Conventionally-defined X coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRF axes. - Position vector, geocentric equatorial rectangular coordinates, - referred to true equator and TIO. - - - - - Get path to a system folder - - SUpply null / nothing to use "current user" - returned string folder path - Folder Number from CSIDL enumeration e.g. CSIDL_PROGRAM_FILES_COMMONX86 = 44 = 0x2c - Indicates whether the folder should be created if it does not already exist. If this value is nonzero, - the folder is created. If this value is zero, the folder is not created - TRUE if successful; otherwise, FALSE. - - - - - Loads a library DLL - - Full path to the file to load - A pointer to the loaded DLL image - This is a wrapper for the Windows kernel32 function LoadLibraryA - - - - Unloads a library DLL - - Pointer to the loaded library returned by the LoadLibrary function. - True or false depending on whether the library was released. - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - NOVAS31: Class presenting the contents of the USNO NOVAS 3.1 library. - NOVAS was developed by the Astronomical Applications department of the United States Naval - Observatory. - - If you wish to explore or utilise NOVAS3.1 please see USNO's extensive help document "NOVAS 3.1 Users Guide" - (NOVAS C3.1 Guide.pdf) included in the ASCOM Platform Docs start menu folder. The latest revision is also available on the USNO web site at - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/novas - in the "C Edition of NOVAS" link. - If you use NOVAS, please send an e-mail through this page: - http://www.usno.navy.mil/help/astronomy-help as this provides evidence to USNO that justifies further - improvements and developments of NOVAS capabilities. - - - - - - Creates a new instance of the NOVAS31 component - - Thrown if the NOVAS31 support library DLL cannot be loaded - - - - - Cleans up the NOVAS3 object and releases its open file handle on the JPL planetary ephemeris file - - - - - - Get position and velocity of target with respect to the centre object. - - Two-element array containing the Julian date, which may be split any way (although the first - element is usually the "integer" part, and the second element is the "fractional" part). Julian date is in the - TDB or "T_eph" time scale. - Target object - Centre object - Position vector array of target relative to center, measured in AU. - Velocity vector array of target relative to center, measured in AU/day. -
- 0   ...everything OK.
- 1,2 ...error returned from State.
-
- This function accesses the JPL planetary ephemeris to give the position and velocity of the target - object with respect to the center object. -
- - - Produces the Cartesian heliocentric equatorial coordinates of the asteroid for the J2000.0 epoch - coordinate system from a set of Chebyshev polynomials read from a file. - - The number of the asteroid for which the position in desired. - The name of the asteroid. - The Julian date on which to find the position and velocity. -
- = 0 ( No error )
- = 1 ( Memory allocation error )
- = 2 ( Mismatch between asteroid name and number )
- = 3 ( Julian date out of bounds )
- = 4 ( Cannot find Chebyshev polynomial file )
- 
- - 6-element array of double containing position and velocity vector values. - The file name of the asteroid is taken from the name given. It is assumed that the name - is all in lower case characters. - - This routine will search in the application's current directory for a file of Chebyshev - polynomial coefficients whose name is based on the provided Name parameter: Name.chby - - Further information on using NOVAS with minor planet data is given here: - http://www.usno.navy.mil/USNO/astronomical-applications/software-products/usnoae98 - -
- - - Interface between the JPL direct-access solar system ephemerides and NOVAS-C. - - Julian date of the desired time, on the TDB time scale. - Body identification number for the solar system object of interest; - Mercury = 1, ..., Pluto= 9, Sun= 10, Moon = 11. - Origin code; solar system barycenter= 0, center of mass of the Sun = 1, center of Earth = 2. - Position vector of 'body' at tjd; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of 'body' at tjd; equatorial rectangular system referred to the ICRS. - Always returns 0 - - - - - Read and interpolate the JPL planetary ephemeris file. - - 2-element Julian date (TDB) at which interpolation is wanted. Any combination of jed[0]+jed[1] which falls within the time span on the file is a permissible epoch. See Note 1 below. - The requested body to get data for from the ephemeris file. - The barycentric position vector array of the requested object, in AU. (If target object is the Moon, then the vector is geocentric.) - The barycentric velocity vector array of the requested object, in AU/Day. - -
- 0 ...everything OK
- 1 ...error reading ephemeris file
- 2 ...epoch out of range.
- 
- - The target number designation of the astronomical bodies is: -
-         = 0: Mercury,               1: Venus, 
-         = 2: Earth-Moon barycenter, 3: Mars, 
-         = 4: Jupiter,               5: Saturn, 
-         = 6: Uranus,                7: Neptune, 
-         = 8: Pluto,                 9: geocentric Moon, 
-         =10: Sun.
- 
- - NOTE 1. For ease in programming, the user may put the entire epoch in jed[0] and set jed[1] = 0. - For maximum interpolation accuracy, set jed[0] = the most recent midnight at or before interpolation epoch, - and set jed[1] = fractional part of a day elapsed between jed[0] and epoch. As an alternative, it may prove - convenient to set jed[0] = some fixed epoch, such as start of the integration and jed[1] = elapsed interval - between then and epoch. - -
-
- - - Corrects position vector for aberration of light. Algorithm includes relativistic terms. - - Position vector, referred to origin at center of mass of the Earth, components in AU. - Velocity vector of center of mass of the Earth, referred to origin at solar system barycenter, components in AU/day. - Light time from object to Earth in days. - Position vector, referred to origin at center of mass of the Earth, corrected for aberration, components in AU - If 'lighttime' = 0 on input, this function will compute it. - - - - Compute the apparent place of a planet or other solar system body. - - TT Julian date for apparent place. - Pointer to structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the apparent place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for apparent place. - Catalog entry structure containing catalog data forthe object in the ICRS - Code specifying the relative accuracy of the output position. - Apparent right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Apparent declination in degrees, referred to true equator and equinox of date 'JdTt'. - -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Compute the astrometric place of a planet or other solar system body. - - TT Julian date for astrometric place. - structure containing the body designation for the solar system body - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). - True distance from Earth to planet in AU. - -
-    0 ... Everything OK
-    1 ... Invalid value of 'Type' in structure 'SsBody'
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the astrometric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for astrometric place. - Catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Astrometric right ascension in hours (referred to the ICRS, without light deflection or aberration). - Astrometric declination in degrees (referred to the ICRS, without light deflection or aberration). -
-    0 ... Everything OK
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Move the origin of coordinates from the barycenter of the solar system to the observer (or the geocenter); i.e., this function accounts for parallax (annual+geocentric or justannual). - - Position vector, referred to origin at solar system barycenter, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Position vector, referred to origin at center of mass of the Earth, components in AU. - Light time from object to Earth in days. - - - - - This function will compute a date on the Gregorian calendar given the Julian date. - - Julian date. - Year - Month number - day number - Fractional hour of the day - - - - - This function rotates a vector from the celestial to the terrestrial system. Specifically, it transforms a vector in the - GCRS (a local space-fixed system) to the ITRS (a rotating earth-fixed system) by applying rotations for the GCRS-to-dynamical - frame tie, precession, nutation, Earth rotation, and polar motion. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. (See note 2 below) - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRS pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRS pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to GCRS axes (celestial system) or with respect to - the equator and equinox of date, depending on 'option'. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRS axes (terrestrial system). -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- Note 1: 'x' = 'y' = 0 means no polar motion transformation. - - Note2: 'option' = 1 only works for the equinox-based method. - -
- - - This function allows for the specification of celestial pole offsets for high-precision applications. Each set of offsets is a correction to the modeled position of the pole for a specific date, derived from observations and published by the IERS. - - TDB or TT Julian date for pole offsets. - Type of pole offset. 1 for corrections to angular coordinates of modeled pole referred to mean ecliptic of date, that is, delta-delta-psi and delta-delta-epsilon. 2 for corrections to components of modeled pole unit vector referred to GCRS axes, that is, dx and dy. - Value of celestial pole offset in first coordinate, (delta-delta-psi or dx) in milliarcseconds. - Value of celestial pole offset in second coordinate, (delta-delta-epsilon or dy) in milliarcseconds. -
- 0 ... Everything OK
- 1 ... Invalid value of 'Type'.
- 
- -
- - - Calaculate an array of CIO RA values around a given date - - TDB Julian date. - Number of Julian dates and right ascension values requested (not less than 2 or more than 20). - An arraylist of RaOfCIO structures containing a time series of the right ascension of the - Celestial Intermediate Origin (CIO) with respect to the GCRS. -
- 0 ... everything OK
- 1 ... error opening the 'cio_ra.bin' file
- 2 ... 'JdTdb' not in the range of the CIO file; 
- 3 ... 'NPts' out of range
- 4 ... unable to allocate memory for the internal 't' array; 
- 5 ... unable to allocate memory for the internal 'ra' array; 
- 6 ... 'JdTdb' is too close to either end of the CIO file; unable to put 'NPts' data points into the output object.
- 
- - - Given an input TDB Julian date and the number of data points desired, this function returns a set of - Julian dates and corresponding values of the GCRS right ascension of the celestial intermediate origin (CIO). - The range of dates is centered (at least approximately) on the requested date. The function obtains - the data from an external data file. - How to create and retrieve values from the arraylist - - Dim CioList As New ArrayList, Nov3 As New ASCOM.Astrometry.NOVAS3 - - rc = Nov3.CioArray(2455251.5, 20, CioList) ' Get 20 values around date 00:00:00 February 24th 2010 - MsgBox("Nov3 RC= " rc) - - For Each CioA As ASCOM.Astrometry.RAOfCio In CioList - MsgBox("CIO Array " CioA.JdTdb " " CioA.RACio) - Next - - - -
- - - Compute the orthonormal basis vectors of the celestial intermediate system. - - TDB Julian date of epoch. - Right ascension of the CIO at epoch (hours). - Reference system in which right ascension is given. 1 ... GCRS; 2 ... True equator and equinox of date. - Accuracy - Unit vector toward the CIO, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward the y-direction, equatorial rectangular coordinates, referred to the GCRS. - Unit vector toward north celestial pole (CIP), equatorial rectangular coordinates, referred to the GCRS. -
- 0 ... everything OK
- 1 ... invalid value of input variable 'RefSys'.
- 
- - To compute the orthonormal basis vectors, with respect to the GCRS (geocentric ICRS), of the celestial - intermediate system defined by the celestial intermediate pole (CIP) (in the z direction) and - the celestial intermediate origin (CIO) (in the x direction). A TDB Julian date and the - right ascension of the CIO at that date is required as input. The right ascension of the CIO - can be with respect to either the GCRS origin or the true equinox of date -- different algorithms - are used in the two cases. -
- - - Returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension - - TDB Julian date. - Selection for accuracy - Right ascension of the CIO, in hours. - Reference system in which right ascension is given -
-    0 ... everything OK
-    1 ... unable to allocate memory for the 'cio' array
- > 10 ... 10 + the error code from function 'CioArray'.
- 
- This function returns the location of the celestial intermediate origin (CIO) for a given Julian date, as a right ascension with respect to either the GCRS (geocentric ICRS) origin or the true equinox of date. The CIO is always located on the true equator (= intermediate equator) of date. -
- - - Computes the true right ascension of the celestial intermediate origin (CIO) at a given TT Julian date. This is -(equation of the origins). - - TT Julian date - Selection for accuracy - Right ascension of the CIO, with respect to the true equinox of date, in hours (+ or -). - -
-   0  ... everything OK
-   1  ... invalid value of 'Accuracy'
- > 10 ... 10 + the error code from function 'CioLocation'
- > 20 ... 20 + the error code from function 'CioBasis'.
- 
- -
- - - Returns the difference in light-time, for a star, between the barycenter of the solar system and the observer (or the geocenter). - - Position vector of star, with respect to origin at solar system barycenter. - Position vector of observer (or the geocenter), with respect to origin at solar system barycenter, components in AU. - Difference in light time, in the sense star to barycenter minus star to earth, in days. - - Alternatively, this function returns the light-time from the observer (or the geocenter) to a point on a - light ray that is closest to a specific solar system body. For this purpose, 'Pos1' is the position - vector toward observed object, with respect to origin at observer (or the geocenter); 'PosObs' is - the position vector of solar system body, with respect to origin at observer (or the geocenter), - components in AU; and the returned value is the light time to point on line defined by 'Pos1' - that is closest to solar system body (positive if light passes body before hitting observer, i.e., if - 'Pos1' is within 90 degrees of 'PosObs'). - - - - - Converts an ecliptic position vector to an equatorial position vector. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system selection. 0 ... mean equator and equinox of date; 1 ... true equator and equinox of date; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified ecliptic and equinox of date. If 'CoordSys' = 2, 'pos1' must be on mean ecliptic and equinox of J2000.0; see Note 1 below. - Position vector, referred to specified equator and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert an ecliptic vector (mean ecliptic and equinox of J2000.0 only) to an ICRS vector, - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the output from this case, all vectors are assumed to be with respect to a dynamical system. - -
- - - Compute the "complementary terms" of the equation of the equinoxes consistent with IAU 2000 resolutions. - - High-order part of TT Julian date. - Low-order part of TT Julian date. - Selection for accuracy - Complementary terms, in radians. - - 1. The series used in this function was derived from Series from IERS Conventions (2003), Chapter 5, Table 5.2C. - This same series was also adopted for use in the IAU's Standards of Fundamental Astronomy (SOFA) software (i.e., subroutine - eect00.for and function eect00.c). - 2. The low-accuracy series used in this function is a simple implementation derived from the first reference, in which terms - smaller than 2 microarcseconds have been omitted. - 3. This function is based on NOVAS Fortran routine 'eect2000', with the low-accuracy formula taken from NOVAS Fortran routine 'etilt'. - - - - - Retrieves the position and velocity of a solar system body from a fundamental ephemeris. - - TDB Julian date split into two parts, where the sum jd[0] + jd[1] is the TDB Julian date. - Structure containing the designation of the body of interest - Origin code; solar system barycenter = 0, center of mass of the Sun = 1. - Slection for accuracy - Position vector of the body at 'Jd'; equatorial rectangular coordinates in AU referred to the ICRS. - Velocity vector of the body at 'Jd'; equatorial rectangular system referred to the mean equator and equinox of the ICRS, in AU/Day. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Origin'
-    2 ... Invalid value of 'Type' in 'CelObj'; 
-    3 ... Unable to allocate memory
- 10+n ... where n is the error code from 'SolarSystem'; 
- 20+n ... where n is the error code from 'ReadEph'.
- 
- It is recommended that the input structure 'cel_obj' be created using function 'MakeObject' in file novas.c. -
- - - To convert right ascension and declination to ecliptic longitude and latitude. - - TT Julian date of equator, equinox, and ecliptic used for coordinates. - Coordinate system: 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Right ascension in hours, referred to specified equator and equinox of date. - Declination in degrees, referred to specified equator and equinox of date. - Ecliptic longitude in degrees, referred to specified ecliptic and equinox of date. - Ecliptic latitude in degrees, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- - To convert ICRS RA and dec to ecliptic coordinates (mean ecliptic and equinox of J2000.0), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. - Except for the input to this case, all input coordinates are dynamical. - -
- - - Converts an equatorial position vector to an ecliptic position vector. - - TT Julian date of equator, equinox, and ecliptic used for - Coordinate system selection. 0 ... mean equator and equinox of date 'JdTt'; 1 ... true equator and equinox of date 'JdTt'; 2 ... ICRS - Selection for accuracy - Position vector, referred to specified equator and equinox of date. - Position vector, referred to specified ecliptic and equinox of date. -
- 0 ... everything OK
- 1 ... invalid value of 'CoordSys'
- 
- To convert an ICRS vector to an ecliptic vector (mean ecliptic and equinox of J2000.0 only), - set 'CoordSys' = 2; the value of 'JdTt' can be set to anything, since J2000.0 is assumed. Except for - the input to this case, all vectors are assumed to be with respect to a dynamical system. -
- - - Converts ICRS right ascension and declination to galactic longitude and latitude. - - ICRS right ascension in hours. - ICRS declination in degrees. - Galactic longitude in degrees. - Galactic latitude in degrees. - - - - - Transforms topocentric right ascension and declination to zenith distance and azimuth. - - UT1 Julian date. - Difference TT-UT1 at 'jd_ut1', in seconds. - Selection for accuracy - onventionally-defined x coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Conventionally-defined y coordinate of celestial intermediate pole with respect to ITRS reference pole, in arcseconds. - Structure containing observer's location - Topocentric right ascension of object of interest, in hours, referred to true equator and equinox of date. - Topocentric declination of object of interest, in degrees, referred to true equator and equinox of date. - Refraction option. 0 ... no refraction; 1 ... include refraction, using 'standard' atmospheric conditions; - 2 ... include refraction, using atmospheric parametersinput in the 'Location' structure. - Topocentric zenith distance in degrees, affected by refraction if 'ref_option' is non-zero. - Topocentric azimuth (measured east from north) in degrees. - Topocentric right ascension of object of interest, in hours, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - Topocentric declination of object of interest, in degrees, referred to true equator and - equinox of date, affected by refraction if 'ref_option' is non-zero. - This function transforms topocentric right ascension and declination to zenith distance and azimuth. - It uses a method that properly accounts for polar motion, which is significant at the sub-arcsecond level. - This function can also adjust coordinates for atmospheric refraction. - - - - Returns the value of the Earth Rotation Angle (theta) for a given UT1 Julian date. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - The Earth Rotation Angle (theta) in degrees. - The expression used is taken from the note to IAU Resolution B1.8 of 2000. 1. The algorithm used - here is equivalent to the canonical theta = 0.7790572732640 + 1.00273781191135448 * t, where t is the time - in days from J2000 (t = JdHigh + JdLow - T0), but it avoids many two-PI 'wraps' that - decrease precision (adopted from SOFA Fortran routine iau_era00; see also expression at top - of page 35 of IERS Conventions (1996)). - - - - Computes quantities related to the orientation of the Earth's rotation axis at Julian date 'JdTdb'. - - TDB Julian Date. - Selection for accuracy - Mean obliquity of the ecliptic in degrees at 'JdTdb'. - True obliquity of the ecliptic in degrees at 'JdTdb'. - Equation of the equinoxes in seconds of time at 'JdTdb'. - Nutation in longitude in arcseconds at 'JdTdb'. - Nutation in obliquity in arcseconds at 'JdTdb'. - Values of the celestial pole offsets 'PSI_COR' and 'EPS_COR' are set using function 'cel_pole', - if desired. See the prolog of 'cel_pole' for details. - - - - To transform a vector from the dynamical reference system to the International Celestial Reference System (ICRS), or vice versa. - - Position vector, equatorial rectangular coordinates. - Set 'direction' 0 for dynamical to ICRS transformation. Set 'direction' =]]> 0 for - ICRS to dynamical transformation. - Position vector, equatorial rectangular coordinates. - - - - - To compute the fundamental arguments (mean elements) of the Sun and Moon. - - TDB time in Julian centuries since J2000.0 - Double array of fundamental arguments - - Fundamental arguments, in radians: -
-   a[0] = l (mean anomaly of the Moon)
-   a[1] = l' (mean anomaly of the Sun)
-   a[2] = F (mean argument of the latitude of the Moon)
-   a[3] = D (mean elongation of the Moon from the Sun)
-   a[4] = a[4] (mean longitude of the Moon's ascending node);
-                from Simon section 3.4(b.3),
-                precession = 5028.8200 arcsec/cy)
- 
-
-
- - - Converts GCRS right ascension and declination to coordinates with respect to the equator of date (mean or true). - - TT Julian date of equator to be used for output coordinates. - Coordinate system selection for output coordinates.; 0 ... mean equator and - equinox of date; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date - Selection for accuracy - GCRS right ascension in hours. - GCRS declination in degrees. - Right ascension in hours, referred to specified equator and right ascension origin of date. - Declination in degrees, referred to specified equator of date. - -
-    0 ... everything OK
- >  0 ... error from function 'Vector2RaDec'' 
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
>
- For coordinates with respect to the true equator of date, the origin of right ascension can be either the true equinox or the celestial intermediate origin (CIO). - This function only supports the CIO-based method. -
- - - This function computes the geocentric position and velocity of an observer on - the surface of the earth or on a near-earth spacecraft. - TT Julian date. - Value of Delta T (= TT - UT1) at 'JdTt'. - Selection for accuracy - Data specifying the location of the observer - Position vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU. - Velocity vector of observer, with respect to origin at geocenter, - referred to GCRS axes, components in AU/day. - -
- 0 ... everything OK
- 1 ... invalid value of 'Accuracy'.
- 
- The final vectors are expressed in the GCRS. -
- - - Computes the total gravitational deflection of light for the observed object due to the major gravitating bodies in the solar system. - - TDB Julian date of observation. - Code for location of observer, determining whether the gravitational deflection due to the earth itself is applied. - Selection for accuracy - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Position vector of observer (or the geocenter), with respect to origin at solar - system barycenter, referred to ICRS axes, components in AU. - Position vector of observed object, with respect to origin at observer (or the geocenter), - referred to ICRS axes, corrected for gravitational deflection, components in AU. -
-    0 ... Everything OK
-  30 ... Error from function 'Ephemeris'; 
- > 30 ... Error from function 'MakeObject'.
- 
- This function valid for an observed body within the solar system as well as for a star. - - If 'Accuracy' is set to zero (full accuracy), three bodies (Sun, Jupiter, and Saturn) are - used in the calculation. If the reduced-accuracy option is set, only the Sun is used in the - calculation. In both cases, if the observer is not at the geocenter, the deflection due to the Earth is included. - - -
- - - Corrects position vector for the deflection of light in the gravitational field of an arbitrary body. - - Position vector of observed object, with respect to origin at observer - (or the geocenter), components in AU. - Position vector of observer (or the geocenter), with respect to origin at - solar system barycenter, components in AU. - Position vector of gravitating body, with respect to origin at solar system - barycenter, components in AU. - Reciprocal mass of gravitating body in solar mass units, that is, - Sun mass / body mass. - Position vector of observed object, with respect to origin at observer - (or the geocenter), corrected for gravitational deflection, components in AU. - This function valid for an observed body within the solar system as well as for a star. - - - - Compute the intermediate right ascension of the equinox at the input Julian date - - TDB Julian date. - Equinox selection flag: mean pr true - Selection for accuracy - Intermediate right ascension of the equinox, in hours (+ or -). If 'equinox' = 1 - (i.e true equinox), then the returned value is the equation of the origins. - - - - - Compute the Julian date for a given calendar date (year, month, day, hour). - - Year number - Month number - Day number - Fractional hour of the day - Computed Julian date. - This function makes no checks for a valid input calendar date. The input calendar date - must be Gregorian. The input time value can be based on any UT-like time scale (UTC, UT1, TT, etc.) - - output Julian date will have the same basis. - - - - Computes the geocentric position of a solar system body, as antedated for light-time. - - TDB Julian date of observation. - Structure containing the designation for thesolar system body - Position vector of observer (or the geocenter), with respect to origin - at solar system barycenter, referred to ICRS axes, components in AU. - First approximation to light-time, in days (can be set to 0.0 if unknown) - Selection for accuracy - Position vector of body, with respect to origin at observer (or the geocenter), - referred to ICRS axes, components in AU. - Final light-time, in days. -
-    0 ... everything OK
-    1 ... algorithm failed to converge after 10 iterations
- ]]> 10 ... error is 10 + error from function 'SolarSystem'.
- 
- -
- - - Determines the angle of an object above or below the Earth's limb (horizon). - - Position vector of observed object, with respect to origin at - geocenter, components in AU. - Position vector of observer, with respect to origin at geocenter, - components in AU. - Angle of observed object above (+) or below (-) limb in degrees. - Nadir angle of observed object as a fraction of apparent radius of limb: 1.0 ... - below the limb; = 1.0 ... on the limb; ]]> 1.0 ... above the limb - The geometric limb is computed, assuming the Earth to be an airless sphere (no - refraction or oblateness is included). The observer can be on or above the Earth. - For an observer on the surface of the Earth, this function returns the approximate unrefracted - altitude. - - - - Computes the local place of a solar system body. - - TT Julian date for local place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Specifies accuracy level - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. - True distance from Earth to planet in AU. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'; 
- ]]> 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the local place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for local place. delta_t (double) - Difference TT-UT1 at 'JdTt', in seconds of time. - catalog entry structure containing catalog data for the object in the ICRS - Structure specifying the position of the observer - Specifies accuracy level. - Local right ascension in hours, referred to the 'local GCRS'. - Local declination in degrees, referred to the 'local GCRS'. -
-    0 ... Everything OK
-    1 ... Invalid value of 'Where' in structure 'Location'
- > 10 ... Error code from function 'MakeObject'
- > 20 ... Error code from function 'Place'.
- 
- -
- - - Create a structure of type 'cat_entry' containing catalog data for a star or "star-like" object. - - Object name (50 characters maximum). - Three-character catalog identifier (e.g. HIP = Hipparcos, TY2 = Tycho-2) - Object number in the catalog. - Right ascension of the object (hours). - Declination of the object (degrees). - Proper motion in right ascension (milliarcseconds/year). - Proper motion in declination (milliarcseconds/year). - Parallax (milliarcseconds). - Radial velocity (kilometers/second). - CatEntry3 structure containing the input data - - - - - Makes a structure of type 'InSpace' - specifying the position and velocity of an observer situated - on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric velocity vector (x_dot, y_dot, z_dot) in km/s. - InSpace structure containing the position and velocity of an observer situated - on a near-Earth spacecraft - - - - - Makes a structure of type 'object' - specifying a celestial object - based on the input parameters. - - Type of object: 0 ... major planet, Sun, or Moon; 1 ... minor planet; - 2 ... object located outside the solar system (e.g. star, galaxy, nebula, etc.) - Body number: For 'Type' = 0: Mercury = 1,...,Pluto = 9, Sun = 10, Moon = 11; - For 'Type' = 1: minor planet numberFor 'Type' = 2: set to 0 (zero) - Name of the object (50 characters maximum). - Structure containing basic astrometric data for any celestial object - located outside the solar system; the catalog data for a star - Structure containing the object definition -
- 0 ... everything OK
- 1 ... invalid value of 'Type'
- 2 ... 'Number' out of range
- 
- -
- - - Makes a structure of type 'observer' - specifying the location of the observer. - - Integer code specifying location of observer: 0: observer at geocenter; - 1: observer on surface of earth; 2: observer on near-earth spacecraft - Structure containing data for an observer's location on the surface - of the Earth; used when 'Where' = 1 - Structure containing an observer's location on a near-Earth spacecraft; - used when 'Where' = 2 - Structure specifying the location of the observer -
- 0 ... everything OK
- 1 ... input value of 'Where' is out-of-range.
- 
- -
- - - Makes a structure of type 'observer' specifying an observer at the geocenter. - - Structure specifying the location of the observer at the geocenter - - - - - Makes a structure of type 'observer' specifying the position and velocity of an observer - situated on a near-Earth spacecraft. - - Geocentric position vector (x, y, z) in km. - Geocentric position vector (x, y, z) in km. - Structure containing the position and velocity of an observer - situated on a near-Earth spacecraft - Both input vectors are with respect to true equator and equinox of date. - - - - Makes a structure of type 'observer' specifying the location of and weather for an observer - on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) longitude in degrees; east positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an observer on - the surface of the Earth - - - - - Makes a structure of type 'on_surface' - specifying the location of and weather for an - observer on the surface of the Earth. - - Geodetic (ITRS) latitude in degrees; north positive. - Geodetic (ITRS) latitude in degrees; north positive. - Height of the observer (meters). - Temperature (degrees Celsius). - Atmospheric pressure (millibars). - Structure containing the location of and weather for an - observer on the surface of the Earth. - - - - - Compute the mean obliquity of the ecliptic. - - TDB Julian Date. - Mean obliquity of the ecliptic in arcseconds. - - - - - Computes the ICRS position of a star, given its apparent place at date 'JdTt'. - Proper motion, parallax and radial velocity are assumed to be zero. - - TT Julian date of apparent place. - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - Specifies accuracy level - ICRS right ascension in hours. - ICRS declination in degrees. -
-    0 ... Everything OK
-    1 ... Iterative process did not converge after 30 iterations; 
- > 10 ... Error from function 'Vector2RaDec'
- > 20 ... Error from function 'AppStar'.
- 
- -
- - - Normalize angle into the range 0 angle (2 * pi). - - Input angle (radians). - The input angle, normalized as described above (radians). - - - - - Nutates equatorial rectangular coordinates from mean equator and equinox of epoch to true equator and equinox of epoch. - - TDB Julian date of epoch. - Flag determining 'direction' of transformation; direction = 0 - transformation applied, mean to true; direction != 0 inverse transformation applied, true to mean. - Selection for accuracy - Position vector, geocentric equatorial rectangular coordinates, referred to - mean equator and equinox of epoch. - Position vector, geocentric equatorial rectangular coordinates, referred to - true equator and equinox of epoch. - Inverse transformation may be applied by setting flag 'direction' - - - - Returns the values for nutation in longitude and nutation in obliquity for a given TDB Julian date. - - TDB time in Julian centuries since J2000.0 - Selection for accuracy - Nutation in longitude in arcseconds. - Nutation in obliquity in arcseconds. - The nutation model selected depends upon the input value of 'Accuracy'. See notes below for important details. - - This function selects the nutation model depending first upon the input value of 'Accuracy'. - If 'Accuracy' = 0 (full accuracy), the IAU 2000A nutation model is used. If 'Accuracy' = 1 - a specially truncated (and therefore faster) version of IAU 2000A, called 'NU2000K' is used. - - - - - - Computes the apparent direction of a star or solar system body at a specified time - and in a specified coordinate system. - - TT Julian date for place. - Specifies the celestial object of interest - Specifies the location of the observer - Difference TT-UT1 at 'JdTt', in seconds of time. - Code specifying coordinate system of the output position. 0 ... GCRS or - "local GCRS"; 1 ... true equator and equinox of date; 2 ... true equator and CIO of date; - 3 ... astrometric coordinates, i.e., without light deflection or aberration. - Selection for accuracy - Structure specifying object's place on the sky at time 'JdTt', - with respect to the specified output coordinate system - -
- = 0         ... No problems.
- = 1         ... invalid value of 'CoordSys'
- = 2         ... invalid value of 'Accuracy'
- = 3         ... Earth is the observed object, and the observer is either at the geocenter or on the Earth's surface (not permitted)
- > 10,  40  ... 10 + error from function 'Ephemeris'
- > 40,  50  ... 40 + error from function 'GeoPosVel'
- > 50,  70  ... 50 + error from function 'LightTime'
- > 70,  80  ... 70 + error from function 'GravDef'
- > 80,  90  ... 80 + error from function 'CioLocation'
- > 90,  100 ... 90 + error from function 'CioBasis'
- 
-
- Values of 'location->where' and 'CoordSys' dictate the various standard kinds of place: -
-     Location->Where = 0 and CoordSys = 1: apparent place
-     Location->Where = 1 and CoordSys = 1: topocentric place
-     Location->Where = 0 and CoordSys = 0: virtual place
-     Location->Where = 1 and CoordSys = 0: local place
-     Location->Where = 0 and CoordSys = 3: astrometric place
-     Location->Where = 1 and CoordSys = 3: topocentric astrometric place
- 
- Input value of 'DeltaT' is used only when 'Location->Where' equals 1 or 2 (observer is - on surface of Earth or in a near-Earth satellite). - - -
- - - Precesses equatorial rectangular coordinates from one epoch to another. - - TDB Julian date of first epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of first epoch. - TDB Julian date of second epoch. See remarks below. - Position vector, geocentric equatorial rectangular coordinates, referred to mean dynamical equator and equinox of second epoch. -
- 0 ... everything OK
- 1 ... Precession not to or from J2000.0; 'JdTdb1' or 'JdTdb2' not 2451545.0.
- 
- One of the two epochs must be J2000.0. The coordinates are referred to the mean dynamical equator and equinox of the two respective epochs. -
- - - Applies proper motion, including foreshortening effects, to a star's position. - - TDB Julian date of first epoch. - Position vector at first epoch. - Velocity vector at first epoch. - TDB Julian date of second epoch. - Position vector at second epoch. - - - - - Converts equatorial spherical coordinates to a vector (equatorial rectangular coordinates). - - Right ascension (hours). - Declination (degrees). - Distance in AU - Position vector, equatorial rectangular coordinates (AU). - - - - - Predicts the radial velocity of the observed object as it would be measured by spectroscopic means. - - Specifies the celestial object of interest - Geometric position vector of object with respect to observer, corrected for light-time, in AU. - Velocity vector of object with respect to solar system barycenter, in AU/day. - Velocity vector of observer with respect to solar system barycenter, in AU/day. - Distance from observer to geocenter, in AU. - Distance from observer to Sun, in AU. - Distance from object to Sun, in AU. - The observed radial velocity measure times the speed of light, in kilometers/second. - Radial velocity is here defined as the radial velocity measure (z) times the speed of light. - For a solar system body, it applies to a fictitious emitter at the center of the observed object, - assumed massless (no gravitational red shift), and does not in general apply to reflected light. - For stars, it includes all effects, such as gravitational red shift, contained in the catalog - barycentric radial velocity measure, a scalar derived from spectroscopy. Nearby stars with a known - kinematic velocity vector (obtained independently of spectroscopy) can be treated like - solar system objects. - - - - Computes atmospheric refraction in zenith distance. - - Structure containing observer's location. - 1 ... Use 'standard' atmospheric conditions; 2 ... Use atmospheric - parameters input in the 'Location' structure. - Observed zenith distance, in degrees. - Atmospheric refraction, in degrees. - This version computes approximate refraction for optical wavelengths. This function - can be used for planning observations or telescope pointing, but should not be used for the - reduction of precise observations. - - - - Computes the Greenwich sidereal time, either mean or apparent, at Julian date 'JdHigh' + 'JdLow'. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Difference TT-UT1 at 'JdHigh'+'JdLow', in seconds of time. - 0 ... compute Greenwich mean sidereal time; 1 ... compute Greenwich apparent sidereal time - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - Greenwich apparent sidereal time, in hours. -
-          0 ... everything OK
-          1 ... invalid value of 'Accuracy'
-          2 ... invalid value of 'Method'
- > 10,  30 ... 10 + error from function 'CioRai'
- 
- The Julian date may be split at any point, but for highest precision, set 'JdHigh' - to be the integral part of the Julian date, and set 'JdLow' to be the fractional part. -
- - - Transforms a vector from one coordinate system to another with same origin and axes rotated about the z-axis. - - Angle of coordinate system rotation, positive counterclockwise when viewed from +z, in degrees. - Position vector. - Position vector expressed in new coordinate system rotated about z by 'angle'. - - - - - Converts angular quantities for stars to vectors. - - Catalog entry structure containing ICRS catalog data - Position vector, equatorial rectangular coordinates, components in AU. - Velocity vector, equatorial rectangular coordinates, components in AU/Day. - - - - - Computes the Terrestrial Time (TT) or Terrestrial Dynamical Time (TDT) Julian date corresponding - to a Barycentric Dynamical Time (TDB) Julian date. - - TDB Julian date. - TT Julian date. - Difference 'tdb_jd'-'tt_jd', in seconds. - Expression used in this function is a truncated form of a longer and more precise - series given in: Explanatory Supplement to the Astronomical Almanac, pp. 42-44 and p. 316. - The result is good to about 10 microseconds. - - - - This function rotates a vector from the terrestrial to the celestial system. - - High-order part of UT1 Julian date. - Low-order part of UT1 Julian date. - Value of Delta T (= TT - UT1) at the input UT1 Julian date. - Selection for method: 0 ... CIO-based method; 1 ... equinox-based method - Selection for accuracy - 0 ... The output vector is referred to GCRS axes; 1 ... The output - vector is produced with respect to the equator and equinox of date. - Conventionally-defined X coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of celestial intermediate pole with respect to - ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, referred to ITRF - axes (terrestrial system) in the normal case where 'option' = 0. - Position vector, geocentric equatorial rectangular coordinates, referred to GCRS - axes (celestial system) or with respect to the equator and equinox of date, depending on 'Option'. -
-    0 ... everything is ok
-    1 ... invalid value of 'Accuracy'
-    2 ... invalid value of 'Method'
- > 10 ... 10 + error from function 'CioLocation'
- > 20 ... 20 + error from function 'CioBasis'
- 
- 'x' = 'y' = 0 means no polar motion transformation. - - The 'option' flag only works for the equinox-based method. - -
- - - Computes the position and velocity vectors of a terrestrial observer with respect to the center of the Earth. - - Structure containing observer's location - Local apparent sidereal time at reference meridian in hours. - Position vector of observer with respect to center of Earth, equatorial - rectangular coordinates, referred to true equator and equinox of date, components in AU. - Velocity vector of observer with respect to center of Earth, equatorial rectangular - coordinates, referred to true equator and equinox of date, components in AU/day. - - If reference meridian is Greenwich and st=0, 'pos' is effectively referred to equator and Greenwich. - This function ignores polar motion, unless the observer's longitude and latitude have been - corrected for it, and variation in the length of day (angular velocity of earth). - The true equator and equinox of date do not form an inertial system. Therefore, with respect - to an inertial system, the very small velocity component (several meters/day) due to the precession - and nutation of the Earth's axis is not accounted for here. - - - - - Computes the topocentric place of a solar system body. - - TT Julian date for topocentric place. - structure containing the body designation for the solar system body - Difference TT-UT1 at 'JdTt', in seconds of time. - Specifies the position of the observer - Selection for accuracy - Apparent right ascension in hours, referred to true equator and equinox of date. - Apparent declination in degrees, referred to true equator and equinox of date. - True distance from Earth to planet at 'JdTt' in AU. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'Place'.
-
- -
- - - Computes the topocentric place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for topocentric place. - Difference TT-UT1 at 'JdTt', in seconds of time. - Catalog entry structure containing catalog data for the object in the ICRS - Specifies the position of the observer - Code specifying the relative accuracy of the output position. - Topocentric right ascension in hours, referred to true equator and equinox of date 'JdTt'. - Topocentric declination in degrees, referred to true equator and equinox of date 'JdTt'. -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Where' in structure 'Location'.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'.
- 
- -
- - - To transform a star's catalog quantities for a change of epoch and/or equator and equinox. - - Transformation option - TT Julian date, or year, of input catalog data. - An entry from the input catalog, with units as given in the struct definition - TT Julian date, or year, of transformed catalog data. - Three-character abbreviated name of the transformed catalog. - The transformed catalog entry, with units as given in the struct definition - -
- = 0 ... Everything OK.
- = 1 ... Invalid value of an input date for option 2 or 3 (see Note 1 below).
- = 2 ... Catalogue ID exceeds three characters
- 
- Also used to rotate catalog quantities on the dynamical equator and equinox of J2000.0 to the ICRS or vice versa. - 1. 'DateInCat' and 'DateNewCat' may be specified either as a Julian date (e.g., 2433282.5) or - a Julian year and fraction (e.g., 1950.0). Values less than 10000 are assumed to be years. - For 'TransformOption' = 2 or 'TransformOption' = 3, either 'DateInCat' or 'DateNewCat' must be 2451545.0 or - 2000.0 (J2000.0). For 'TransformOption' = 4 and 'TransformOption' = 5, 'DateInCat' and 'DateNewCat' are ignored. - 2. 'TransformOption' = 1 updates the star's data to account for the star's space motion between the first - and second dates, within a fixed reference frame. 'TransformOption' = 2 applies a rotation of the reference - frame corresponding to precession between the first and second dates, but leaves the star fixed in - space. 'TransformOption' = 3 provides both transformations. 'TransformOption' = 4 and 'TransformOption' = 5 provide a a - fixed rotation about very small angles (0.1 arcsecond) to take data from the dynamical system - of J2000.0 to the ICRS ('TransformOption' = 4) or vice versa ('TransformOption' = 5). -3. For 'TransformOption' = 1, input data can be in any fixed reference system. for 'TransformOption' = 2 or - 'TransformOption' = 3, this function assumes the input data is in the dynamical system and produces output - in the dynamical system. for 'TransformOption' = 4, the input data must be on the dynamical equator and - equinox of J2000.0. for 'TransformOption' = 5, the input data must be in the ICRS. -4. This function cannot be properly used to bring data from old star catalogs into the - modern system, because old catalogs were compiled using a set of constants that are incompatible - with modern values. In particular, it should not be used for catalogs whose positions and - proper motions were derived by assuming a precession constant significantly different from - the value implicit in function 'precession'. -
- - - Convert Hipparcos catalog data at epoch J1991.25 to epoch J2000.0, for use within NOVAS. - - An entry from the Hipparcos catalog, at epoch J1991.25, with all members - having Hipparcos catalog units. See Note 1 below - The transformed input entry, at epoch J2000.0. See Note 2 below - To be used only for Hipparcos or Tycho stars with linear space motion. Both input and - output data is in the ICRS. - - 1. Input (Hipparcos catalog) epoch and units: - - Epoch: J1991.25 - Right ascension (RA): degrees - Declination (Dec): degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second (not in catalog) - - - - 2. Output (modified Hipparcos) epoch and units: - - Epoch: J2000.0 - Right ascension: hours - Declination: degrees - Proper motion in RA: milliarcseconds per year - Proper motion in Dec: milliarcseconds per year - Parallax: milliarcseconds - Radial velocity: kilometers per second - > - - - - - - Converts a vector in equatorial rectangular coordinates to equatorial spherical coordinates. - - Position vector, equatorial rectangular coordinates. - Right ascension in hours. - Declination in degrees. - -
- = 0 ... Everything OK.
- = 1 ... All vector components are zero; 'Ra' and 'Dec' are indeterminate.
- = 2 ... Both Pos[0] and Pos[1] are zero, but Pos[2] is nonzero; 'Ra' is indeterminate.
- 
- -
- - - Compute the virtual place of a planet or other solar system body. - - TT Julian date for virtual place. - structure containing the body designation for the solar system body( - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - True distance from Earth to planet in AU. - -
- =  0 ... Everything OK.
- =  1 ... Invalid value of 'Type' in structure 'SsBody'.
- > 10 ... Error code from function 'Place'.
- 
- -
- - - Computes the virtual place of a star at date 'JdTt', given its catalog mean place, proper motion, parallax, and radial velocity. - - TT Julian date for virtual place. - catalog entry structure containing catalog data for the object in the ICRS - Code specifying the relative accuracy of the output position. - Virtual right ascension in hours, referred to the GCRS. - Virtual declination in degrees, referred to the GCRS. - -
- =  0 ... Everything OK.
- > 10 ... Error code from function 'MakeObject'.
- > 20 ... Error code from function 'Place'
- 
- -
- - - Corrects a vector in the ITRF (rotating Earth-fixed system) for polar motion, and also corrects - the longitude origin (by a tiny amount) to the Terrestrial Intermediate Origin (TIO). - - TT or UT1 Julian date. - direction (short int) - Flag determining 'direction' of transformation; - direction = 0 transformation applied, ITRS to terrestrial intermediate system - direction != 0 inverse transformation applied, terrestrial intermediate system to ITRS - Conventionally-defined X coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Conventionally-defined Y coordinate of Celestial Intermediate Pole with - respect to ITRF pole, in arcseconds. - Position vector, geocentric equatorial rectangular coordinates, - referred to ITRF axes. - Position vector, geocentric equatorial rectangular coordinates, - referred to true equator and TIO. - - - - - Get path to a system folder - - SUpply null / nothing to use "current user" - returned string folder path - Folder Number from CSIDL enumeration e.g. CSIDL_PROGRAM_FILES_COMMONX86 = 44 = 0x2c - Indicates whether the folder should be created if it does not already exist. If this value is nonzero, - the folder is created. If this value is zero, the folder is not created - TRUE if successful; otherwise, FALSE. - - - - - Loads a library DLL - - Full path to the file to load - A pointer to the loaded DLL image - This is a wrapper for the Windows kernel32 function LoadLibraryA - - - - Unloads a library DLL - - Pointer to the loaded library returned by the LoadLibrary function. - True or false depending on whether the library was released. - - - - - Return the value of DeltaT for the given Julian date - - Julian date for which the delta T value is required - Double value of DeltaT (seconds) - Valid between the years 1650 and 2050 - - - - Interface to the SOFA component - - Implemented by the SOFA component - - - - This class presents a subset of the SOFA (Standards of Fundamental Astronomy) astrometry routines in a form that is easily accessible from both 32bit and 64bit .NET and - COM applications. - - - SOFA operates under the auspices of the International Astronomical Union (IAU) to provide algorithms and software for use in astronomical computing. The entire SOFA - collection comprises many authoritative routines across a number of areas including: - - Astrometry - Calendars - Time Scales - Earth rotation and sidereal time - Ephemerides (medium precision) - Geocentric/geodetic transformations - Precession, nutation, polar motion - Star space motion - Star catalogue conversion - - The class's functionality is provided by underlying DLLs compiled from unmodified original C source code distributed by SOFA but the class does not constitute software provided by and/or endorsed by SOFA. - No change whatsoever has been made to the algorithms implemented by SOFA that realise IAU standards. - - SOFA provides a validation routine to confirm that the compiled library provides expected results. 32 and 64bit versions of this routine (SofaTestXX.exe and SofaTestXX-64.exe, where XX is the issue number) - are included in this distribution and can be found in the Common Files\ASCOM\Astrometry directory. To run them open a command prompt in the Astrometry directory and enter the commands SofaTest10 /verbose and SofaTest10-64 /verbose. - The susbset of these tests that is relevant to the routines presented in this component have also been incorporated in the ASCOM Diagnostics tool and expected operation of the SOFA routnines can be confirmed through this tool. - Further information on the full library of SOFA routines is available here: http://www.iausofa.org/ - - - - - Static initialiser to load the SOFA DLL so that it is available for SOFA static functions such as GetBuiltInLeapSeconds - - - - - Creates a new instance of the SOFA component - - Thrown if the SOFA support library DLL cannot be loaded - - - - - Cleans up the SOFA object - - - - - - Major number of the SOFA issue currently used by this component. - - Integer issue number - - - - - Release date of the SOFA issue currently used by this component. - - String date in format yyyy-mm-dd - - - - - Release date of the revision to the SOFA Issue that is actually being used by this component. - - String date in format yyyy-mm-dd - When a new issue is employed that doesn't yet have a revision, this mehtod will return the SofaIssueDate - - - - Convert degrees, arcminutes, arcseconds to radians. - - Sign: '-' = negative, otherwise positive - Degrees - Arcminutes - Arcseconds - Angle in radian - Status: 0 = OK, 1 = ideg outside range 0-359, 2 = iamin outside range 0-59, 3 = asec outside range 0-59.999... - - Notes: - - The result is computed even if any of the range checks fail. - Negative ideg, iamin and/or asec produce a warning status, but the absolute value is used in the conversion. - If there are multiple errors, the status value reflects only the first, the smallest taking precedence. - - - - - - Normalize angle into the range 0 <= a < 2pi. - - Angle (radians) - Angle in range 0-2pi - - - - - Transform ICRS star data, epoch J2000.0, to CIRS using the SOFA Atci13 function. - - ICRS right ascension at J2000.0 (radians, Note 1) - ICRS declination at J2000.0 (radians, Note 1) - RA proper motion (radians/year; Note 2) - Dec proper motion (radians/year) - parallax (arcsec) - radial velocity (km/s, +ve if receding) - TDB as a 2-part Julian Date (Note 3) - TDB as a 2-part Julian Date (Note 3) - CIRS geocentric RA (radians) - CIRS geocentric Dec (radians) - equation of the origins (ERA-GST, Note 5) - - Notes: - - Star data for an epoch other than J2000.0 (for example from the Hipparcos catalog, which has an epoch of J1991.25) will require a preliminary call to iauPmsafe before use. - The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. - The TDB date date1+date2 is a Julian Date, apportioned in any convenient way between the two arguments. For example, JD(TDB)=2450123.8g could be expressed in any of these ways, among others: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Date 1 - Date 2 - Method
- 2450123.8 - 0.0 - JD method
- 2451545.0 - -1421.3 - J2000 method
- 2400000.5 - 50123.2 - MJD method
- 2450123.5 - 0.2 - Date and time method
- The JD method is the most natural and convenient to use in cases where the loss of several decimal digits of resolution is acceptable. The J2000 method is best matched to the way the argument is handled internally - and will deliver the optimum resolution. The MJD method and the date and time methods are both good compromises between resolution and convenience. For most applications of this function the choice will not be at all critical. - TT can be used instead of TDB without any significant impact on accuracy. -
- The available accuracy is better than 1 milliarcsecond, limited mainly by the precession-nutation model that is used, namely IAU 2000A/2006. Very close to solar system bodies, additional - errors of up to several milliarcseconds can occur because of unmodeled light deflection; however, the Sun's contribution is taken into account, to first order. The accuracy limitations of - the SOFA function iauEpv00 (used to compute Earth position and velocity) can contribute aberration errors of up to 5 microarcseconds. Light deflection at the Sun's limb is uncertain at the 0.4 mas level. - Should the transformation to (equinox based) apparent place be required rather than (CIO based) intermediate place, subtract the equation of the origins from the returned right ascension: - RA = RI - EO. (The Anp function can then be applied, as required, to keep the result in the conventional 0-2pi range.) -
-
-
- - - ICRS RA,Dec to observed place using the SOFA Atco13 function. - - ICRS RA (radians, note 1) - ICRS Dec (radians, note 2) - RA Proper motion (radians/year) - Dec Proper motion (radians/year - Parallax (arcsec) - Radial veolcity (Km/s, +ve if receding - UTC Julian date (part 1, notes 3,4) - UTC Julian date (part 2, notes 3,4) - UT1 - UTC (seonds, note 5) - Site longitude (radians, note 6) - Site Latitude (radians, note 6) - Site Height (meters, notes 6,8) - Polar motion co-ordinate (radians, note 7) - Polar motion co-ordinate (radians,note 7) - Site Presure (hPa = mB, note 8) - Site Temperature (C) - Site relative humidity (fraction in the range: 0.0 to 1.0) - Observation wavem=length (micrometres, note 9) - Observed Azimuth (radians) - Observed Zenith distance (radians) - Observed Hour Angle (radians) - Observed Declination (radians) - Observed RA (radians) - Equation of the origins (ERA-GST) - +1 = dubious year (Note 4), 0 = OK, -1 = unacceptable date - - Notes: - - Star data for an epoch other than J2000.0 (for example from the Hipparcos catalog, which has an epoch of J1991.25) will require a preliminary call to iauPmsafe before use. - The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. - utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any convenient way between the two arguments, for example where utc1 is the Julian Day Number and utc2 is the fraction of a day. - However, JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the length is 86399, 86400 or 86401 SI seconds. - Applications should use the function iauDtf2d to convert from calendar date and time of day into 2-part quasi Julian Date, as it implements the leap-second-ambiguity convention just described. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - UT1-UTC is tabulated in IERS bulletins. It increases by exactly one second at the end of each positive UTC leap second, introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This practice is under review, and in the future UT1-UTC may grow essentially without limit. - The geographical coordinates are with respect to the WGS84 reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the longitude required by the present function is east-positive (i.e. right-handed), in accordance with geographical convention. - The polar motion xp,yp can be obtained from IERS bulletins. The values are the coordinates (in radians) of the Celestial Intermediate Pole with respect to the International Terrestrial Reference System (see IERS Conventions 2003), measured along the meridians 0 and 90 deg west respectively. For many applications, xp and yp can be set to zero. - If hm, the height above the ellipsoid of the observing station in meters, is not known but phpa, the pressure in hPa (=mB), is available, an adequate estimate of hm can be obtained from the expression: -

hm = -29.3 * tsl * log ( phpa / 1013.25 );

- where tsl is the approximate sea-level air temperature in K (See Astrophysical Quantities, C.W.Allen, 3rd edition, section 52). Similarly, if the pressure phpa is not known, it can be estimated from the height of the observing station, hm, as follows: -

phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) );

- Note, however, that the refraction is nearly proportional to the pressure and that an accurate phpa value is important for precise work.
- The argument wl specifies the observing wavelength in micrometers. The transition from optical to radio is assumed to occur at 100 micrometers (about 3000 GHz). - The accuracy of the result is limited by the corrections for refraction, which use a simple A*tan(z) + B*tan^3(z) model. Providing the meteorological parameters are known accurately and there are no gross local effects, the predicted observed coordinates should be within 0.05 arcsec (optical) or 1 arcsec (radio) for a zenith distance of less than 70 degrees, better than 30 arcsec (optical or radio) at 85 degrees and better than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. - Without refraction, the complementary functions iauAtco13 and iauAtoc13 are self-consistent to better than 1 microarcsecond all over the celestial sphere. With refraction included, consistency falls off at high zenith distances, but is still better than 0.05 arcsec at 85 degrees. - "Observed" Az,ZD means the position that would be seen by a perfect geodetically aligned theodolite. (Zenith distance is used rather than altitude in order to reflect the fact that no allowance is made for depression of the horizon.) This is related to the observed HA,Dec via the standard rotation, using the geodetic latitude (corrected for polar motion), while the observed HA and RA are related simply through the Earth rotation angle and the site longitude. "Observed" RA,Dec or HA,Dec thus means the position that would be seen by a perfect equatorial with its polar axis aligned to the Earth's axis of rotation. - It is advisable to take great care with units, as even unlikely values of the input parameters are accepted and processed in accordance with the models used. -
-
-
- - - Encode date and time fields into 2-part Julian Date (or in the case of UTC a quasi-JD form that includes special provision for leap seconds). - - Time scale ID (Note 1) - Year in Gregorian calendar (Note 2) - Month in Gregorian calendar (Note 2) - Day in Gregorian calendar (Note 2) - Hour - Minute - Seconds - 2-part Julian Date (Notes 3, 4) - 2-part Julian Date (Notes 3, 4) - Status: +3 = both of next two, +2 = time is after end of day (Note 5), +1 = dubious year (Note 6), 0 = OK, -1 = bad year, -2 = bad month, -3 = bad day, -4 = bad hour, -5 = bad minute, -6 = bad second (<0) - - Notes: - - Scale identifies the time scale. Only the value "UTC" (in upper case) is significant, and enables handling of leap seconds (see Note 4). - For calendar conventions and limitations, see iauCal2jd. - The sum of the results, d1+d2, is Julian Date, where normally d1 is the Julian Day Number and d2 is the fraction of a day. In the case of UTC, where the use of JD is problematical, special conventions apply: see the next note. - JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The SOFA internal convention is that the quasi-JD day represents UTC days whether the length is 86399, - 86400 or 86401 SI seconds. In the 1960-1972 era there were smaller jumps (in either direction) each time the linear UTC(TAI) expression was changed, and these "mini-leaps" are also included in the SOFA convention. - The warning status "time is after end of day" usually means that the sec argument is greater than 60.0. However, in a day ending in a leap second the limit changes to 61.0 (or 59.0 in the case of a negative leap second). - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - Only in the case of continuous and regular time scales (TAI, TT, TCG, TCB and TDB) is the result d1+d2 a Julian Date, strictly speaking. In the other cases (UT1 and UTC) the result must be - used with circumspection; in particular the difference between two such results cannot be interpreted as a precise time interval. - - - - - - Equation of the origins, IAU 2006 precession and IAU 2000A nutation. - - TT as a 2-part Julian Date (Note 1) - TT as a 2-part Julian Date (Note 1) - Equation of the origins in radians (Note 2) - - Notes: - - The TT date date1+date2 is a Julian Date, apportioned in any convenient way between the two arguments. For example, JD(TT)=2450123.7 could be expressed in any of these ways, among others: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Date 1 - Date 2 - Method
- 2450123.7 - 0.0 - JD method
- 2451545.0 - -1421.3 - J2000 method
- 2400000.5 - 50123.2 - MJD method
- 2450123.5 - 0.2 - Date and time method
- The JD method is the most natural and convenient to use in cases where the loss of several decimal digits of resolution is acceptable. The J2000 method is best matched to the way the argument is handled internally - and will deliver the optimum resolution. The MJD method and the date and time methods are both good compromises between resolution and convenience. For most applications of this function the choice will not be at all critical. -
- The equation of the origins is the distance between the true equinox and the celestial intermediate origin and, equivalently, the difference between Earth rotation angle and Greenwich - apparent sidereal time (ERA-GST). It comprises the precession (since J2000.0) in right ascension plus the equation of the equinoxes (including the small correction terms). -
-
-
- - - Transform star RA,Dec from geocentric CIRS to ICRS astrometric using the SOFA Atic13 function. - - CIRS geocentric RA (radians) - CIRS geocentric Dec (radians) - TDB as a 2-part Julian Date (Note 1) - TDB as a 2-part Julian Date (Note 1) - ICRS astrometric RA (radians) - ICRS astrometric Dec (radians) - equation of the origins (ERA-GST, Note 4) - - Notes: - - The TDB date date1+date2 is a Julian Date, apportioned in any convenient way between the two arguments. For example, JD(TDB)=2450123.8g could be expressed in any of these ways, among others: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Date 1 - Date 2 - Method
- 2450123.8 - 0.0 - JD method
- 2451545.0 - -1421.3 - J2000 method
- 2400000.5 - 50123.2 - MJD method
- 2450123.5 - 0.2 - Date and time method
- The JD method is the most natural and convenient to use in cases where the loss of several decimal digits of resolution is acceptable. The J2000 method is best matched to the way the argument is handled internally - and will deliver the optimum resolution. The MJD method and the date and time methods are both good compromises between resolution and convenience. For most applications of this function the choice will not be at all critical. - TT can be used instead of TDB without any significant impact on accuracy. -
- Iterative techniques are used for the aberration and light deflection corrections so that the functions Atic13 and Atci13 are accurate inverses; - even at the edge of the Sun's disk the discrepancy is only about 1 nanoarcsecond. - The available accuracy is better than 1 milliarcsecond, limited mainly by the precession-nutation model that is used, namely IAU 2000A/2006. Very close to solar system bodies, additional - errors of up to several milliarcseconds can occur because of unmodeled light deflection; however, the Sun's contribution is taken into account, to first order. The accuracy limitations of - the SOFA function iauEpv00 (used to compute Earth position and velocity) can contribute aberration errors of up to 5 microarcseconds. Light deflection at the Sun's limb is uncertain at the 0.4 mas level. - Should the transformation to (equinox based) J2000.0 mean place be required rather than (CIO based) ICRS coordinates, subtract the equation of the origins from the returned right ascension: - RA = RI - EO. (The Anp function can then be applied, as required, to keep the result in the conventional 0-2pi range.) -
-
-
- - - CIRS RA,Dec to observed place using the SOFA Atio13 funciton. - - CIRS right ascension (CIO-based, radians) - CIRS declination (radians) - UTC as a 2-part quasi Julian Date (Notes 1,2) - UTC as a 2-part quasi Julian Date (Notes 1,2) - UT1-UTC (seconds, Note 3) - longitude (radians, east +ve, Note 4) - geodetic latitude (radians, Note 4) - height above ellipsoid (m, geodetic Notes 4,6) - polar motion coordinates (radians, Note 5) - polar motion coordinates (radians, Note 5) - pressure at the observer (hPa = mB, Note 6) - ambient temperature at the observer (deg C) - relative humidity at the observer (range 0-1) - wavelength (micrometers, Note 7) - observed azimuth (radians: N=0,E=90) - observed zenith distance (radians) - observed hour angle (radians) - observed declination (radians) - observed right ascension (CIO-based, radians) - Status: +1 = dubious year (Note 2), 0 = OK, -1 = unacceptable date - - Notes: - - utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any convenient way between the two arguments, for example where utc1 is the Julian Day Number and utc2 is the fraction of a day. - However, JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the length is 86399, 86400 or 86401 SI seconds. - Applications should use the function iauDtf2d to convert from calendar date and time of day into 2-part quasi Julian Date, as it implements the leap-second-ambiguity convention just described. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - UT1-UTC is tabulated in IERS bulletins. It increases by exactly one second at the end of each positive UTC leap second, introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This practice is under review, and in the future UT1-UTC may grow essentially without limit. - The geographical coordinates are with respect to the WGS84 reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the longitude required by the present function is east-positive (i.e. right-handed), in accordance with geographical convention. - The polar motion xp,yp can be obtained from IERS bulletins. The values are the coordinates (in radians) of the Celestial Intermediate Pole with respect to the International Terrestrial - Reference System (see IERS Conventions 2003), measured along the meridians 0 and 90 deg west respectively. For many applications, xp and yp can be set to zero. - If hm, the height above the ellipsoid of the observing station in meters, is not known but phpa, the pressure in hPa (=mB), is available, an adequate estimate of hm can be obtained from the expression: -

hm = -29.3 * tsl * log ( phpa / 1013.25 );

- where tsl is the approximate sea-level air temperature in K (See Astrophysical Quantities, C.W.Allen, 3rd edition, section 52). Similarly, if the pressure phpa is not known, it can be estimated from the height of the observing station, hm, as follows: -

phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) );

- Note, however, that the refraction is nearly proportional to the pressure and that an accurate phpa value is important for precise work.
- The argument wl specifies the observing wavelength in micrometers. The transition from optical to radio is assumed to occur at 100 micrometers (about 3000 GHz). - "Observed" Az,ZD means the position that would be seen by a perfect geodetically aligned theodolite. (Zenith distance is used rather than altitude in order to reflect the fact that no - allowance is made for depression of the horizon.) This is related to the observed HA,Dec via the standard rotation, using the geodetic latitude (corrected for polar motion), while the observed HA and RA are related simply through the Earth rotation - angle and the site longitude. "Observed" RA,Dec or HA,Dec thus means the position that would be seen by a perfect equatorial with its polar axis aligned to the Earth's axis of rotation. - The accuracy of the result is limited by the corrections for refraction, which use a simple A*tan(z) + B*tan^3(z) model. Providing the meteorological parameters are known accurately and there are no gross local effects, the predicted astrometric - coordinates should be within 0.05 arcsec (optical) or 1 arcsec (radio) for a zenith distance of less than 70 degrees, better than 30 arcsec (optical or radio) at 85 degrees and better than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. - The complementary functions iauAtio13 and iauAtoi13 are self-consistent to better than 1 microarcsecond all over the celestial sphere. - It is advisable to take great care with units, as even unlikely values of the input parameters are accepted and processed in accordance with the models used. -
-
-
- - - Observed place at a groundbased site to to ICRS astrometric RA,Dec using the SOFA Atoc13 function. - - type of coordinates - "R", "H" or "A" (Notes 1,2) - observed Az, HA or RA (radians; Az is N=0,E=90) - observed ZD or Dec (radians) - UTC as a 2-part quasi Julian Date (Notes 3,4) - UTC as a 2-part quasi Julian Date (Notes 3,4) - UT1-UTC (seconds, Note 5) - longitude (radians, east +ve, Note 6) - geodetic latitude (radians, Note 6) - height above ellipsoid (m, geodetic Notes 6,8) - polar motion coordinates (radians, Note 7) - polar motion coordinates (radians, Note 7) - pressure at the observer (hPa = mB, Note 8) - ambient temperature at the observer (deg C) - relative humidity at the observer (range 0-1) - wavelength (micrometers, Note 9) - ICRS astrometric RA (radians) - ICRS astrometric Dec (radians) - Status: +1 = dubious year (Note 4), 0 = OK, -1 = unacceptable date - - Notes: - - "Observed" Az,ZD means the position that would be seen by a perfect geodetically aligned theodolite. (Zenith distance is used rather than altitude in order to reflect the fact that no - allowance is made for depression of the horizon.) This is related to the observed HA,Dec via the standard rotation, using the geodetic latitude (corrected for polar motion), while the - observed HA and RA are related simply through the Earth rotation angle and the site longitude. "Observed" RA,Dec or HA,Dec thus means the position that would be seen by a perfect equatorial with its polar axis aligned to the Earth's axis of rotation. - Only the first character of the type argument is significant. "R" or "r" indicates that ob1 and ob2 are the observed right ascension and declination; "H" or "h" indicates that they are hour angle (west +ve) and declination; anything else ("A" or - "a" is recommended) indicates that ob1 and ob2 are azimuth (north zero, east 90 deg) and zenith distance. - utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any convenient way between the two arguments, for example where utc1 is the Julian Day Number and utc2 is the fraction of a day. - However, JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the length is 86399, 86400 or 86401 SI seconds. - Applications should use the function iauDtf2d to convert from calendar date and time of day into 2-part quasi Julian Date, as it implements the leap-second-ambiguity convention just described. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - UT1-UTC is tabulated in IERS bulletins. It increases by exactly one second at the end of each positive UTC leap second, introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This practice is under review, and in the future UT1-UTC may grow essentially without limit. - The geographical coordinates are with respect to the WGS84 reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the longitude required by the present function is east-positive (i.e. right-handed), in accordance with geographical convention. - The polar motion xp,yp can be obtained from IERS bulletins. The values are the coordinates (in radians) of the Celestial Intermediate Pole with respect to the International Terrestrial Reference System (see IERS Conventions 2003), measured along the - meridians 0 and 90 deg west respectively. For many applications, xp and yp can be set to zero. - If hm, the height above the ellipsoid of the observing station in meters, is not known but phpa, the pressure in hPa (=mB), is available, an adequate estimate of hm can be obtained from the expression: -

hm = -29.3 * tsl * log ( phpa / 1013.25 );

- where tsl is the approximate sea-level air temperature in K (See Astrophysical Quantities, C.W.Allen, 3rd edition, section 52). Similarly, if the pressure phpa is not known, it can be estimated from the height of the observing station, hm, as follows: -

phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) );

- Note, however, that the refraction is nearly proportional to the pressure and that an accurate phpa value is important for precise work.
- The argument wl specifies the observing wavelength in micrometers. The transition from optical to radio is assumed to occur at 100 micrometers (about 3000 GHz). - The accuracy of the result is limited by the corrections for refraction, which use a simple A*tan(z) + B*tan^3(z) model. Providing the meteorological parameters are known accurately and - there are no gross local effects, the predicted astrometric coordinates should be within 0.05 arcsec (optical) or 1 arcsec (radio) for a zenith distance of less than 70 degrees, better than 30 arcsec (optical or radio) at 85 degrees and better - than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. -Without refraction, the complementary functions iauAtco13 and iauAtoc13 are self-consistent to better than 1 microarcsecond all over the celestial sphere. With refraction included, consistency falls off at high zenith distances, but is still better than 0.05 arcsec at 85 degrees. - It is advisable to take great care with units, as even unlikely values of the input parameters are accepted and processed in accordance with the models used. -
-
-
- - - Observed place to CIRS using the SOFA Atoi13 function. - - type of coordinates - "R", "H" or "A" (Notes 1,2) - observed Az, HA or RA (radians; Az is N=0,E=90) - observed ZD or Dec (radians) - UTC as a 2-part quasi Julian Date (Notes 3,4) - UTC as a 2-part quasi Julian Date (Notes 3,4) - UT1-UTC (seconds, Note 5) - longitude (radians, east +ve, Note 6) - geodetic latitude (radians, Note 6) - height above the ellipsoid (meters, Notes 6,8) - polar motion coordinates (radians, Note 7) - polar motion coordinates (radians, Note 7) - pressure at the observer (hPa = mB, Note 8) - ambient temperature at the observer (deg C) - relative humidity at the observer (range 0-1) - wavelength (micrometers, Note 9) - CIRS right ascension (CIO-based, radians) - CIRS declination (radians) - Status: +1 = dubious year (Note 2), 0 = OK, -1 = unacceptable date - - Notes: - - "Observed" Az,ZD means the position that would be seen by a perfect geodetically aligned theodolite. (Zenith distance is used rather than altitude in order to reflect the fact that no - allowance is made for depression of the horizon.) This is related to the observed HA,Dec via the standard rotation, using the geodetic latitude (corrected for polar motion), while the - observed HA and RA are related simply through the Earth rotation angle and the site longitude. "Observed" RA,Dec or HA,Dec thus means the position that would be seen by a perfect equatorial - with its polar axis aligned to the Earth's axis of rotation. - Only the first character of the type argument is significant. "R" or "r" indicates that ob1 and ob2 are the observed right ascension and declination; "H" or "h" indicates that they are - hour angle (west +ve) and declination; anything else ("A" or "a" is recommended) indicates that ob1 and ob2 are azimuth (north zero, east 90 deg) and zenith distance. - utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any convenient way between the two arguments, for example where utc1 is the Julian Day Number and utc2 is the fraction of a day. - However, JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the length is 86399, 86400 or 86401 SI seconds. - Applications should use the function iauDtf2d to convert from calendar date and time of day into 2-part quasi Julian Date, as it implements the leap-second-ambiguity convention just described. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - UT1-UTC is tabulated in IERS bulletins. It increases by exactly one second at the end of each positive UTC leap second, introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This - practice is under review, and in the future UT1-UTC may grow essentially without limit. - The geographical coordinates are with respect to the WGS84 reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the longitude required by the present function is east-positive - (i.e. right-handed), in accordance with geographical convention. - The polar motion xp,yp can be obtained from IERS bulletins. The values are the coordinates (in radians) of the Celestial Intermediate Pole with respect to the International Terrestrial - Reference System (see IERS Conventions 2003), measured along the meridians 0 and 90 deg west respectively. For many applications, xp and yp can be set to zero. - If hm, the height above the ellipsoid of the observing station in meters, is not known but phpa, the pressure in hPa (=mB), is available, an adequate estimate of hm can be obtained from the expression: -

hm = -29.3 * tsl * log ( phpa / 1013.25 );

- where tsl is the approximate sea-level air temperature in K (See Astrophysical Quantities, C.W.Allen, 3rd edition, section 52). Similarly, if the pressure phpa is not known, it can be estimated from the height of the observing station, hm, as follows: -

phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) );

- Note, however, that the refraction is nearly proportional to the pressure and that an accurate phpa value is important for precise work.
- The argument wl specifies the observing wavelength in micrometers. The transition from optical to radio is assumed to occur at 100 micrometers (about 3000 GHz). - The accuracy of the result is limited by the corrections for refraction, which use a simple A*tan(z) + B*tan^3(z) model. Providing the meteorological parameters are known accurately and - there are no gross local effects, the predicted astrometric coordinates should be within 0.05 arcsec (optical) or 1 arcsec (radio) for a zenith distance of less than 70 degrees, better - than 30 arcsec (optical or radio) at 85 degrees and better than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. - Without refraction, the complementary functions iauAtio13 and iauAtoi13 are self-consistent to better than 1 microarcsecond all over the celestial sphere. With refraction included, - consistency falls off at high zenith distances, but is still better than 0.05 arcsec at 85 degrees. - It is advisable to take great care with units, as even unlikely values of the input parameters are accepted and processed in accordance with the models used. -
-
-
- - - Time scale transformation: International Atomic Time, TAI, to Coordinated Universal Time, UTC. - - TAI as a 2-part Julian Date (Note 1) - TAI as a 2-part Julian Date (Note 1) - UTC as a 2-part quasi Julian Date (Notes 1-3) - UTC as a 2-part quasi Julian Date (Notes 1-3) - Status: +1 = dubious year (Note 4), 0 = OK, -1 = unacceptable date - - Notes: - - tai1+tai2 is Julian Date, apportioned in any convenient way between the two arguments, for example where tai1 is the Julian Day Number and tai2 is the fraction of a day. The returned utc1 - and utc2 form an analogous pair, except that a special convention is used, to deal with the problem of leap seconds - see the next note. - JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the - length is 86399, 86400 or 86401 SI seconds. In the 1960-1972 era there were smaller jumps (in either direction) each time the linear UTC(TAI) expression was changed, and these "mini-leaps are also included in the SOFA convention. - The function iauD2dtf can be used to transform the UTC quasi-JD into calendar date and clock time, including UTC leap second handling. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - - - - - - Time scale transformation: International Atomic Time, TAI, to Terrestrial Time, TT. - - TAI as a 2-part Julian Date - TAI as a 2-part Julian Date - TT as a 2-part Julian Date - TT as a 2-part Julian Date - Status: 0 = OK - - Notes: - - tai1+tai2 is Julian Date, apportioned in any convenient way between the two arguments, for example where tai1 is the Julian Day Number and tai2 is the fraction of a day. The returned - tt1,tt2 follow suit. - - - - - - Time scale transformation: Terrestrial Time, TT, to International Atomic Time, TAI. - - TT as a 2-part Julian Date - TT as a 2-part Julian Date - TAI as a 2-part Julian Date - TAI as a 2-part Julian Date - Status: 0 = OK - - Note - - tt1+tt2 is Julian Date, apportioned in any convenient way between the two arguments, for example where tt1 is the Julian Day Number and tt2 is the fraction of a day. The returned tai1,tai2 follow suit. - - - - - - Convert hours, minutes, seconds to radians. - - sign: '-' = negative, otherwise positive - Hours - Minutes - Seconds - Angle in radians - Status: 0 = OK, 1 = ihour outside range 0-23, 2 = imin outside range 0-59, 3 = sec outside range 0-59.999... - - Notes: - - The result is computed even if any of the range checks fail. - Negative ihour, imin and/or sec produce a warning status, but the absolute value is used in the conversion. - If there are multiple errors, the status value reflects only the first, the smallest taking precedence. - - - - - - Time scale transformation: Coordinated Universal Time, UTC, to International Atomic Time, TAI. - - UTC as a 2-part quasi Julian Date (Notes 1-4) - UTC as a 2-part quasi Julian Date (Notes 1-4) - TAI as a 2-part Julian Date (Note 5) - TAI as a 2-part Julian Date (Note 5) - Status: +1 = dubious year (Note 3) 0 = OK -1 = unacceptable date - - Notes: - - utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any convenient way between the two arguments, for example where utc1 is the Julian Day Number and utc2 is the fraction of a day. - JD cannot unambiguously represent UTC during a leap second unless special measures are taken. The convention in the present function is that the JD day represents UTC days whether the - length is 86399, 86400 or 86401 SI seconds. In the 1960-1972 era there were smaller jumps (in either direction) each time the linear UTC(TAI) expression was changed, and these "mini-leaps" are also included in the SOFA convention. - The warning status "dubious year" flags UTCs that predate the introduction of the time scale or that are too far in the future to be trusted. See iauDat for further details. - The function iauDtf2d converts from calendar date and time of day into 2-part Julian Date, and in the case of UTC implements the leap-second-ambiguity convention described above. - The returned TAI1,TAI2 are such that their sum is the TAI Julian Date. - - - - - - Get path to a system folder - - SUpply null / nothing to use "current user" - returned string folder path - Folder Number from CSIDL enumeration e.g. CSIDL_PROGRAM_FILES_COMMONX86 = 44 = 0x2c - Indicates whether the folder should be created if it does not already exist. If this value is nonzero, - the folder is created. If this value is zero, the folder is not created - TRUE if successful; otherwise, FALSE. - - - - - Loads a library DLL - - Full path to the file to load - A pointer to the loaded DLL image - This is a wrapper for the Windows kernel32 function LoadLibraryA - - - - Unloads a library DLL - - Pointer to the loaded library returned by the LoadLibrary function. - True or false depending on whether the library was released. - - - - - Indicates whether we are running as a 32bit or 64bit application - - True if the application is 64bit, False for 32bit - - - - - Calculates the value of DeltaT over a wide range of hstoric and future Julian dates - - Julian Date of interest - DelatT value at the given Julian date - - Post 2011, calculation is effected throgh a 2nd order polynomial best fit to real DeltaT data from: http://maia.usno.navy.mil/ser7/deltat.data - together with projections of DeltaT from: http://maia.usno.navy.mil/ser7/deltat.preds - The analysis spreadsheets for DeltaT values at dates post 2011 are stored in the \NOVAS\DeltaT Predictions folder of the ASCOM source tree. - - To esnure that leap second and DeltaUT1 transitions are handled correctly and occur at 00:00:00 UTC, the supplied Julian date should be in UTC time - - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.Attributes.xml b/MeadeAutostar497/bin/Debug/ASCOM.Attributes.xml deleted file mode 100644 index b0c1e74..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.Attributes.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - ASCOM.Attributes - - - - - An attribute for declaratively associating an assembly, class or property with an - ASCOM device ID (and optionally, a display name). - - - This attribute is intended for use in two main situations: - - - - Settings management and integration with Visual Studio designers - - - When this attribute is placed on the driver's Properties.Settings class, it propagates - down to each of the settings properties. When the setting is passed to the - ASCOM.SettingsProvider class at runtime, the settings provider looks for this attribute - to determine which settings hive to save the value in when it is passed to - . - - - - - Deployment - - - The values in this attribute could be used by an installer custom action to perform - ASCOM registration during setup. Historically this has been handled programmatically, - but there are trends towards a more declarative approach to deployment (for example - WiX, Windows Installer Xml). It is expected that such an installer may need to obtain - registration data by reflecting on the assemblies being installed. Placing this attribute - at the assembly level will assist in this situation. - - - - - - - - Initializes a new instance of the class. - - The ASCOM device ID (aka COM ProgID) to be associated with the class. - - - Recommended usage is: - - [DeviceId("ASCOM.SuperDuper.Telescope", DeviceName="SuperDuper Deluxe")] - - - - In the event that the DeviceName optional parameter is not set, it will return the DeviceId. - - - - - - Gets the ASCOM DeviceID, also known as the COM ProgID. - - - - - Gets or sets the display name of the device. This would be the short display name, as displayed in the ASCOM Chooser. - - The name of the device. - - - - An attribute that confers a 'friendly name' on a class and marks it as loadable by LocalServer. - The 'friendly name' is used by the ASCOM LocalServer to register the class with the ASCOM Chooser. - The 'friendly name' is what gets displayed to the user in the driver selection combo box. - This attribute is also used by the LocalServer to filter the assemblies that it will - attempt to load at runtime. LocalServer will only load classes bearing this attribute. - - - - - Initializes a new instance of the class. - - The 'friendly name' of the served class. - - - - Gets or sets the 'friendly name' of the served class, as registered with the ASCOM Chooser. - - The 'friendly name' of the served class. - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.Controls.xml b/MeadeAutostar497/bin/Debug/ASCOM.Controls.xml deleted file mode 100644 index 7b0d3d4..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.Controls.xml +++ /dev/null @@ -1,513 +0,0 @@ - - - - ASCOM.Controls - - - - - The TrafficLight enumeration may be used in any situation where a Normal/Warning/Error status indication is needed. - - - - - Green traffic light represents a good or normal status. - - - - - Yellow traffic light represents a warning condition, which does not necessarily prevent continued - operation but which merits further investigation. - - - - - Red traffic light represents an error condition or a situation that prevents further progress. - - - - - - Wikipedia: An annunciator panel is a group of lights used as a central indicator of status of equipment or systems in an aircraft, - industrial process, building or other installation. Usually the annunciator panel includes a main warning lamp or audible signal - to draw the attention of operating personnel to the annunciator panel for abnormal events or conditions. - - - The Anunciator control provides a simple, standard method of displaying a status notification to the user within a Windows Forms application. - Anunciators are best used with the companion control, although they can be placed anywhere on a Windows Form. - The control can be used to provide simple On/Off status displays or can be configured to blink with various levels of urgency so that it can - represent alarm conditions. - - An anunciator may represent the slewing state of a telescope. It would be represented by the word "SLEW". When the telescope is stationary, - the anunciator remains inactive. When the telescope begins to slew, the anunciator is set to - to alert the user that the equipment is in motion. - - - - Each anunciator has active and inactive states. When inactive, the control displays in a subdued colour that is readable but does not draw - attention. When active, the control will display in a stronger, more visible colour and will either have a steady state or will blink in one - of a number of predefined cadence patterns. The cadence patterns are fixed and not user-definable, so that a standard 'look and feel' - is promoted accross different applications. - - - Whilst the user is at liberty to choose different colours for both and , - The default colours have been chosen to look similar to earlier applications that use similar displays and the defaults are highly - recommended for most circumstances. The control's background colour is inherited from the parent control (which should normally be - an ) and is not directly settable by the user. - - - - - - A flag that records the anunciator's last known state. - - - - - Stores the mute status for the anunciator. - - - - - Tracks whether this object has been disposed. - - - - - Initializes a new instance of the class. - - - - - Gets or sets the foreground color of the control. There is little point in setting this value - directly as it will normally be constantly overwritten at runtime. - - - - The foreground of the control. The default is the value of the property. - - - - - - - - Gets or sets the color of the anunciator text when inactive. - - - - The foreground of the control. The default is the value of the property. - - - - - - - - Gets or sets the color of the anunciator text when active. - - The color of the anunciator text when active. - - - - Gets or sets the background color for the control. - - - - A that represents the background color of the control. The default is the value of the property. - - - - - - - - Gets or sets a value indicating whether the control can respond to user interaction. - For an anunciator, this affects how it displays. A disabled anunciator will always display in - its regardless of other settings and it will not participate in - cadence updates. - - - true if the control can respond to user interaction; otherwise, false. - The default is true. - - - - - - - - - - - Unregisters this control from the so that it will no longer receive cadence updates. - - - - - Registers this control with the so that it will receive cadence updates. - - - - - Releases all resources used by the . - - - - - Releases the unmanaged resources used by the and optionally releases the managed resources. - - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - - Gets or sets the cadence (blink pattern) of the anunciator. - Different cadence patterns imply different levels of urgency or severity. - - The cadence pattern. - - - - Updates the anunciator's display, if it has changed since the last update. - - The new state of the control's appearance ('on' or 'off'). - - Implements the method. - The always calls this method on the GUI thread. - - - - - Handles the ParentChanged event of the Anunciator control. - Changes the control's background colour to blend in with the parent control. - - The source of the event. - The instance containing the event data. - - - - Defines the signature for the CadenceUpdateDelegate, used in making thread-safe control updates. - - - - - A panel control for grouping and arranging controls. - This control inherits most of its behaviour from the - base class, but provides some defaults that are appropriate for use with ASCOM. - - - - - Initializes a new instance of the class. - - - - - Releases all resources used by the . - - - - - Manages objects that must be toggled on and off in a regular pattern over time. This is known as a cadence. - CadenceManager is intended primarily for Windows Forms controls, but can be used for any item that implements - the interface. - - - CadenceManager behaves slightly differently if the managed item is a Windows Forms control. - - Invisible controls do not receive updates until they become visible again. - The method is marshalled to the GUI thread. - - - - - - The one and only instance of this class. - - - - - An object used for thread synchronization during object initialization. - This ensures that the singleton is thread-safe. - - - - - A list of all the anunciator controls that have been created which need updating - when the timer ticks. - - - - - Indicates the current bit position within the cadence register. - - - - - A timer that triggers updates to anunciators to simulate flashing. - - - - - Initializes a new instance of the class. - This constructor is declared private so that no instances of the class can be created - except by the class itself - this is how the singleton pattern ensures there is just a single instance. - - - - - Gets a reference to the Singleton. - If the Singleton has not yet be instantiated, this causes the object - to be created and the constructor to execute (lazy loading). - This operation uses the double-checked locking pattern to ensure thread-safety. - - - - - Adds the specified to the list of managed controls. - If this is the first control being added, then the update timer is configured and started. - - The control to be managed. - - Each control can only appear in the list once (duplicate adds will be silently ignored). - - - - - Removes a control from the update list. - If no managed controls remain in the list, then the update timer is stopped. - - - The to be removed from the update list. - - - If the control is null, or is not in the update list, no action is taken. - If the update list is empty after the control is removed, then the cadence timer is stopped. - - - - - Handles the Tick event of the tmrCadence control. - Computes the new display status for each cadenced control based on its - property and requests the control update itself with the new value. - - The source of the event. - The instance containing the event data. - - - - Delegate used to make thread-safe control updates. - - - - - Cadence patterns for blinking LEDs. - Cadences are based on 32-bit unsigned integers, such that the ordinal value - of each item represents a bit mask that can be used directly in an update routine. - - - - - Permanently off, - appropriate for indication of a non-critical inactive state. - - - - - Permanently on, - appropriate for indication of a non-critical active state. - - - - - Fast blink, - appropriate for indicating a state of hightened but non-critical alert. - Usage example: during movement of robotic equipment. - - - - - Slow blink, - appropriate for non-critical persistent conditions. - Usage example: image exposure in progress. - - - - - Very fast blink, - appropriate for drawing attention to urgent conditions that require operator intervention. - Usage example: Rain detected - - - - - Strobe is mostly off but with an occasional short blip on, - appropriate for indicating non-critical ongoing steady idle state. - - - - - Wink (mostly on with occasional short wink-off), - appropriate for indicating non-critical ongoing steady active state. - - - - - Defines the members necessary for a control to register and be managed by the - singleton. - - - - - Gets or sets the cadence (blink pattern) of the control. - Different cadence patterns imply different levels of urgency or severity. - - The cadence pattern. - - is based on a 64-bit long integer but - only 32-bits are used. This is necessary to achieve CLS compliance, because - 32-bit uints are not CLS compliant. - - - - - Updates the control's display. - always calls this method on the GUI thread so that control updates are thread-safe. - - - The new display state of the control: true for active, false for inactive. - - - - - Provides a status indicator modeled on a bi-colour red/green LED lamp. - The lamp can be red or green and (traffic light colours) and - can be steady or can flash with a choice of different cadences. - - - - - Required designer variable. - - - - - Records the current cadence state of the control. - Used to short-cut display updates when they are unnecessary. - - - - - When True, the LED indicator reflects the state of the Red, Green and Cadence settings. - When False, the LED appears inactive (steady off). - - - - - True when the instance has been disposed. - - - - - Internal control used to display the LED's text label. - - - - - Internal panel control that is used to display the LED's colour. - - - - - Gets or sets the LED's status (which controls its display colour). - - - - - Sets the text displayed alongside the indicator - - - - - Sets or reads the 'power status' of the LED - When the LED is Enabled, it reflects the current colour settings and cadence. - When disabled, the LED appears off and cadencing is disabled. - - - - - Gets or sets the LED cadence bitmap. - If the cadence has changed and is non-steady and the LED is enabled, then the cadence timer is started. - - - Implements the property. - - - - - Default constructor for a new LEDIndicator object. Performs the default processing required - by the designer. - - - - - Releases all resources used by the . - - - - - Releases the unmanaged resources and optionally releases the managed resources. - - true to release both managed and unmanaged resources; false to release only unmanaged resources. - - - - Required method for Designer support - do not modify - the contents of this method with the code editor. - - - - - Refreshes the LED display, taking account of the power, - colour and cadence settings. - - The new state of the control's appearance ('on' or 'off'). - - Implements the method. - The always calls this method on the GUI thread. - - - - - Renders the 'power off' appearance of the LED indicator. - - - - - Renders the 'power on' appearance of the LED indicator. The exact appearance depends on the property. - - - - - Sets the colour of the LED. - If the colour is changed, then the LED's panel control is invalidated to force a re-draw. - - The new led colour. - - - - Unregister from the . - - - - - Register with the . - - - - - The URL of the ASCOM Standards web site. - - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.DeviceInterfaces.xml b/MeadeAutostar497/bin/Debug/ASCOM.DeviceInterfaces.xml deleted file mode 100644 index 17cb886..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.DeviceInterfaces.xml +++ /dev/null @@ -1,6948 +0,0 @@ - - - - -ASCOM.DeviceInterfaces - - - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - The alignment mode of the mount. - - - - - Altitude-Azimuth alignment. - - - - - Polar (equatorial) mount other than German equatorial. - - - - - German equatorial mount. - - - - - Well-known telescope tracking rates. - - - - - Sidereal tracking rate (15.041 arcseconds per second). - - - - - Lunar tracking rate (14.685 arcseconds per second). - - - - - Solar tracking rate (15.0 arcseconds per second). - - - - - King tracking rate (15.0369 arcseconds per second). - - - - - Equatorial coordinate systems used by telescopes. - Only used with telescope interface versions 2 and 3 - - - In June 2018 the name equLocalTopocentric was deprecated in favour of equTopocentric, both names return the same value (1). - The rationale for this change is set out in the Astronomical Coordinates section. - - - - - Custom or unknown equinox and/or reference frame. - - - - - Topocentric coordinates. Coordinates of the object at the current date having allowed for annual aberration, precession and nutation. This is the most common coordinate type for amateur telescopes. - - - - - J2000 equator/equinox. Coordinates of the object at mid-day on 1st January 2000, ICRS reference frame. - - - - - J2050 equator/equinox, ICRS reference frame. - - - - - B1950 equinox, FK4 reference frame. - - - - - Please use equTopocentric instead - see Astronomical Coordinates for an explanation. - - - - - The direction in which the guide-rate motion is to be made. - - - - - North (+ declination/altitude). - - - - - South (- declination/altitude). - - - - - East (+ right ascension/azimuth). - - - - - West (- right ascension/azimuth) - - - - - The telescope axes - Only used with if the telescope interface version is 2 or 3 - - - - - Primary axis (e.g., Right Ascension or Azimuth). - - - - - Secondary axis (e.g., Declination or Altitude). - - - - - Tertiary axis (e.g. imager rotator/de-rotator). - - - - - The pointing state of the mount - - - Pier side is a GEM-specific term that has historically caused much confusion. - As of Platform 6, the PierSide property is defined to refer to the telescope pointing state. Please see for - much more information on this topic. - In order to support Dome slaving, where it is important to know on which side of the pier the mount is actually located, ASCOM has adopted the - convention that the Normal pointing state will be the state where the mount is on the East side of the pier, looking West with the counterweights below - the optical assembly. - Only used with telescope interface versions 2 and later. - - - - - Normal pointing state - Mount on the East side of pier (looking West) - - - - - Unknown or indeterminate. - - - - - Through the pole pointing state - Mount on the West side of pier (looking East) - - - - - ASCOM Dome ShutterState status values. - - - - - Dome shutter status open - - - - - Dome shutter status closed - - - - - Dome shutter status opening - - - - - Dome shutter status closing - - - - - Dome shutter status error - - - - - ASCOM Camera status values. - - - - - Camera status idle - - - - - Camera status waiting - - - - - Camera status exposing - - - - - Camera status reading - - - - - Camera status download - - - - - Camera status error - - - - - Sensor type, identifies the type of colour sensor - V2 cameras only - ] - - - - Camera produces monochrome array with no Bayer encoding - - - - - Camera produces color image directly, requiring not Bayer decoding - - - - - Camera produces RGGB encoded Bayer array images - - - - - Camera produces CMYG encoded Bayer array images - - - - - Camera produces CMYG2 encoded Bayer array images - - - - - Camera produces Kodak TRUESENSE Bayer LRGB array images - - - - - A collection of rates at which the telescope may be moved about the specified axis by the method. - This is only used if the telescope interface version is 2 or 3 - - See the description of the method for more information. - This method must return an empty collection if is not supported. - The values used in members must be non-negative; forward and backward motion is achieved by the application - applying an appropriate sign to the returned values in the command. - - - - - Return information about the rates at which the telescope may be moved about the specified axis by the method. - - The axis about which rate information is desired - Collection of Rate objects describing the supported rates of motion that can be supplied to the method for the specified axis. - Collection of Rate objects - The (symbolic) values for Index () are: - -
  • 0 Primary axis (e.g., Hour Angle or Azimuth)
  • -
  • 1 Secondary axis (e.g., Declination or Altitude)
  • -
  • 2 Tertiary axis (e.g. imager rotator/de-rotator)
  • -
    -
    -
    - - - Number of items in the returned collection - - Number of items - Integer number of items - - - - - Disposes of the object and cleans up - - - - - - Returns an enumerator for the collection - - An enumerator - - - - - Defines the ICamera Interface - - The camera state diagram is shown here: - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a PropertyNotImplementedException.

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a PropertyNotImplementedException.

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a MethodNotImplementedException.

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    May throw a MethodNotImplementedException if the device does not support any actions.

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented, must not throw a PropertyNotImplementedException.

    This method must return an empty arraylist if no actions are supported. - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    May throw a MethodNotImplementedException.

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    May throw a MethodNotImplementedException.

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    May throw a MethodNotImplementedException.

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Aborts the current exposure, if any, and returns the camera to Idle state. - - -

    Must be implemented, must not throw a MethodNotImplementedException.

    - NOTES: - - Must throw exception if camera is not idle and abort is unsuccessful (or not possible, e.g. during download). - Must throw exception if hardware or communications error occurs. - Must NOT throw an exception if the camera is already idle. - -
    - Thrown if the driver is not connected. - Thrown if abort is not currently possible (e.g. during download). - Thrown if a communications error occurs, or if the abort fails. -
    - - - Sets the binning factor for the X axis, also returns the current value. - - - Should default to 1 when the camera connection is established. Note: driver does not check - for compatible subframe values when this value is set; rather they are checked upon StartExposure. - - The X binning value - Must throw an exception for illegal binning values - - - - Sets the binning factor for the Y axis, also returns the current value. - - - Should default to 1 when the camera connection is established. Note: driver does not check - for compatible subframe values when this value is set; rather they are checked upon StartExposure. - - The Y binning value. - Must throw an exception for illegal binning values - - - - Returns the current camera operational state - - - Returns one of the following status information: - - Value State Meaning - 0 CameraIdle At idle state, available to start exposure - 1 CameraWaiting Exposure started but waiting (for shutter, trigger, filter wheel, etc.) - 2 CameraExposing Exposure currently in progress - 3 CameraReading CCD array is being read out (digitized) - 4 CameraDownload Downloading data to PC - 5 CameraError Camera error condition serious enough to prevent further operations (connection fail, etc.). - - - The state of the camera. - Must return an exception if the camera status is unavailable. - - - - Returns the width of the CCD camera chip in unbinned pixels. - - The size of the camera X. - Must throw exception if the value is not known - - - - Returns the height of the CCD camera chip in unbinned pixels. - - The size of the camera Y. - Must throw exception if the value is not known - - - - Returns true if the camera can abort exposures; false if not. - - - true if this instance can abort exposure; otherwise, false. - - Thrown if the driver is not connected. - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - Returns a flag showing whether this camera supports asymmetric binning - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If true, the camera can have different binning on the X and Y axes, as - determined by and . If false, the binning must be equal on the X and Y axes. -
    - - true if this instance can asymmetric bin; otherwise, false. - - Must throw exception if the value is not known (n.b. normally only - occurs if no connection established and camera must be queried) -
    - - - If true, the camera's cooler power setting can be read. - - - true if this instance can get cooler power; otherwise, false. - - Thrown if the driver is not connected. - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - Returns a flag indicating whether this camera supports pulse guiding - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - Returns true if the camera can send autoguider pulses to the telescope mount; false if not. - Note: this does not provide any indication of whether the autoguider cable is actually connected. -
    - - true if this instance can pulse guide; otherwise, false. - - Thrown if the driver is not connected. -
    - - - Returns a flag indicatig whether this camera supports setting the CCD temperature - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If true, the camera's cooler setpoint can be adjusted. If false, the camera - either uses open-loop cooling or does not have the ability to adjust temperature - from software, and setting the property has no effect. -
    - - true if this instance can set CCD temperature; otherwise, false. - - Thrown if the driver is not connected. -
    - - - Returns a flag indicating whether this camera can stop an exposure that is in progress - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - Some cameras support , which allows the exposure to be terminated - before the exposure timer completes, but will still read out the image. Returns - true if is available, false if not. -
    - - true if the camera can stop the exposure; otherwise, false. - - an error condition such as connection failure is present -
    - - - Returns the current CCD temperature in degrees Celsius. - - The CCD temperature. - Must throw exception if data unavailable. - Must throw exception if not supported. - - - - Turns on and off the camera cooler, and returns the current on/off state. - - - Warning: turning the cooler off when the cooler is operating at high delta-T - (typically >20C below ambient) may result in thermal shock. Repeated thermal - shock may lead to damage to the sensor or cooler stack. Please consult the - documentation supplied with the camera for further information. - - true if the cooler is on; otherwise, false. - not supported - an error condition such as connection failure is present - - - - Returns the present cooler power level, in percent. - - - Returns zero if is false. - - The cooler power. - not supported - an error condition such as connection failure is present - - - - Returns the gain of the camera in photoelectrons per A/D unit. - - - Some cameras have multiple gain modes; these should be selected via the and thus are - static during a session. - - The electrons per ADU. - Must throw exception if data unavailable. - - - - Reports the full well capacity of the camera in electrons, at the current camera settings (binning, SetupDialog settings, etc.) - - The full well capacity. - Must throw exception if data unavailable. - - - - Returns a flag indicating whether this camera has a mechanical shutter - - - If true, the camera has a mechanical shutter. If false, the camera does not have - a shutter. If there is no shutter, the StartExposure command will ignore the - Light parameter. - - - true if this instance has shutter; otherwise, false. - - Thrown if the driver is not connected. - - - - Returns the current heat sink temperature (called "ambient temperature" by some manufacturers) in degrees Celsius. - - - Only valid if is true. - - The heat sink temperature. - Must throw exception if data unavailable. - - - - Returns a safearray of int of size * containing the pixel values from the last exposure. - - - The application must inspect the Safearray parameters to determine the dimensions. - Note: if or is changed after a call to StartExposure it will - have no effect on the size of this array. This is the preferred method for programs (not scripts) to download - iamges since it requires much less memory. - For color or multispectral cameras, will produce an array of * * - NumPlanes. If the application cannot handle multispectral images, it should use just the first plane. - - The image array. - Must throw exception if data unavailable. - - - - Returns a safearray of Variant of size * containing the pixel values from the last exposure. - - - The application must inspect the Safearray parameters to - determine the dimensions. Note: if or is changed after a call to - StartExposure it will have no effect on the size of this array. This property - should only be used from scripts due to the extremely high memory utilization on - large image arrays (26 bytes per pixel). Pixels values should be in Short, int, - or Double format. - For color or multispectral cameras, will produce an array of * * - NumPlanes. If the application cannot handle multispectral images, it should use - just the first plane. - - The image array variant. - Must throw exception if data unavailable. - - - - Returns a flag indicating whether the image is ready to be downloaded fom the camera - - - If true, there is an image from the camera available. If false, no image - is available and attempts to use the method will produce an exception - . - true if [image ready]; otherwise, false. - hardware or communications connection error has occurred. - - - - Returns a flag indicating whether the camera is currrently in a PulseGuide operation. - - - If true, pulse guiding is in progress. Required if the PulseGuide method - (which is non-blocking) is implemented. See the PulseGuide method. - - - true if this instance is pulse guiding; otherwise, false. - - hardware or communications connection error has occurred. - - - - Reports the actual exposure duration in seconds (i.e. shutter open time). - - - This may differ from the exposure time requested due to shutter latency, camera timing precision, etc. - - The last duration of the exposure. - Must throw an exception if not supported - If called before any exposure has been taken - - - - Reports the actual exposure start in the FITS-standard CCYY-MM-DDThh:mm:ss[.sss...] format. - The start time must be UTC. - - The last exposure start time in UTC. - Must throw an exception if not supported - If called before any exposure has been taken - - - - Reports the maximum ADU value the camera can produce. - - The maximum ADU. - Must throw exception if data unavailable. - - - - Returns the maximum allowed binning for the X camera axis - - - If = false, returns the maximum allowed binning factor. If - = true, returns the maximum allowed binning factor for the X axis. - - The max bin X. - Must throw exception if data unavailable. - - - - Returns the maximum allowed binning for the Y camera axis - - - If = false, equals . If = true, - returns the maximum allowed binning factor for the Y axis. - - The max bin Y. - Must throw exception if data unavailable. - - - - Sets the subframe width. Also returns the current value. - - - If binning is active, value is in binned pixels. No error check is performed when the value is set. - Should default to . - - The num X. - - - - Sets the subframe height. Also returns the current value. - - - If binning is active, - value is in binned pixels. No error check is performed when the value is set. - Should default to . - - The num Y. - - - - Returns the width of the CCD chip pixels in microns. - - The pixel size X. - Must throw exception if data unavailable. - - - - Returns the height of the CCD chip pixels in microns. - - The pixel size Y. - Must throw exception if data unavailable. - - - - Activates the Camera's mount control sytem to instruct the mount to move in a particular direction for a given period of time - - -

    May throw a not implemented exception if this camera does not support PulseGuide

    - This method returns only after the move has completed. - - The (symbolic) values for GuideDirections are: - - Constant Value Description - guideNorth 0 North (+ declination/elevation) - guideSouth 1 South (- declination/elevation) - guideEast 2 East (+ right ascension/azimuth) - guideWest 3 West (+ right ascension/azimuth) - - - Note: directions are nominal and may depend on exact mount wiring. - must be opposite , and - must be opposite . -
    - The direction of movement. - The duration of movement in milli-seconds. - PulseGuide command is unsupported - PulseGuide command is unsuccessful - Thrown if the driver is not connected. -
    - - - Sets the camera cooler setpoint in degrees Celsius, and returns the current setpoint. - - - The driver should throw an if an attempt is made to set - outside the valid range for the camera. As an assitance to driver authors, to protect equipment and prevent harm to individuals, - Conform will report an issue if it is possible to set below -280C or above +100C. - Note: Camera hardware and/or driver should perform cooler ramping, to prevent - thermal shock and potential damage to the CCD array or cooler stack. - - The set CCD temperature. - Must throw exception if command not successful. - Must throw an InvalidValueException if an attempt is made to set a value is outside the - camera's valid termperature setpoint range. - Must throw exception if is false. - Thrown if the driver is not connected. - - - - Starts an exposure. Use to check when the exposure is complete. - - -

    Must be implemented, must not throw a MethodNotImplementedException.

    - A dark frame or bias exposure may be shorter than the V2 value and for a bias frame can be zero. - Check the value of Light and allow exposures down to 0 seconds - if Light is false. If the hardware will not - support an exposure duration of zero then, for dark and bias frames, set it to the minimum that is possible. - Some applications will set an exposure time of zero for bias frames so it's important that the driver allows this. -
    - Duration of exposure in seconds, can be zero if Light is false - true for light frame, false for dark frame (ignored if no shutter) - , , , - , , , or Duration parameters are invalid. - is false and != - the exposure cannot be started for any reason, such as a hardware or communications error -
    - - - Sets the subframe start position for the X axis (0 based) and returns the current value. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If binning is active, value is in binned pixels. -
    - The start X. - Thrown if the driver is not connected. -
    - - - Sets the subframe start position for the Y axis (0 based). Also returns the current value. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If binning is active, value is in binned pixels. -
    - The start Y. - Thrown if the driver is not connected. -
    - - - Stops the current exposure, if any. - - -

    May throw a not implemented exception

    - If an exposure is in progress, the readout process is initiated. Ignored if readout is already in process. -
    - Must throw an exception if CanStopExposure is false - Must throw an exception if the camera or connection has an error condition - Must throw an exception if for any reason no image readout will be available. -
    - - - Returns the X offset of the Bayer matrix, as defined in . - - The Bayer colour matrix X offset, as defined in . - Monochrome cameras must throw this exception, colour cameras must not. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    Must be implemented by colour cameras, monochrome cameras must throw a PropertyNotImplementedException

    - Since monochrome cameras don't have a bayer colour matrix by definition, such cameras shold throw a . - Colour cameras should always return a value and must not throw a - The value returned must be in the range 0 to M-1 where M is the width of the Bayer matrix. The offset is relative to the 0,0 pixel in - the sensor array, and does not change to reflect subframe settings. - It is recommended that this function be called only after a connection is established with - the camera hardware, to ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Returns the Y offset of the Bayer matrix, as defined in . - - The Bayer colour matrix Y offset, as defined in . - Monochrome cameras must throw this exception, colour cameras must not. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    Must be implemented by colour cameras, monochrome cameras must throw a PropertyNotImplementedException

    - Since monochrome cameras don't have a bayer colour matrix by definition, such cameras shold throw a . - Colour cameras should always return a value and must not throw a - The value returned must be in the range 0 to M-1 where M is the width of the Bayer matrix. The offset is relative to the 0,0 pixel in - the sensor array, and does not change to reflect subframe settings. - It is recommended that this function be called only after a connection is established with - the camera hardware, to ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Camera has a fast readout mode - - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - true when the camera supports a fast readout mode -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - It is recommended that this function be called only after a connection is established with the camera hardware, to - ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Returns the maximum exposure time supported by StartExposure. - - The maximum exposure time, in seconds, that the camera supports - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - It is recommended that this function be called only after - a connection is established with the camera hardware, to ensure that the driver is aware of the capabilities of the - specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Minimium exposure time - - The minimum exposure time, in seconds, that the camera supports through StartExposure - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This must be a non-zero number representing the shortest possible exposure time supported by the camera model. - Please note that for bias frame acquisition an even shorter exposure may be possible; please see StartExposure - for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Exposure resolution - - The smallest increment in exposure time supported by StartExposure. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This can be used, for example, to specify the resolution of a user interface "spin control" used to dial in the exposure time. - Please note that the Duration provided to StartExposure does not have to be an exact multiple of this number; - the driver should choose the closest available value. Also in some cases the resolution may not be constant over the full range - of exposure times; in this case the smallest increment would be appropriate. A value of 0.0 shall indicate that there is no minimum resulution - except that imposed by the resolution of the double value itself. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Gets or sets Fast Readout Mode - - true for fast readout mode, false for normal mode - Thrown if is false. - Thrown if the driver is not connected and a connection is required to obtain this information. -

    Must throw a PropertyNotImplementedException if CanFastReadout is false or - return a boolean value if CanFastReadout is true.

    - Must thrown an exception if no connection is established to the camera. Must throw - a if returns false. - Many cameras have a "fast mode" intended for use in focusing. When set to true, the camera will operate in Fast mode; when - set false, the camera will operate normally. This property, if implemented, should default to False. - Please note that this function may in some cases interact with ; for example, there may be modes where - the Fast/Normal switch is meaningless. In this case, it may be preferable to use the function to control - fast/normal switching. - If this feature is not available, then must return false. - This is only available for the Camera Interface Version 2 -
    -
    - - - Index into the array for the selected camera gain - - Short integer index for the current camera gain in the string array. - Index into the Gains array for the selected camera gain - Must throw an exception if gain is not supported - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. -

    May throw a PropertyNotImplementedException if Gain is not supported by the camera.

    - can be used to adjust the gain setting of the camera, if supported. There are two typical usage scenarios: -
      -
    • DSLR Cameras - will return a 0-based array of strings, which correspond to different gain settings such as - "ISO 800". must be set to an integer in this range. and must thrown an exception if - this mode is used.
    • -
    • Adjustable gain CCD cameras - and return integers, which specify the valid range for and .
    • -
    -The driver must default to a valid value. -Please note that may in some cases affect the gain of the camera; if so the driver must be written such - that the two properties do not conflict if both are used. - This is only available for the Camera Interface Version 2 -
    -
    - - - Maximum value of - - Short integer representing the maximum gain value supported by the camera. - The maximum gain value that this camera supports - Must throw an exception if GainMax is not supported - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    May throw a PropertyNotImplementedException if GainMax is not supported by the camera..

    - When specifying the gain setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Minimum value of - - The minimum gain value that this camera supports - Must throw an exception if GainMin is not supported - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    May throw a PropertyNotImplementedException if GainMin is not supported by the camera.

    - When specifying the gain setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Gains supported by the camera - - An ArrayList of gain names - Must throw an exception if Gains is not supported - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    May throw a PropertyNotImplementedException if Gains is not supported by the camera.

    - provides a 0-based array of available gain settings. This is often used to specify ISO settings for DSLR cameras. - Typically the application software will display the available gain settings in a drop list. The application will then supply - the selected index to the driver via the property. - The setting may alternatively be specified using integer values; if this mode is used then is invalid - and must throw an exception. Please see and for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, - to ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Percent conpleted, Interface Version 2 only - - A value between 0 and 100% indicating the completeness of this operation - Must throw an exception if PercentCompleted is not supported - Thrown when it is inappropriate to call -

    May throw a PropertyNotImplementedException if PercentCompleted is not supported by the camera.

    - If valid, returns an integer between 0 and 100, where 0 indicates 0% progress (function just started) and - 100 indicates 100% progress (i.e. completion). - At the discretion of the driver author, may optionally be valid - when is in any or all of the following - states: , - , - or . In all other states an exception shall be thrown. - Typically the application user interface will show a progress bar based on the value. - Please note that client applications are not required to use this value, and in some cases may display status - information based on other information, such as time elapsed. - This is only available for the Camera Interface Version 2 -
    -
    - - - Readout mode, Interface Version 2 only - - - Short integer index into the ReadoutModes array of string readout mode names indicating - the camera's current readout mode. - Must throw an exception if set to an illegal or unavailable mode. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    Must be implemented if CanFastReadout is false, must throw a PropertyNotImplementedException if - CanFastReadout is true.

    - is an index into the array , and selects the desired readout mode for the camera. - Defaults to 0 if not set. Throws an exception if the selected mode is not available. - It is strongly recommended, but not required, that driver authors make the 0-index mode suitable for standard imaging operations, - since it is the default. - Please see for additional information. - This is only available for the Camera Interface Version 2 -
    -
    - - - List of available readout modes, Interface Version 2 only - - An ArrayList of readout mode names - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    Must be implemented if CanFastReadout is false, must throw a PropertyNotImplementedException if - CanFastReadout is true.

    - This property provides an array of strings, each of which describes an available readout mode of the camera. - At least one string must be present in the list. The user interface of a control application will typically present to the - user a drop-list of modes. The choice of available modes made available is entirely at the discretion of the driver author. - Please note that if the camera has many different modes of operation, then the most commonly adjusted settings should be in - ; additional settings may be provided using . - To select a mode, the application will set to the index of the desired mode. The index is zero-based. - This property should only be read while a connection to the camera is actually established. Drivers often support - multiple cameras with different capabilities, which are not known until the connection is made. If the available readout modes - are not known because no connection has been established, this property shall throw an exception. - Please note that the default setting is 0. It is strongly recommended, but not required, that - driver authors use the 0-index mode for standard imaging operations, since it is the default. - This feature may be used in parallel with ; however, care should be taken to ensure that the two - features work together consistently. If there are modes that are inconsistent having a separate fast/normal switch, then it - may be better to simply list Fast as one of the . - It is recommended that this function be called only after a connection is established with - the camera hardware, to ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Sensor name, Interface Version 2 only - ## Mandatory must return an empty string if the sensor is unknown - - The name of the sensor used within the camera. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    May throw a PropertyNotImplementedException if the sensor's name is not known.

    - Returns the name (datasheet part number) of the sensor, e.g. ICX285AL. The format is to be exactly as shown on - manufacturer data sheet, subject to the following rules: - - All letters shall be uppercase. - Spaces shall not be included. - Any extra suffixes that define region codes, package types, temperature range, coatings, grading, color/monochrome, - etc. shall not be included. - For color sensors, if a suffix differentiates different Bayer matrix encodings, it shall be included. - The call shall return an empty string if the sensor name is not known. - - Examples: - - ICX285AL-F shall be reported as ICX285 - KAF-8300-AXC-CD-AA shall be reported as KAF-8300 - - Note: - The most common usage of this property is to select approximate color balance parameters to be applied to - the Bayer matrix of one-shot color sensors. Application authors should assume that an appropriate IR cutoff filter is - in place for color sensors. - It is recommended that this function be called only after a connection is established with - the camera hardware, to ensure that the driver is aware of the capabilities of the specific camera model. - This is only available for the Camera Interface Version 2 -
    -
    - - - Type of colour information returned by the the camera sensor, Interface Version 2 only - - - The enum value of the camera sensor - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) -

    May throw a PropertyNotImplementedException if the sensor type is not known.

    - This is only available for the Camera Interface Version 2 - returns a value indicating whether the sensor is monochrome, or what Bayer matrix it encodes. If this value - cannot be determined by interrogating the camera, the appropriate value may be set through the user setup dialogue or the property may - return a . Please note that for some cameras, changing , - or may change the apparent type of the sensor and so you should change the value returned here - to match if this is the case for your camera. - The following values are defined: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Value - Enumeration - Meaning
    - 0 - Monochrome - Camera produces monochrome array with no Bayer encoding
    - 1 - Colour - Camera produces color image directly, requiring not Bayer decoding
    - 2 - RGGB - Camera produces RGGB encoded Bayer array images
    - 3 - CMYG - Camera produces CMYG encoded Bayer array images
    - 4 - CMYG2 - Camera produces CMYG2 encoded Bayer array images
    - 5 - LRGB - Camera produces Kodak TRUESENSE Bayer LRGB array images
    -
    - Please note that additional values may be defined in future updates of the standard, as new Bayer matrices may be created - by sensor manufacturers in the future. If this occurs, then a new enumeration value shall be defined. The pre-existing enumeration - values shall not change. - can possibly change between exposures, for example if Camera.ReadoutMode is changed, and should always be checked after each exposure. - In the following definitions, R = red, G = green, B = blue, C = cyan, M = magenta, Y = yellow. The Bayer matrix is - defined with X increasing from left to right, and Y increasing from top to bottom. The pattern repeats every N x M pixels for the - entire pixel array, where N is the height of the Bayer matrix, and M is the width. - RGGB indicates the following matrix: - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 - R - G
    - Y = 1 - G - B
    -
    - - CMYG indicates the following matrix: - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 - Y - C
    - Y = 1 - G - M
    -
    - CMYG2 indicates the following matrix: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 - C - Y
    - Y = 1 - M - G
    - Y = 2 - C - Y
    - Y = 3 - G - M
    -
    - - LRGB indicates the following matrix (Kodak TRUESENSE): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1 - X = 2 - X = 3
    - Y = 0 - L - R - L - G
    - Y = 1 - R - L - G - L
    - Y = 2 - L - G - L - B
    - Y = 3 - G - L - B - L
    -
    - - The alignment of the array may be modified by and . - The offset is measured from the 0,0 position in the sensor array to the upper left corner of the Bayer matrix table. - Please note that the Bayer offset values are not affected by subframe settings. - For example, if a CMYG2 sensor has a Bayer matrix offset as shown below, is 0 and is 1: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 - G - M
    - Y = 1 - C - Y
    - Y = 2 - M - G
    - Y = 3 - C - Y
    -
    - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure that - the driver is aware of the capabilities of the specific camera model. -
    -
    - - - Defines the IDome Interface - - - This interface is used to handle a dome, with or without a controllable shutter, and also a roll off roof. - The dome implentation should be self explanatory. - A roll off roof is implemented using the shutter control as the roof. The properties and methods shoud be implented as follows: - - OpenShutter and CloseShutter open and close the roof. - CanFindHome, CanPark,CanSetAltitude, CanSetAzimuth, CanSetPark, CanSlave and CanSyncAzimuth all return false. - CanSetShutter returns true. - ShutterStatus is implemented. - Slewing always returns false. - AbortSlew should stop the shutter moving. - FindHome, Park, SetPark, SlewToAltitude, SlewToAzimuth and SyncToAzimuth all throw the - Altitude and Azimuth throw the . - - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Immediately cancel current dome operation. - - -

    Must be implemented, must not throw a MethodNotImplementedException.

    - Calling this method will immediately disable hardware slewing ( will become False). Raises an error if a communications failure occurs, or if the command is known to have failed. -
    -
    - - - The dome altitude (degrees, horizon zero and increasing positive to 90 zenith). - - If the property is not implemented - - Raises an error only if no altitude control. If actual dome altitude can not be read, then reports back the last slew position. - - - - - Indicates whether the dome is in the home position. Raises an error if not supported. - - This is normally used following a operation. The value is reset with any azimuth slew operation that moves the dome away from the home position. - - - may also become true durng normal slew operations, if the dome passes through the home position and the dome controller hardware is capable of detecting that; - or at the end of a slew operation if the dome comes to rest at the home position. - - - If the property is not implemented - - The home position is normally defined by a hardware sensor positioned around the dome circumference and represents a fixed, known azimuth reference. - For some devices, the home position may represent a small range of azimuth values, rather than a discrete value, since dome inertia, the resolution of the home position sensor and/or the azimuth encoder may be - insufficient to return the exact same azimuth value on each occasion. Some dome controllers, on the other hand, will always force the azimuth reading to a fixed value whenever the home position sensor is active. - Because of these potential differences in behaviour, applications should not rely on the reported azimuth position being identical each time is set true. - - [ASCOM-135] TPL - Updated documentation - - - - True if the dome is in the programmed park position. - - If the property is not implemented - - Set only following a operation and reset with any slew operation. Raises an error if not supported. - - - - - The dome azimuth (degrees, North zero and increasing clockwise, i.e., 90 East, 180 South, 270 West) - - If the property is not implemented - Raises an error only if no azimuth control. If actual dome azimuth can not be read, then reports back last slew position - - - - True if driver can do a search for home position. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if driver is capable of setting dome altitude. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if driver is capable of setting dome altitude. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if driver is capable of setting dome azimuth. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if driver can set the dome park position. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if driver is capable of automatically operating shutter. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - True if the dome hardware supports slaving to a telescope. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - See the notes for the property. -
    -
    - - - True if driver is capable of synchronizing the dome azimuth position using the method. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - Close shutter or otherwise shield telescope from the sky. - - If the method is not implemented - - - - Start operation to search for the dome home position. - - If the method is not implemented - - After Home position is established initializes to the default value and sets the flag. - Exception if not supported or communications failure. Raises an error if is True. - - - - - Open shutter or otherwise expose telescope to the sky. - - If the method is not implemented - - Raises an error if not supported or if a communications failure occurs. - - - - - Rotate dome in azimuth to park position. - - If the method is not implemented - - After assuming programmed park position, sets flag. Raises an error if is True, or if not supported, or if a communications failure has occurred. - - - - - Set the current azimuth, altitude position of dome to be the park position. - - If the method is not implemented - - Raises an error if not supported or if a communications failure occurs. - - - - - Status of the dome shutter or roll-off roof. - - If the property is not implemented - - Raises an error only if no shutter control. If actual shutter status can not be read, then reports back the last shutter state. - - - - - True if the dome is slaved to the telescope in its hardware, else False. - - -

    Slaved Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    Slaved Write can throw a PropertyNotImplementedException.

    - Set this property to True to enable dome-telescope hardware slaving, if supported (see ). Raises an exception on any attempt to set - this property if hardware slaving is not supported). Always returns False if hardware slaving is not supported. -
    -
    - - - True if any part of the dome is currently moving, False if all dome components are steady. - - -

    Slewing must be implemented and must not throw a PropertyNotImplementedException.

    - Raises an error if is True, if not supported, if a communications failure occurs, or if the dome can not reach indicated azimuth. -
    -
    - - - Slew the dome to the given altitude position. - - If the method is not implemented - If the supplied altitude is outside the range 0..90 degrees. - - Raises an error if is True, if not supported, if a communications failure occurs, or if the dome can not reach indicated altitude. - - Target dome altitude (degrees, horizon zero and increasing positive to 90 zenith) - - - - Slew the dome to the given azimuth position. - - If the method is not implemented - If the supplied azimuth is outside the range 0..360 degrees. - - Raises an error if is True, if not supported, if a communications failure occurs, or if the dome can not reach indicated azimuth. - - Target azimuth (degrees, North zero and increasing clockwise. i.e., 90 East, 180 South, 270 West) - - - - Synchronize the current position of the dome to the given azimuth. - - If the method is not implemented - If the supplied azimuth is outside the range 0..360 degrees. - - Raises an error if not supported or if a communications failure occurs. - - Target azimuth (degrees, North zero and increasing clockwise. i.e., 90 East, 180 South, 270 West) - - - - Defines the IFilterWheel Interface - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Focus offset of each filter in the wheel - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - For each valid slot number (from 0 to N-1), reports the focus offset for the given filter position. These values are focuser and filter dependent, and would usually be set up by the user via - the SetupDialog. The number of slots N can be determined from the length of the array. If focuser offsets are not available, then it should report back 0 for all array values. -
    -
    - - - Name of each filter in the wheel - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - For each valid slot number (from 0 to N-1), reports the name given to the filter position. These names would usually be set up by the user via the - SetupDialog. The number of slots N can be determined from the length of the array. If filter names are not available, then it should report back "Filter 1", "Filter 2", etc. -
    -
    - - - Sets or returns the current filter wheel position - - Must throw an InvalidValueException if an invalid position is set - Must throw an exception if the Filter Wheel is not connected - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - Write a position number between 0 and N-1, where N is the number of filter slots (see ). Starts filter wheel rotation immediately when written. Reading - the property gives current slot number (if wheel stationary) or -1 if wheel is moving. - Returning a position of -1 is mandatory while the filter wheel is in motion; valid slot numbers must not be reported back while the filter wheel is rotating past filter positions. - Note - Some filter wheels are built into the camera (one driver, two interfaces). Some cameras may not actually rotate the wheel until the exposure is triggered. In this case, the written value is available - immediately as the read value, and -1 is never produced. -
    -
    - - - Provides universal access to Focuser drivers - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. - The Connected property is not implemented in Version 1 drivers; these use the - property and will raise a Not Implemented exception for this property. Version 2 drivers must implement both Connected and Link. - Applications should check that InterfaceVersion returns 2 or more before using Connected. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - True if the focuser is capable of absolute position; that is, being commanded to a specific step location. - - If the driver must be connected in order to determine the property value. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Immediately stop any focuser motion due to a previous method call. - - Focuser does not support this method. - If the driver is not connected. - Must throw an exception if the call was not successful - -

    Can throw a not implemented exception

    Some focusers may not support this function, in which case an exception will be raised. - Recommendation: Host software should call this method upon initialization and, - if it fails, disable the Halt button in the user interface. -
    -
    - - - True if the focuser is currently moving to a new position. False if the focuser is stationary. - - If the driver is not connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - State of the connection to the focuser. - - - Must throw an exception if the call was not successful -

    Must be implemented

    Set True to start the connection to the focuser; set False to terminate the connection. - The current connection status can also be read back through this property. - An exception will be raised if the link fails to change state for any reason. - Note - The FocuserV1 interface was the only interface to name its "Connect" method "Link" all others named - their "Connect" method as "Connected". All interfaces including Focuser now have a method and this is - the recommended method to use to "Connect" to Focusers exposing the V2 and later interfaces. - Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. -
    -
    - - - Maximum increment size allowed by the focuser; - i.e. the maximum number of steps allowed in one move operation. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - For most focusers this is the same as the property. This is normally used to limit the Increment display in the host software. -
    -
    - - - Maximum step position permitted. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - The focuser can step between 0 and . If an attempt is made to move the focuser beyond these limits, it will automatically stop at the limit. -
    -
    - - - Moves the focuser by the specified amount or to the specified position depending on the value of the property. - - Step distance or absolute position, depending on the value of the property. - If a Move operation is requested when is True - If the device is not connected. - Must throw an exception if the call was not successful -

    Must be implemented

    - If the property is True, then this is an absolute positioning focuser. The Move command tells the focuser to move to an exact step position, and the Position parameter - of the Move method is an integer between 0 and . - If the property is False, then this is a relative positioning focuser. The Move command tells the focuser to move in a relative direction, and the Position parameter - of the Move method (in this case, step distance) is an integer between minus and plus . -
    -
    - - - Current focuser position, in steps. - - If the property is not available for this device. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Can throw a not implemented exception

    Valid only for absolute positioning focusers (see the property). - A PropertyNotImplementedException exception must be thrown if this device is a relative positioning focuser rather than an absolute position focuser. -
    -
    - - - Step size (microns) for the focuser. - - If the focuser does not intrinsically know what the step size is. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    Must throw an exception if the focuser does not intrinsically know what the step size is.
    -
    - - - The state of temperature compensation mode (if available), else always False. - - If is False and an attempt is made to set to true. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    TempComp Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    TempComp Write can throw a PropertyNotImplementedException.

    - If the property is True, then setting to True puts the focuser into temperature tracking mode. While in temperature tracking mode, - Move commands will be rejected by the focuser. Set to False to turn off temperature tracking. - If temperature compensation is not available, this property must always return False. - A exception must be thrown if is False and an attempt is made to set to true. -
    -
    - - - True if focuser has temperature compensation available. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - Will be True only if the focuser's temperature compensation can be turned on and off via the property. -
    -
    - - - Current ambient temperature as measured by the focuser. - - If the property is not available for this device. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    - Raises an exception if ambient temperature is not available. Commonly available on focusers with a built-in temperature compensation mode. -
    -
    - - - Provides universal access to Focuser drivers - Updated to IFocuserV3 - see remarks below - - - SPECIFICATION REVISION - Platform 6.4 - The method signatures in the revised interface specification are identical to the preceeding IFocuserV2, however, the IFocuserV3.Move command must - no longer throw an InvalidOperationException exception if a Move is attempted when temperature compensation is enabled. - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. - The Connected property is not implemented in Version 1 drivers; these use the - property and will raise a Not Implemented exception for this property. Version 2 drivers must implement both Connected and Link. - Applications should check that InterfaceVersion returns 2 or more before using Connected. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 3 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - True if the focuser is capable of absolute position; that is, being commanded to a specific step location. - - If the driver must be connected in order to determine the property value. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Immediately stop any focuser motion due to a previous method call. - - Focuser does not support this method. - If the driver is not connected. - Must throw an exception if the call was not successful - -

    Can throw a not implemented exception

    Some focusers may not support this function, in which case an exception will be raised. - Recommendation: Host software should call this method upon initialization and, - if it fails, disable the Halt button in the user interface. -
    -
    - - - True if the focuser is currently moving to a new position. False if the focuser is stationary. - - If the driver is not connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - State of the connection to the focuser. - - - Must throw an exception if the call was not successful -

    Must be implemented

    Set True to start the connection to the focuser; set False to terminate the connection. - The current connection status can also be read back through this property. - An exception will be raised if the link fails to change state for any reason. - Note - The FocuserV1 interface was the only interface to name its "Connect" method "Link" all others named - their "Connect" method as "Connected". All interfaces including Focuser now have a method and this is - the recommended method to use to "Connect" to Focusers exposing the V2 and later interfaces. - Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. -
    -
    - - - Maximum increment size allowed by the focuser; - i.e. the maximum number of steps allowed in one move operation. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - For most focusers this is the same as the property. This is normally used to limit the Increment display in the host software. -
    -
    - - - Maximum step position permitted. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - The focuser can step between 0 and . If an attempt is made to move the focuser beyond these limits, it will automatically stop at the limit. -
    -
    - - - Moves the focuser by the specified amount or to the specified position depending on the value of the property. - - Step distance or absolute position, depending on the value of the property. - If the device is not connected. - Must throw an exception if the call was not successful -

    Must be implemented

    - If the property is True, then this is an absolute positioning focuser. The Move command tells the focuser to move to an exact step position, and the Position parameter - of the Move method is an integer between 0 and . - If the property is False, then this is a relative positioning focuser. The Move command tells the focuser to move in a relative direction, and the Position parameter - of the Move method (in this case, step distance) is an integer between minus and plus . - BEHAVIOURAL CHANGE - Platform 6.4 - Prior to Platform 6.4, the interface specification mandated that drivers must throw an if a move was attempted when was True, even if the focuser - was able to execute the move safely without disrupting temperature compensation. - Following discussion on ASCOM-Talk in January 2018, the Focuser interface specification has been revised to IFocuserV3, removing the requrement to throw the InvalidOperationException exception. IFocuserV3 compliant drivers - are expected to execute Move requests when temperature compensation is active and to hide any specific actions required by the hardware from the client. For example this could be achieved by disabling temperature compensation, moving the focuser and re-enabling - temperature compensation or simply by moving the focuser with compensation enabled if the hardware supports this. - Conform will continue to pass IFocuserV2 drivers that throw InvalidOperationException exceptions. However, Conform will now fail IFocuserV3 drivers that throw InvalidOperationException exceptions, in line with this revised specification. -
    -
    - - - Current focuser position, in steps. - - If the property is not available for this device. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Can throw a not implemented exception

    Valid only for absolute positioning focusers (see the property). - A PropertyNotImplementedException exception must be thrown if this device is a relative positioning focuser rather than an absolute position focuser. -
    -
    - - - Step size (microns) for the focuser. - - If the focuser does not intrinsically know what the step size is. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    Must throw an exception if the focuser does not intrinsically know what the step size is.
    -
    - - - The state of temperature compensation mode (if available), else always False. - - If is False and an attempt is made to set to true. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    TempComp Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    TempComp Write can throw a PropertyNotImplementedException.

    - If the property is True, then setting to True puts the focuser into temperature tracking mode; setting it to False will turn off temperature tracking. - If temperature compensation is not available, this property must always return False. - A exception must be thrown if is False and an attempt is made to set to true. - BEHAVIOURAL CHANGE - Platform 6.4 - Prior to Platform 6.4, the interface specification mandated that drivers must throw an if a move was attempted when was True, even if the focuser - was able to execute the move safely without disrupting temperature compensation. - Following discussion on ASCOM-Talk in January 2018, the Focuser interface specification has been revised to IFocuserV3, removing the requrement to throw the InvalidOperationException exception. IFocuserV3 compliant drivers - are expected to execute Move requests when temperature compensation is active and to hide any specific actions required by the hardware from the client. For example this could be achieved by disabling temperature compensation, moving the focuser and re-enabling - temperature compensation or simply by moving the focuser with compensation enabled if the hardware supports this. - Conform will continue to pass IFocuserV2 drivers that throw InvalidOperationException exceptions. However, Conform will now fail IFocuserV3 drivers that throw InvalidOperationException exceptions, in line with this revised specification. -
    -
    - - - True if focuser has temperature compensation available. - - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful - -

    Must be implemented

    - Will be True only if the focuser's temperature compensation can be turned on and off via the property. -
    -
    - - - Current ambient temperature as measured by the focuser. - - If the property is not available for this device. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    - Raises an exception if ambient temperature is not available. Commonly available on focusers with a built-in temperature compensation mode. -
    -
    - - - Defines the IObservingConditions Interface. - This interface provides a limited set of values that are useful - for astronomical purposes for things such as determining if it is safe to open or operate the observing system, - for recording astronomical data or determining refraction corrections. - - It is NOT intended as a general purpose environmental sensor system. The Action method and - SupportedActions property can be used to extend your driver to present any further sensors that you need. - - - - - Set to True to connect to the device hardware. Set to False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and model number. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Must return 1 for this interface version. - -

    Must be implemented

    This value will be incremented if the interface - specification is extended in the future. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. - For ObservingConditions drivers the following conventions are recommended: - - The "ActionName" should be the name of a sensor in a form that makes sense to the user. - This must not be changed in the driver. - The "ActionParameter" should be "Value" to return the sensor value and - "Description" to return the sensor description. - The description must return a valid description, even if not connected. - - -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. - See Action for advice on how th implement this for ObservingConditions drivers. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Gets And sets the time period over which observations will be averaged - - Time period (hours) over which to average sensor readings - If the value set is not available for this driver. All drivers must accept 0.0 to specify that - an instantaneous value is available. - If the device is not connected and this information is only available when connected. - -

    Mandatory property, must be implemented, can NOT throw a PropertyNotImplementedException

    - This property should return the time period (hours) over which sensor readings will be averaged. If your driver is delivering instantaneous sensor readings this property should return a value of 0.0. - Please resist the temptation to throw exceptions when clients query sensor properties when insufficient time has passed to get a true average reading. - A best estimate of the average sensor value should be returned in these situations. -
    -
    - - - Amount of sky obscured by cloud - - percentage of the sky covered by cloud - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - This property should return a value between 0.0 and 100.0 where 0.0 = clear sky and 100.0 = 100% cloud coverage -
    -
    - - - Atmospheric dew point at the observatory - - Atmospheric dew point reported in °C. - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException when the property also throws a PropertyNotImplementedException.

    -

    Mandatory property, must NOT throw a PropertyNotImplementedException when the property is implemented.

    - The units of this property are degrees Celsius. Driver and application authors can use the method - to convert these units to and from degrees Farenhheit. - The ASCOM specification requires that DewPoint and Humidity are either both implemented or both throw PropertyNotImplementedExceptions. It is not allowed for - one to be implemented and the other to throw a PropertyNotImplementedException. The Utilities component contains methods ( and - ) to convert DewPoint to Humidity and vice versa given the ambient temperature. -
    -
    - - - Atmospheric humidity at the observatory - - Atmospheric humidity (%) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException when the property also throws a PropertyNotImplementedException.

    -

    Mandatory property, must NOT throw a PropertyNotImplementedException when the property is implemented.

    - The ASCOM specification requires that DewPoint and Humidity are either both implemented or both throw PropertyNotImplementedExceptions. It is not allowed for - one to be implemented and the other to throw a PropertyNotImplementedException. The Utilities component contains methods ( and - ) to convert DewPoint to Humidity and vice versa given the ambient temperature. - This property should return a value between 0.0 and 100.0 where 0.0 = 0% relative humidity and 100.0 = 100% relative humidity. -
    -
    - - - Atmospheric pressure at the observatory - - Atmospheric presure at the observatory (hPa) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are hectoPascals. Client and driver authors can use the method - to convert these units to and from milliBar, mm of mercury and inches of mercury. - This must be the pressure at the observatory altitude and not the adjusted pressure at sea level. - Please check whether your pressure sensor delivers local observatory pressure or sea level pressure and, if it returns sea level pressure, - adjust this to actual pressure at the observatory's altitude before returning a value to the client. - The method can be used to effect this adjustment. - -
    -
    - - - Rain rate at the observatory - - Rain rate (mm / hour) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are millimetres per hour. Client and driver authors can use the method - to convert these units to and from inches per hour. - This property can be interpreted as 0.0 = Dry any positive nonzero value = wet. - Rainfall intensity is classified according to the rate of precipitation: - - Light rain — when the precipitation rate is less than 2.5 mm (0.098 in) per hour - Moderate rain — when the precipitation rate is between 2.5 mm (0.098 in) and 10 mm (0.39 in) per hour - Heavy rain — when the precipitation rate is between 10 mm (0.39 in) and 50 mm (2.0 in) per hour - Violent rain — when the precipitation rate is > 50 mm (2.0 in) per hour - -
    -
    - - - Sky brightness at the observatory - - Sky brightness (Lux) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - This property returns the sky brightness measured in Lux. - Luminance Examples in Lux - - - IlluminanceSurfaces illuminated by: - - 0.0001 luxMoonless, overcast night sky (starlight) - 0.002 luxMoonless clear night sky with airglow - 0.27–1.0 luxFull moon on a clear night - 3.4 luxDark limit of civil twilight under a clear sky - 50 luxFamily living room lights (Australia, 1998) - 80 luxOffice building hallway/toilet lighting - 100 luxVery dark overcast day - 320–500 luxOffice lighting - 400 luxSunrise or sunset on a clear day. - 1000 luxOvercast day; typical TV studio lighting - 10000–25000 luxFull daylight (not direct sun) - 32000–100000 luxDirect sunlight - -
    -
    - - - Sky quality at the observatory - - Sky quality measured in magnitudes per square arc second - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - Sky quality is typically measured in units of magnitudes per square arc second. A sky quality of 20 magnitudes per square arc second means that the - overall sky appears with a brightness equivalent to having 1 magnitude 20 star in each square arc second of sky. - Examples of typical sky quality values were published by Sky and Telescope (http://www.skyandtelescope.com/astronomy-resources/rate-your-skyglow/) and, in slightly adpated form, are reproduced below: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Sky Quality (mag/arcsec2) - Description
    - 22.0 - By convention, this is often assumed to be the average brightness of a moonless night sky that's completely free of artificial light pollution.
    - 21.0 - This is typical for a rural area with a medium-sized city not far away. It's comparable to the glow of the brightest section of the northern Milky Way, from Cygnus through Perseus.
    - 20.0 - This is typical for the outer suburbs of a major metropolis. The summer Milky Way is readily visible but severely washed out.
    - 19.0 - Typical for a suburb with widely spaced single-family homes. It's a little brighter than a remote rural site at the end of nautical twilight, when the Sun is 12° below the horizon.
    - 18.0 - Bright suburb or dark urban neighborhood. It's also a typical zenith skyglow at a rural site when the Moon is full. The Milky Way is invisible, or nearly so.
    - 17.0 - Typical near the center of a major city.
    - 13.0 - The zenith skyglow at the end of civil twilight, roughly a half hour after sunset, when the Sun is 6° below the horizon. Venus and Jupiter are easy to see, but bright stars are just beginning to appear.
    - 7.0 - The zenith skyglow at sunrise or sunset
    -
    -
    -
    - - - Seeing at the observatory measured as star full width half maximum (FWHM) in arc secs. - - Seeing reported as star full width half maximum (arc seconds) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    -
    -
    - - - Sky temperature at the observatory - - Sky temperature in °C - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are degrees Celsius. Driver and application authors can use the method - to convert these units to and from degrees Farenhheit. - This is expected to be returned by an infra-red sensor looking at the sky. The lower the temperature the more the sky is likely to be clear. -
    -
    - - - Temperature at the observatory - - Temperature in °C - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are degrees Celsius. Driver and application authors can use the method - to convert these units to and from degrees Farenhheit. - This is expected to be the ambient temperature at the observatory. -
    -
    - - - Wind direction at the observatory - - Wind direction (degrees, 0..360.0) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The returned value must be between 0.0 and 360.0, interpreted according to the metereological standard, where a special value of 0.0 is returned when the wind speed is 0.0. - Wind direction is measured clockwise from north, through east, where East=90.0, South=180.0, West=270.0 and North=360.0. -
    -
    - - - Peak 3 second wind gust at the observatory over the last 2 minutes - - Wind gust (m/s) Peak 3 second wind speed over the last 2 minutes - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are metres per second. Driver and application authors can use the method - to convert these units to and from miles per hour or knots. -
    -
    - - - Wind speed at the observatory - - Wind speed (m/s) - If this property is not available. - If the device is not connected and this information is only available when connected. - -

    Optional property, can throw a PropertyNotImplementedException

    - The units of this property are metres per second. Driver and application authors can use the method - to convert these units to and from miles per hour or knots. -
    -
    - - - Provides the time since the sensor value was last updated - - Name of the property whose time since last update is required - Time in seconds since the last sensor update for this property - If the sensor is not implemented. - If the device is not connected and this information is only available when connected. - If an invalid property name parameter is supplied. - -

    Must Not throw a MethodNotImplementedException when the specified sensor Is implemented but must throw a MethodNotImplementedException when the specified sensor Is Not implemented.

    - PropertyName must be the name of one of the sensor properties specified in the interface. If the caller supplies some other value, throw an InvalidValueException. - Return a negative value to indicate that no valid value has ever been received from the hardware. - If an empty string is supplied as the PropertyName, the driver must return the time since the most recent update of any sensor. A MethodNotImplementedException must not be thrown in this circumstance. -
    -
    - - - Provides a description of the sensor providing the requested property - - Name of the sensor whose description is required - The description of the specified sensor. - If the sensor is not implemented. - If the device is not connected and this information is only available when connected. - If an invalid property name parameter is supplied. - -

    Must Not throw a MethodNotImplementedException when the specified sensor Is implemented - but must throw a MethodNotImplementedException when the specified sensor Is Not implemented.

    - PropertyName must be the name of one of the sensor properties specified in the interface. If the caller supplies some other value, throw an InvalidValueException. - If the sensor is implemented, this must return a valid string, even if the driver is not connected, so that applications can use this to determine what sensors are available. - If the sensor is not implemented, this must throw a MethodNotImplementedException. -
    -
    - - - Forces the driver to immediately query its attached hardware to refresh sensor values - - If this method is not available. - If the device is not connected. - -

    Optional method, can throw a MethodNotImplementedException

    -
    -
    - - - Describes a range of rates supported by the method (degrees/per second) - These are contained within an collection and serve to describe one or more supported ranges of rates of motion about a mechanical axis. - It is possible that the and properties will be equal. In this case, the object expresses a single discrete rate. - Both the and properties are always expressed in units of degrees per second. - This is only using for Telescope InterfaceVersions 2 and 3 - - Values used must be non-negative and are scalar values. You do not need to supply complementary negative rates for each positive - rate that you specify. Movement in both directions is achieved by the application applying an appropriate positive or negative sign to the - rate when it is used in the command. - - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - The maximum rate (degrees per second) - This must always be a positive number. It indicates the maximum rate in either direction about the axis. - - - - - The minimum rate (degrees per second) - This must always be a positive number. It indicates the maximum rate in either direction about the axis. - - - - - Defines the IRotator Interface - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Indicates whether the Rotator supports the method. - - - True if the Rotator supports the method. - - -

    Must be implemented and must not throw a PropertyNotImplementedException.

    -
    -
    - - - Immediately stop any Rotator motion due to a previous Move or MoveAbsolute method call. - - This is an optional method. Raises an error if not supported. - Throw a MethodNotImplementedException if the rotator cannot halt. - - - - Indicates whether the rotator is currently moving - - True if the Rotator is moving to a new position. False if the Rotator is stationary. - If the property is not implemented. - Rotation is asynchronous, that is, when the Move method is called, it starts the rotation, then returns - immediately. During rotation, must be True, else it must be False. - - - - Causes the rotator to move Position degrees relative to the current value. - - If the method is not implemented. - If Position is invalid. - Relative position to move in degrees from current . - - Calling Move causes the property to change to the sum of the current angular position - and the value of the parameter (modulo 360 degrees), then starts rotation to . - - - - - Causes the rotator to move the absolute position of degrees. - - Absolute position in degrees. - If the method is not implemented. - If Position is invalid. - Calling MoveAbsolute causes the property to change to the value of the - parameter, then starts rotation to . - - - - Current instantaneous Rotator position, in degrees. - - If the property is not implemented. - - The position is expressed as an angle from 0 up to but not including 360 degrees, counter-clockwise against the - sky. This is the standard definition of Position Angle. However, the rotator does not need to (and in general will not) - report the true Equatorial Position Angle, as the attached imager may not be precisely aligned with the rotator's indexing. - It is up to the client to determine any offset between mechanical rotator position angle and the true Equatorial Position - Angle of the imager, and compensate for any difference. - The optional property is provided in order to manage rotators being used on optics with odd or - even number of reflections. With the Reverse switch in the correct position for the optics, the reported position angle must - be counter-clockwise against the sky. - - - - - Sets or Returns the rotator’s Reverse state. - - True if the rotation and angular direction must be reversed for the optics - Throw a PropertyNotImplementedException if the rotator cannot reverse and CanReverse is False. - See the definition of . Raises an error if not supported. - - - - The minimum StepSize, in degrees. - - Throw a PropertyNotImplementedException if the rotator does not know its step size. - - Raises an exception if the rotator does not intrinsically know what the step size is. - - - - - The destination position angle for Move() and MoveAbsolute(). - - The destination position angle forMove and MoveAbsolute. - If the property is not implemented. - - Upon calling Move or MoveAbsolute, this property immediately changes to the position angle to which the rotator is moving. The value is retained until a subsequent call - to Move or MoveAbsolute. - - - - - Defines the ISwitchV2 Interface - - - The Switch interface is used to define a number of 'switch devices'. A switch device can be used to control something, such as a power switch - or may be used to sense the state of something, such as a limit switch. - This SwitchV2 interface is an extension of the original Switch interface. The changes allow devices to have more than two states and - to distinguish between devices that are writable and those that are read only. - Compatibility between Switch and SwitchV2 interfaces: - Switch devices that implemented the original Switch interface and - client applications that use the original interface will still work together. - Client applications that implement the original - Switch interface should still work with drivers that implement the new interface. - Client applications that use the new features in this interface - will not work with drivers that do not implement the new interface. - - Each device has a CanWrite method, this is true if it can be written to or false if the device can only be read. - The new MinSwitchValue, MaxSwitchValue and SwitchStep methods are used to define the range and values that a device can handle. - This also defines the number of different values - states - that a device can have, from two for a traditional on-off switch, through - those with a small number of states to those which have many states. - The SetSwitchValue and GetSwitchValue methods are used to set and get the value of a device as a double. - There is no fundamental difference between devices with different numbers of states. - Naming Conventions - Each device handled by a Switch is known as a device or switch device for general cases, - a controller device if it can alter the state of the device and a sensor device if it can only be read. - For convenience devices are referred to as boolean if the device can only have two states, and multi-state if it can have more than two values. - These are treated the same in the interface definition. - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - The number of switch devices managed by this driver - - The number of devices managed by this driver. -

    Must be implemented, must not throw a

    -

    Devices are numbered from 0 to - 1

    -
    - - - Return the name of switch device n. - - The device number (0 to - 1) - The name of the device - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw an ASCOM.MethodNotImplementedException

    - Devices are numbered from 0 to - 1
    -
    - - - Set a switch device name to a specified value. - - The device number (0 to - 1) - The name of the device - If the device name cannot be set in the application code. - If id is outside the range 0 to - 1 -

    Can throw a if the device name can not be set by the application.

    - Devices are numbered from 0 to - 1 -
    -
    - - - Gets the description of the specified switch device. This is to allow a fuller description of - the device to be returned, for example for a tool tip. - - The device number (0 to - 1) - - String giving the device description. - - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw an ASCOM.MethodNotImplementedException

    - Decices are numbered from 0 to - 1 - This is a Version 2 method. -
    -
    - - - Reports if the specified switch device can be written to, default true. - This is false if the device cannot be written to, for example a limit switch or a sensor. - - The device number (0 to - 1) - - true if the device can be written to, otherwise false. - - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw an ASCOM.MethodNotImplementedException

    - Devices are numbered from 0 to - 1 - This is a Version 2 method, version 1 switch devices can be assumed to be writable. -
    -
    - - - Return the state of switch device id as a boolean - - The device number (0 to - 1) - True or false - If id is outside the range 0 to - 1 - If there is a temporary condition that prevents the device value being returned. -

    Must be implemented, must not throw a .

    - All devices must implement this. A multi-state device will return true if the device is at the maximum value, false if the value is at the minumum - and either true or false as specified by the driver developer for intermediate values. - Some devices do not support reading their state although they do allow state to be set. In these cases, on startup, the driver can not know the hardware state and it is recommended that the - driver either: - - Sets the device to a known state on connection - Throws an until the client software has set the device state for the first time - - In both cases the driver should save a local copy of the state which it last set and return this through and - Devices are numbered from 0 to - 1
    -
    - - - Sets a switch controller device to the specified state, true or false. - - The device number (0 to - 1) - The required control state - If id is outside the range 0 to - 1 - If is false. -

    Can throw a if is False.

    - must return if the set state is true and if the set state is false. - Devices are numbered from 0 to - 1
    -
    - - - Returns the maximum value for this switch device, this must be greater than . - - The device number (0 to - 1) - The maximum value to which this device can be set or which a read only sensor will return. - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw a .

    - If a two state device cannot report its state, should return the value 1.0. - Devices are numbered from 0 to - 1. - This is a Version 2 method. -
    -
    - - - Returns the minimum value for this switch device, this must be less than - - The device number (0 to - 1) - The minimum value to which this device can be set or which a read only sensor will return. - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw a .

    - If a two state device cannot report its state, should return the value 0.0. - Devices are numbered from 0 to - 1. - This is a Version 2 method. -
    -
    - - - Returns the step size that this device supports (the difference between successive values of the device). - - The device number (0 to - 1) - The step size for this device. - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw .

    - SwitchStep, MinSwitchValue and MaxSwitchValue can be used to determine the way the device is controlled and/or displayed, - for example by setting the number of decimal places or number of states for a display. - must be greater than zero and the number of steps can be calculated as: - (( - ) / ) + 1. - The switch range ( - ) must be an exact multiple of . - If a two state device cannot report its state, should return the value 1.0. - Devices are numbered from 0 to - 1. - This is a Version 2 method. -
    -
    - - - Returns the value for switch device id as a double - - The device number (0 to - 1) - The value for this switch, this is expected to be between and - . - If there is a temporary condition that prevents the device value being returned. - If id is outside the range 0 to - 1 -

    Must be implemented, must not throw a .

    - Some devices do not support reading their state although they do allow state to be set. In these cases, on startup, the driver can not know the hardware state and it is recommended that the - driver either: - - Sets the device to a known state on connection - Throws an until the client software has set the device state for the first time - - In both cases the driver should save a local copy of the state which it last set and return this through and - Devices are numbered from 0 to - 1. - This is a Version 2 method. -
    -
    - - - Set the value for this device as a double. - - The device number (0 to - 1) - The value to be set, between and - If id is outside the range 0 to - 1 - If value is outside the range to - If is false. -

    Can throw a if is False.

    - If the value is more than or less than - then the method must throw an . - A set value that is intermediate between the values specified by should result in the device being set to an achievable value close to the requested set value. - Devices are numbered from 0 to - 1. - This is a Version 2 method. -
    -
    - - - Defines the ITelescope Interface - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 3 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Stops a slew in progress. - - If the method is not implemented - - Effective only after a call to , , , or . - Does nothing if no slew/motion is in progress. Tracking is returned to its pre-slew state. Raises an error if is true. - - - - - The alignment mode of the mount (Alt/Az, Polar, German Polar). - - If the property is not implemented - - This is only available for telescope InterfaceVersions 2 and 3 - - - - - The Altitude above the local horizon of the telescope's current position (degrees, positive up) - - If the property is not implemented - - - - The area of the telescope's aperture, taking into account any obstructions (square meters) - - - This is only available for telescope InterfaceVersions 2 and 3 - - If the property is not implemented - - - - The telescope's effective aperture diameter (meters) - - - This is only available for telescope InterfaceVersions 2 and 3 - - If the property is not implemented - - - - True if the telescope is stopped in the Home position. Set only following a operation, - and reset with any slew operation. This property must be False if the telescope does not support homing. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if the telescope has been put into the parked state by the seee method. Set False by calling the Unpark() method. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - AtPark is True when the telescope is in the parked state. This is achieved by calling the method. When AtPark is true, - the telescope movement is stopped (or restricted to a small safe range of movement) and all calls that would cause telescope - movement (e.g. slewing, changing Tracking state) must not do so, and must raise an error. - The telescope is taken out of parked state by calling the method. If the telescope cannot be parked, - then AtPark must always return False. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - Determine the rates at which the telescope may be moved about the specified axis by the method. - - The axis about which rate information is desired (TelescopeAxes value) - Collection of rate objects - If an invalid Axis is specified. - -

    Must be implemented, must not throw a MethodNotImplementedException.

    - See the description of for more information. This method must return an empty collection if is not supported. - This is only available for telescope InterfaceVersions 2 and 3 - - Please note that the rate objects must contain absolute non-negative values only. Applications determine the direction by applying a - positive or negative sign to the rates provided. This obviates the need for the driver to to present a duplicate set of negative rates - as well as the positive rates. -
    -
    - - - The azimuth at the local horizon of the telescope's current position (degrees, North-referenced, positive East/clockwise). - - If the property is not implemented - - - - True if this telescope is capable of programmed finding its home position ( method). - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if this telescope can move the requested axis - - Primary, Secondary or Tertiary axis - Boolean indicating can or can not move the requested axis - If an invalid Axis is specified. - -

    Must be implemented, must not throw a MethodNotImplementedException.

    - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if this telescope is capable of programmed parking (method) - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if this telescope is capable of software-pulsed guiding (via the method) - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if the property can be changed to provide offset tracking in the declination axis. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if the guide rate properties used for can ba adjusted. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if this telescope is capable of programmed setting of its park position ( method) - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if the property can be set, meaning that the mount can be forced to flip. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This will always return False for non-German-equatorial mounts that do not have to be flipped. - May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - True if the property can be changed to provide offset tracking in the right ascension axis. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if the property can be changed, turning telescope sidereal tracking on and off. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed slewing (synchronous or asynchronous) to equatorial coordinates - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If this is true, then only the synchronous equatorial slewing methods are guaranteed to be supported. - See the property for the asynchronous slewing capability flag. - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed slewing (synchronous or asynchronous) to local horizontal coordinates - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If this is true, then only the synchronous local horizontal slewing methods are guaranteed to be supported. - See the property for the asynchronous slewing capability flag. - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed asynchronous slewing to local horizontal coordinates - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This indicates the the asynchronous local horizontal slewing methods are supported. - If this is True, then will also be true. - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed asynchronous slewing to equatorial coordinates. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - This indicates the the asynchronous equatorial slewing methods are supported. - If this is True, then will also be true. - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed synching to equatorial coordinates. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed synching to local horizontal coordinates - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - May raise an error if the telescope is not connected. -
    -
    - - - True if this telescope is capable of programmed unparking ( method). - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - If this is true, then will also be true. May raise an error if the telescope is not connected. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - The declination (degrees) of the telescope's current equatorial coordinates, in the coordinate system given by the property. - Reading the property will raise an error if the value is unavailable. - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    -
    -
    - - - The declination tracking rate (arcseconds per SI second, default = 0.0) - - If DeclinationRate Write is not implemented. - -

    DeclinationRate Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    DeclinationRate Write can throw a PropertyNotImplementedException.

    - This property, together with , provides support for "offset tracking". - Offset tracking is used primarily for tracking objects that move relatively slowly against the equatorial coordinate system. - It also may be used by a software guiding system that controls rates instead of using the PulseGuide method. - - NOTES: - - - The property value represents an offset from zero motion. - If is False, this property will always return 0. - To discover whether this feature is supported, test the property. - The supported range of this property is telescope specific, however, if this feature is supported, - it can be expected that the range is sufficient to allow correction of guiding errors caused by moderate misalignment - and periodic error. - If this property is non-zero when an equatorial slew is initiated, the telescope should continue to update the slew - destination coordinates at the given offset rate. - This will allow precise slews to a fast-moving target with a slow-slewing telescope. - When the slew completes, the and properties should reflect the final (adjusted) destination. - The units of this property are arcseconds per SI (atomic) second. Please note that for historic reasons the units of the property are seconds of RA per sidereal second. - - - -This is not a required feature of this specification, however it is desirable. - -
    -
    - - - Predict side of pier for German equatorial mounts - - The destination right ascension (hours). - The destination declination (degrees, positive North). - The side of the pier on which the telescope would be on if a slew to the given equatorial coordinates is performed at the current instant of time. - If the method is not implemented - If an invalid RightAscension or Declination is specified. - - This is only available for telescope InterfaceVersions 2 and 3 - - - - - True if the telescope or driver applies atmospheric refraction to coordinates. - - Either read or write or both properties can throw PropertyNotImplementedException if not implemented - - If this property is True, the coordinates sent to, and retrieved from, the telescope are unrefracted. - This is only available for telescope InterfaceVersions 2 and 3 - - NOTES: - - If the driver does not know whether the attached telescope does its own refraction, and if the driver does not itself calculate - refraction, this property (if implemented) must raise an error when read. - Writing to this property is optional. Often, a telescope (or its driver) calculates refraction using standard atmospheric parameters. - If the client wishes to calculate a more accurate refraction, then this property could be set to False and these - client-refracted coordinates used. - If disabling the telescope or driver's refraction is not supported, the driver must raise an error when an attempt to set - this property to False is made. - Setting this property to True for a telescope or driver that does refraction, or to False for a telescope or driver that - does not do refraction, shall not raise an error. It shall have no effect. - - - - - - - Equatorial coordinate system used by this telescope (e.g. Topocentric or J2000). - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - Most amateur telescopes use topocentric coordinates. This coordinate system is simply the apparent position in the sky - (possibly uncorrected for atmospheric refraction) for "here and now", thus these are the coordinates that one would use with digital setting - circles and most amateur scopes. More sophisticated telescopes use one of the standard reference systems established by professional astronomers. - The most common is the Julian Epoch 2000 (J2000). These instruments apply corrections for precession,nutation, abberration, etc. to adjust the coordinates - from the standard system to the pointing direction for the time and location of "here and now". - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - Locates the telescope's "home" position (synchronous) - - If the method is not implemented and is False - - Returns only after the home position has been found. - At this point the property will be True. - Raises an error if there is a problem. - Raises an error if AtPark is true. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - The telescope's focal length, meters - - If the property is not implemented - - This property may be used by clients to calculate telescope field of view and plate scale when combined with detector pixel size and geometry. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - The current Declination movement rate offset for telescope guiding (degrees/sec) - - If the property is not implemented - If an invalid guide rate is set. - - This is the rate for both hardware/relay guiding and the PulseGuide() method. - This is only available for telescope InterfaceVersions 2 and 3 - - NOTES: - - To discover whether this feature is supported, test the property. - The supported range of this property is telescope specific, however, if this feature is supported, it can be expected that the range is sufficient to - allow correction of guiding errors caused by moderate misalignment and periodic error. - If a telescope does not support separate guiding rates in Right Ascension and Declination, then it is permissible for and GuideRateDeclination to be tied together. - In this case, changing one of the two properties will cause a change in the other. - Mounts must start up with a known or default declination guide rate, and this property must return that known/default guide rate until changed. - - - - - - - The current Right Ascension movement rate offset for telescope guiding (degrees/sec) - - If the property is not implemented - If an invalid guide rate is set. - - This is the rate for both hardware/relay guiding and the PulseGuide() method. - This is only available for telescope InterfaceVersions 2 and 3 - - NOTES: - - To discover whether this feature is supported, test the property. - The supported range of this property is telescope specific, however, if this feature is supported, it can be expected that the range is sufficient to allow correction of guiding errors caused by moderate - misalignment and periodic error. - If a telescope does not support separate guiding rates in Right Ascension and Declination, then it is permissible for GuideRateRightAscension and to be tied together. - In this case, changing one of the two properties will cause a change in the other. - Mounts must start up with a known or default right ascension guide rate, and this property must return that known/default guide rate until changed. - - - - - - - True if a command is in progress, False otherwise - - If is False - - Raises an error if the value of the property is false (the driver does not support the method). - - - - - Move the telescope in one axis at the given rate. - - The physical axis about which movement is desired - The rate of motion (deg/sec) about the specified axis - If the method is not implemented. - If an invalid axis or rate is given. - - This method supports control of the mount about its mechanical axes. - The telescope will start moving at the specified rate about the specified axis and continue indefinitely. - This method can be called for each axis separately, and have them all operate concurrently at separate rates of motion. - Set the rate for an axis to zero to restore the motion about that axis to the rate set by the property. - Tracking motion (if enabled, see note below) is suspended during this mode of operation. - - Raises an error if is true. - This must be implemented for the if the property returns True for the given axis. - This is only available for telescope InterfaceVersions 2 and 3 - - NOTES: - - The movement rate must be within the value(s) obtained from a object in the - the collection. This is a signed value with negative rates moving in the oposite direction to positive rates. - The values specified in are absolute, unsigned values and apply to both directions, determined by the sign used in this command. - The value of must be True if the telescope is moving about any of its axes as a result of this method being called. - This can be used to simulate a handbox by initiating motion with the MouseDown event and stopping the motion with the MouseUp event. - When the motion is stopped by setting the rate to zero the scope will be set to the previous or to no movement, depending on the state of the property. - It may be possible to implement satellite tracking by using the method to move the scope in the required manner to track a satellite. - - - - - - - Move the telescope to its park position, stop all motion (or restrict to a small safe range), and set to True. - - If the method is not implemented and is False - - Raises an error if there is a problem communicating with the telescope or if parking fails. Parking should put the telescope into a state where its pointing accuracy - will not be lost if it is power-cycled (without moving it).Some telescopes must be power-cycled before unparking. Others may be unparked by simply calling the method. - Calling this with = True does nothing (harmless) - - - - - Moves the scope in the given direction for the given interval or time at - the rate given by the corresponding guide rate property - - The direction in which the guide-rate motion is to be made - The duration of the guide-rate motion (milliseconds) - If the method is not implemented and is False - If an invalid direction or duration is given. - - This method returns immediately if the hardware is capable of back-to-back moves, - i.e. dual-axis moves. For hardware not having the dual-axis capability, - the method returns only after the move has completed. - - NOTES: - - Raises an error if is true. - The property must be be True during pulse-guiding. - The rate of motion for movements about the right ascension axis is - specified by the property. The rate of motion - for movements about the declination axis is specified by the - property. These two rates may be tied together - into a single rate, depending on the driver's implementation - and the capabilities of the telescope. - - - - - - - The right ascension (hours) of the telescope's current equatorial coordinates, - in the coordinate system given by the EquatorialSystem property - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - Reading the property will raise an error if the value is unavailable. -
    -
    - - - The right ascension tracking rate offset from sidereal (seconds per sidereal second, default = 0.0) - - If RightAscensionRate Write is not implemented. - If an invalid rate is set. - -

    RightAscensionRate Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    RightAscensionRate Write can throw a PropertyNotImplementedException.

    - This property, together with , provides support for "offset tracking". Offset tracking is used primarily for tracking objects that move relatively slowly - against the equatorial coordinate system. It also may be used by a software guiding system that controls rates instead of using the PulseGuide method. - - NOTES: - The property value represents an offset from the currently selected . - - If this property is zero, tracking will be at the selected . - If is False, this property must always return 0. - To discover whether this feature is supported, test the property. - The units of this property are seconds of right ascension per sidereal second. Please note that for historic reasons the units of the property are arcseconds per SI second. - To convert a given rate in (the more common) units of sidereal seconds per UTC (clock) second, multiply the value by 0.9972695677 - (the number of UTC seconds in a sidereal second) then set the property. Please note that these units were chosen for the Telescope V1 standard, - and in retrospect, this was an unfortunate choice. However, to maintain backwards compatibility, the units cannot be changed. - A simple multiplication is all that's needed, as noted. The supported range of this property is telescope specific, however, - if this feature is supported, it can be expected that the range is sufficient to allow correction of guiding errors - caused by moderate misalignment and periodic error. - If this property is non-zero when an equatorial slew is initiated, the telescope should continue to update the slew destination coordinates - at the given offset rate. This will allow precise slews to a fast-moving target with a slow-slewing telescope. When the slew completes, - the and properties should reflect the final (adjusted) destination. This is not a required - feature of this specification, however it is desirable. - Use the property to enable and disable sidereal tracking (if supported). - - -
    -
    - - - Sets the telescope's park position to be its current position. - - If the method is not implemented and is False - - - - Indicates the pointing state of the mount. - - If the property is not implemented. - If an invalid side of pier is set. - - For historical reasons, this property's name does not reflect its true meaning. The name will not be changed (so as to preserve - compatibility), but the meaning has since become clear. All conventional mounts have two pointing states for a given equatorial (sky) position. - Mechanical limitations often make it impossible for the mount to position the optics at given HA/Dec in one of the two pointing - states, but there are places where the same point can be reached sensibly in both pointing states (e.g. near the pole and - close to the meridian). In order to understand these pointing states, consider the following (thanks to Patrick Wallace for this info): - All conventional telescope mounts have two axes nominally at right angles. For an equatorial, the longitude axis is mechanical - hour angle and the latitude axis is mechanical declination. Sky coordinates and mechanical coordinates are two completely separate arenas. - This becomes rather more obvious if your mount is an altaz, but it's still true for an equatorial. Both mount axes can in principle - move over a range of 360 deg. This is distinct from sky HA/Dec, where Dec is limited to a 180 deg range (+90 to -90). Apart from - practical limitations, any point in the sky can be seen in two mechanical orientations. To get from one to the other the HA axis - is moved 180 deg and the Dec axis is moved through the pole a distance twice the sky codeclination (90 - sky declination). - Mechanical zero HA/Dec will be one of the two ways of pointing at the intersection of the celestial equator and the local meridian. - In order to support Dome slaving, where it is important to know which side of the pier the mount is actually on, ASCOM has adopted the - convention that the Normal pointing state will be the state where a German Equatorial mount is on the East side of the pier, looking West, with the - counterweights below the optical assembly and that will represent this pointing state. - Move your scope to this position and consider the two mechanical encoders zeroed. The two pointing states are, then: - - Normal ()Where the mechanical Dec is in the range -90 deg to +90 deg - Beyond the pole ()Where the mechanical Dec is in the range -180 deg to -90 deg or +90 deg to +180 deg. - - - "Side of pier" is a "consequence" of the former definition, not something fundamental. - Apart from mechanical interference, the telescope can move from one side of the pier to the other without the mechanical Dec - having changed: you could track Polaris forever with the telescope moving from west of pier to east of pier or vice versa every 12h. - Thus, "side of pier" is, in general, not a useful term (except perhaps in a loose, descriptive, explanatory sense). - All this applies to a fork mount just as much as to a GEM, and it would be wrong to make the "beyond pole" state illegal for the - former. Your mount may not be able to get there if your camera hits the fork, but it's possible on some mounts. Whether this is useful - depends on whether you're in Hawaii or Finland. - To first order, the relationship between sky and mechanical HA/Dec is as follows: - Normal state: - - HA_sky = HA_mech - Dec_sky = Dec_mech - - - Beyond the pole - - HA_sky = HA_mech + 12h, expressed in range ± 12h - Dec_sky = 180d - Dec_mech, expressed in range ± 90d - - - Astronomy software often needs to know which which pointing state the mount is in. Examples include setting guiding polarities - and calculating dome opening azimuth/altitude. The meaning of the SideOfPier property, then is: - - pierEastNormal pointing state - pierWestBeyond the pole pointing state - - - If the mount hardware reports neither the true pointing state (or equivalent) nor the mechanical declination axis position - (which varies from -180 to +180), a driver cannot calculate the pointing state, and *must not* implement SideOfPier. - If the mount hardware reports only the mechanical declination axis position (-180 to +180) then a driver can calculate SideOfPier as follows: - - pierEast = abs(mechanical dec) <= 90 deg - pierWest = abs(mechanical Dec) > 90 deg - - - It is allowed (though not required) that this property may be written to force the mount to flip. Doing so, however, may change - the right ascension of the telescope. During flipping, Telescope.Slewing must return True. - This property is only available in telescope InterfaceVersions 2 and 3. - Pointing State and Side of Pier - Help for Driver Developers - A further document, "Pointing State and Side of Pier", is installed in the Developer Documentation folder by the ASCOM Developer - Components installer. This further explains the pointing state concept and includes diagrams illustrating how it relates - to physical side of pier for German equatorial telescopes. It also includes details of the tests performed by Conform to determine whether - the driver correctly reports the pointing state as defined above. - - - - - The local apparent sidereal time from the telescope's internal clock (hours, sidereal) - - -

    Must be implemented, must not throw a PropertyNotImplementedException.

    - It is required for a driver to calculate this from the system clock if the telescope - has no accessible source of sidereal time. Local Apparent Sidereal Time is the sidereal - time used for pointing telescopes, and thus must be calculated from the Greenwich Mean - Sidereal time, longitude, nutation in longitude and true ecliptic obliquity. -
    -
    - - - The elevation above mean sea level (meters) of the site at which the telescope is located - - If the property is not implemented. - If an invalid elevation is set. - If the application must set the elevation before reading it, but has not. - - Setting this property will raise an error if the given value is outside the range -300 through +10000 metres. - Reading the property will raise an error if the value has never been set or is otherwise unavailable. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - The geodetic(map) latitude (degrees, positive North, WGS84) of the site at which the telescope is located. - - If the property is not implemented. - If an invalid latitude is set. - If the application must set the latitude before reading it, but has not. - - Setting this property will raise an error if the given value is outside the range -90 to +90 degrees. - Reading the property will raise an error if the value has never been set or is otherwise unavailable. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - The longitude (degrees, positive East, WGS84) of the site at which the telescope is located. - - If the property is not implemented. - If an invalid longitude is set. - If the application must set the longitude before reading it, but has not. - - Setting this property will raise an error if the given value is outside the range -180 to +180 degrees. - Reading the property will raise an error if the value has never been set or is otherwise unavailable. - Note that West is negative! - This is only available for telescope InterfaceVersions 2 and 3 - - - - - True if telescope is currently moving in response to one of the - Slew methods or the method, False at all other times. - - If the property is not implemented. - - Reading the property will raise an error if the value is unavailable. If the telescope is not capable of asynchronous slewing, this property will always be False. - The definition of "slewing" excludes motion caused by sidereal tracking, PulseGuide, , and . - It reflects only motion caused by one of the Slew commands, flipping caused by changing the property, or . - - - - - Specifies a post-slew settling time (sec.). - - If the property is not implemented. - If an invalid settle time is set. - - Adds additional time to slew operations. Slewing methods will not return, - and the property will not become False, until the slew completes and the SlewSettleTime has elapsed. - This feature (if supported) may be used with mounts that require extra settling time after a slew. - - - - - Move the telescope to the given local horizontal coordinates, return when slew is complete - - If the method is not implemented and is False - If an invalid azimuth or elevation is given. - - This Method must be implemented if returns True. Raises an error if the slew fails. The slew may fail if the target coordinates are beyond limits imposed within the driver component. - Such limits include mechanical constraints imposed by the mount or attached instruments, building or dome enclosure restrictions, etc. - The and properties are not changed by this method. - Raises an error if is True, or if is True. This is only available for telescope InterfaceVersions 2 and 3 - - Target azimuth (degrees, North-referenced, positive East/clockwise). - Target altitude (degrees, positive up) - - - - This Method must be implemented if returns True. - - Azimuth to which to move - Altitude to which to move to - If the method is not implemented and is False - If an invalid azimuth or elevation is given. - - This method should only be implemented if the properties , , - , and can be read while the scope is slewing. Raises an error if starting the slew fails. Returns immediately after starting the slew. - The client may monitor the progress of the slew by reading the , , and properties during the slew. When the slew completes, Slewing becomes False. - The slew may fail if the target coordinates are beyond limits imposed within the driver component. Such limits include mechanical constraints imposed by the mount or attached instruments, building or dome enclosure restrictions, etc. - The and properties are not changed by this method. - Raises an error if is True, or if is True. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - Move the telescope to the given equatorial coordinates, return when slew is complete - - If an invalid right ascension or declination is given. - The destination right ascension (hours). Copied to . - The destination declination (degrees, positive North). Copied to . - If the method is not implemented and is False - - This Method must be implemented if returns True. Raises an error if the slew fails. - The slew may fail if the target coordinates are beyond limits imposed within the driver component. - Such limits include mechanical constraints imposed by the mount or attached instruments, - building or dome enclosure restrictions, etc. The target coordinates are copied to - and whether or not the slew succeeds. - Raises an error if is True, or if is False. - - - - - Move the telescope to the given equatorial coordinates, return immediately after starting the slew. - - The destination right ascension (hours). Copied to . - The destination declination (degrees, positive North). Copied to . - If the method is not implemented and is False - If an invalid right ascension or declination is given. - - This method must be implemented if returns True. Raises an error if starting the slew failed. - Returns immediately after starting the slew. The client may monitor the progress of the slew by reading - the , , and properties during the slew. When the slew completes, - becomes False. The slew may fail to start if the target coordinates are beyond limits - imposed within the driver component. Such limits include mechanical constraints imposed - by the mount or attached instruments, building or dome enclosure restrictions, etc. - The target coordinates are copied to and - whether or not the slew succeeds. - Raises an error if is True, or if is False. - - - - - Move the telescope to the and coordinates, return when slew complete. - - If the method is not implemented and is False - - This Method must be implemented if returns True. Raises an error if the slew fails. - The slew may fail if the target coordinates are beyond limits imposed within the driver component. - Such limits include mechanical constraints imposed by the mount or attached - instruments, building or dome enclosure restrictions, etc. - Raises an error if is True, or if is False. - - - - - Move the telescope to the and coordinates, - returns immediately after starting the slew. - - If the method is not implemented and is False - - This Method must be implemented if returns True. - Raises an error if starting the slew failed. Returns immediately after starting the slew. The client may monitor the progress of the slew by reading the RightAscension, Declination, - and Slewing properties during the slew. When the slew completes, becomes False. The slew may fail to start if the target coordinates are beyond limits imposed within - the driver component. Such limits include mechanical constraints imposed by the mount or attached instruments, building or dome enclosure restrictions, etc. - Raises an error if is True, or if is False. - - - - - Matches the scope's local horizontal coordinates to the given local horizontal coordinates. - - Target azimuth (degrees, North-referenced, positive East/clockwise) - Target altitude (degrees, positive up) - If the method is not implemented and is False - If an invalid azimuth or altitude is given. - - This must be implemented if the property is True. Raises an error if matching fails. - Raises an error if is True, or if is True. - This is only available for telescope InterfaceVersions 2 and 3 - - - - - Matches the scope's equatorial coordinates to the given equatorial coordinates. - - The corrected right ascension (hours). Copied to the property. - The corrected declination (degrees, positive North). Copied to the property. - If the method is not implemented and is False - If an invalid right ascension or declination is given. - - This must be implemented if the property is True. Raises an error if matching fails. - Raises an error if AtPark is True, or if is False. - The way that Sync is implemented is mount dependent and it should only be relied on to improve pointing for positions close to - the position at which the sync is done. - - - - - Matches the scope's equatorial coordinates to the given equatorial coordinates. - - If the method is not implemented and is False - - This must be implemented if the property is True. Raises an error if matching fails. - Raises an error if AtPark is True, or if is False. - The way that Sync is implemented is mount dependent and it should only be relied on to improve pointing for positions close to - the position at which the sync is done. - - - - - The declination (degrees, positive North) for the target of an equatorial slew or sync operation - - If the property is not implemented. - If an invalid declination is set. - If the property is read before being set for the first time. - - Setting this property will raise an error if the given value is outside the range -90 to +90 degrees. Reading the property will raise an error if the value has never been set or is otherwise unavailable. - - - - - The right ascension (hours) for the target of an equatorial slew or sync operation - - If the property is not implemented. - If an invalid right ascension is set. - If the property is read before being set for the first time. - - Setting this property will raise an error if the given value is outside the range 0 to 24 hours. Reading the property will raise an error if the value has never been set or is otherwise unavailable. - - - - - The state of the telescope's sidereal tracking drive. - - If Tracking Write is not implemented. - -

    Tracking Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    Tracking Write can throw a PropertyNotImplementedException.

    - Changing the value of this property will turn the sidereal drive on and off. - However, some telescopes may not support changing the value of this property - and thus may not support turning tracking on and off. - See the property. -
    -
    - - - The current tracking rate of the telescope's sidereal drive - - If TrackingRate Write is not implemented. - If an invalid drive rate is set. - -

    TrackingRate Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    TrackingRate Write can throw a PropertyNotImplementedException.

    - Supported rates (one of the values) are contained within the collection. - Values assigned to TrackingRate must be one of these supported rates. If an unsupported value is assigned to this property, it will raise an error. - The currently selected tracking rate can be further adjusted via the and properties. These rate offsets are applied to the currently - selected tracking rate. Mounts must start up with a known or default tracking rate, and this property must return that known/default tracking rate until changed. - If the mount's current tracking rate cannot be determined (for example, it is a write-only property of the mount's protocol), - it is permitted for the driver to force and report a default rate on connect. In this case, the preferred default is Sidereal rate. - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - Returns a collection of supported values that describe the permissible - values of the property for this telescope type. - - -

    Must be implemented and must not throw a PropertyNotImplementedException.

    - At a minimum, this must contain an item for . - This is only available for telescope InterfaceVersions 2 and 3 -
    -
    - - - Takes telescope out of the Parked state. - - If the method is not implemented and is False - - The state of after unparking is undetermined. Valid only after . Applications must check and change Tracking as needed after unparking. - Raises an error if unparking fails. Calling this with = False does nothing (harmless) - - - - - The UTC date/time of the telescope's internal clock - - If UTCDate Write is not implemented. - If an invalid is set. - When UTCDate is read and the mount cannot provide this property itslef and a value has not yet be established by writing to the property. - -

    UTCDate Read must be implemented and must not throw a PropertyNotImplementedException.

    -

    UTCDate Write can throw a PropertyNotImplementedException.

    - The driver must calculate this from the system clock if the telescope has no accessible source of UTC time. In this case, the property must not be writeable (this would change the system clock!) and will instead raise an error. - However, it is permitted to change the telescope's internal UTC clock if it is being used for this property. This allows clients to adjust the telescope's UTC clock as needed for accuracy. Reading the property - will raise an error if the value has never been set or is otherwise unavailable. -
    -
    - - - Returns a collection of supported DriveRate values that describe the permissible values of the TrackingRate property for this telescope type. - - - - - Returns a specified item from the collection - - Number of the item to return - A collection of supported DriveRate values that describe the permissible values of the TrackingRate property for this telescope type. - Returns a collection of supported DriveRate values - This is only used by telescope interface versions 2 and 3 - - - - Number of DriveRates supported by the Telescope - - Number of DriveRates supported by the Telescope - Integer count - - - - - Returns an enumerator for the collection - - An enumerator - - - - - Disposes of the TrackingRates object - - - - - - ASCOM Video Camera supported frame rates. - - - - - This is a video camera that supports variable frame rates. - - - - - 25 frames per second (fps) corresponding to a PAL (colour) or CCIR (black and white) video standard. - - - - - 29.97 frames per second (fps) corresponding to an NTSC (colour) or EIA (black and white) video standard. - - - - - ASCOM Video Camera status values. - - - - - Camera status running. The video is receiving signal and video frames are available for viewing or recording. - - - - - Camera status recording. The video camera is recording video to the file system. Video frames are available for viewing. - - - - - Camera status error. The video camera is in a state of an error and cannot continue its operation. Usually a reset will be required to resolve the error condition. - - - - - Defines the IVideoFrame Interface. - - - - - Returns a safearray of int32 containing the pixel values from the video frame. The array could be one of: ImageArray[Pixels], ImageArray[Height, Width], ImageArray[NumPlane, Pixels] - or ImageArray[NumPlane, Height, Width]. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - The application must inspect the Safearray parameters to determine the dimensions and also the to determine if the image is Color or not. - The following table should be used to determine the format of the data: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Dimensions - SensorType - Array Format
    1; int[]Monochrome, RGGB, CMYG, CMYG2, LRGBA row major ImageArray[Pixels] of * elements. The pixels in the array start from the top left part of the image and are listed by horizontal lines/rows. The second pixel in the array is the second pixel from the first horizontal row - and the second last pixel in the array is the second last pixels from the last horizontal row.
    1; int[]Color

    Invalid configuration.

    2; int[,]Monochrome, RGGB, CMYG, CMYG2, LRGBImageArray[Height, Width] of x elements.
    2; int[,]ColorImageArray[NumPlane, Pixels] of NumPlanes x * elements. The order of the three colour planes is - first is R, the second is G and third is B. The pixels in second dimension of the array start from the top left part of the image and are listed by horizontal lines/rows. The second pixel is the second pixel from the first horizontal row - and the second last pixel is the second last pixels from the last horizontal row.
    3; int[,,]Monochrome, RGGB, CMYG, CMYG2, LRGB

    Invalid configuration.

    3; int[,,]ColorImageArray[NumPlane, Height, Width] of NumPlanes x x elements. The order of the three colour planes is - first is R, the second is G and third is B.
    -
    - In Color SensorType mode, if the application cannot handle multispectral images, it should use just the first plane. -
    - The image array. -
    - - - Returns a preview bitmap for the last video frame as an array of byte. - - The following code can be used to create a Bitmap from the returned byte array - - using (var memStr = new MemoryStream(frame.PreviewBitmap)) - { - bmp = (Bitmap)Image.FromStream(memStr); - } - - - Using memStr = New MemoryStream(frame.PreviewBitmap) - bmp = DirectCast(Image.FromStream(memStr), Bitmap) - End Using - - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    The application can use this bitmap to show a preview image of the last video frame when required. This is a convenience property for - those applications that don't require to process the but usually only adjust the video camera settings and then record a video file. - When a 24bit RGB image can be returned by the driver this should be the preferred format. -
    - The preview bitmap image. -
    - - - Returns the frame number. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - The frame number of the first exposed frame may not be zero and is dependent on the device and/or the driver. The frame number increases with each acquired frame not with each requested frame by the client. -
    - The frame number of the current video frame. -
    - - - Returns the actual exposure duration in seconds (i.e. shutter open time). - - - This may differ from the exposure time corresponding to the requested frame exposure due to shutter latency, camera timing precision, etc. - - The duration of the frame exposure. - Must throw an exception if not implemented. - - - - Returns the actual exposure start time in the FITS-standard CCYY-MM-DDThh:mm:ss[.sss...] format, if supported. - - The frame exposure start time. - Must throw an exception if not implemented. - - - - Returns additional information associated with the video frame as a list of named variables. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - The returned object contains entries for each value. For each entry, the Key property is the value's name, and the Value property is the string value itself. - This property must return an empty list if no video frame metadata is provided. - The Keys is a single word, or multiple words joined by underscore characters, that sensibly describes the variable. It is recommended that Keys - should be a maximum of 16 characters for legibility and all upper case. - The KeyValuePair objects are instances of the KeyValuePair class -
    - An ArrayList of KeyValuePair objects. -
    - - - Defines the IVideo Interface. - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and model number. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful. -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 1 for this interface version. - - Must throw an exception if the call was not successful. -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - The short name of the driver, for display purposes. - - Must throw an exception if the call was not successful. -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are supported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful. - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    May throw a MethodNotImplementedException if the device does not support any actions.

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - "General" will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    This method must return an empty arraylist if no actions are supported. - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - The name of the video capture device when such a device is used. - - Must throw an exception if not implemented. - For analogue video this is usually the video capture card or dongle attached to the computer. - - - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful. -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - The maximum supported exposure (integration time) in seconds. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - This value is for information purposes only. The exposure cannot be set directly in seconds, use property to change the exposure. -
    -
    - - - The minimum supported exposure (integration time) in seconds. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - This value is for information purposes only. The exposure cannot be set directly in seconds, use property to change the exposure. -
    -
    - - - The frame rate at which the camera is running. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - Analogue cameras run in one of the two fixed frame rates - 25fps for PAL video and 29.97fps for NTSC video. - Digital cameras usually can run at a variable frame rate. This value is for information purposes only and cannot be set. The FrameRate has the same value during the entire operation of the device. - Changing the property may change the actual variable frame rate but cannot changethe return value of this property. -
    -
    - - - Returns the list of integration rates supported by the video camera. - - - Digital and integrating analogue video cameras allow the effective exposure of a frame to be changed. If the camera supports setting the exposure directly i.e. 2.153 sec then the driver must only - return a range of useful supported exposures. For many video cameras the supported exposures (integration rates) increase by a factor of 2 from a base exposure e.g. 1, 2, 4, 8, 16 sec or 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24 sec. - If the camers supports only one exposure that cannot be changed (such as all non integrating PAL or NTSC video cameras) then this property must throw . - - The list of supported integration rates in seconds. - Must throw exception if data unavailable. - Must throw exception if camera supports only one integration rate (exposure) that cannot be changed. - - - - Index into the array for the selected camera integration rate. - - Integer index for the current camera integration rate in the string array. - Index into the SupportedIntegrationRates array for the selected camera integration rate. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. - Must throw an exception if the camera supports only one integration rate (exposure) that cannot be changed. - - can be used to adjust the integration rate (exposure) of the camera, if supported. A 0-based array of strings - , - which correspond to different discrete integration rate settings supported by the camera will be returned. must be set to an integer in this range. - The driver must default to a valid value when integration rate is supported by the camera. - - - - - Returns an with its property populated. - - The current video frame. - Must throw exception if data unavailable. - If called before any video frame has been taken. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - Sensor name. - - The name of sensor used within the camera. - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw exception if not implemented. - Returns the name (datasheet part number) of the sensor, e.g. ICX285AL. The format is to be exactly as shown on - manufacturer data sheet, subject to the following rules. All letter shall be uppercase. Spaces shall not be included. - Any extra suffixes that define region codes, package types, temperature range, coatings, grading, color/monochrome, - etc. shall not be included. For color sensors, if a suffix differentiates different Bayer matrix encodings, it shall be - included. - Examples: - - ICX285AL-F shall be reported as ICX285 - KAF-8300-AXC-CD-AA shall be reported as KAF-8300 - - Note: - The most common usage of this property is to select approximate color balance parameters to be applied to - the Bayer matrix of one-shot color sensors. Application authors should assume that an appropriate IR cutoff filter is - in place for color sensors. - It is recommended that this function be called only after a connection is established with - the camera hardware, to ensure that the driver is aware of the capabilities of the specific camera model. - - - - -Type of colour information returned by the the camera sensor. - - - The enum value of the camera sensor - Must throw an exception if the information is not available. (Some drivers may require an -active connection in order to retrieve necessary information from the camera.) - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - returns a value indicating whether the sensor is monochrome, or what Bayer matrix it encodes. -The following values are defined: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Value - Enumeration - Meaning
    -0 -Monochrome -Camera produces monochrome array with no Bayer encoding
    -1 -Colour -Camera produces color image directly, requiring not Bayer decoding. The monochome pixels for the R, G and B channels are returned in this order in the .
    -2 -RGGB -Camera produces RGGB encoded Bayer array images
    -3 -CMYG -Camera produces CMYG encoded Bayer array images
    -4 -CMYG2 -Camera produces CMYG2 encoded Bayer array images
    -5 -LRGB -Camera produces Kodak TRUESENSE Bayer LRGB array images
    -
    - Please note that additional values may be defined in future updates of the standard, as new Bayer matrices may be created -by sensor manufacturers in the future. If this occurs, then a new enumeration value shall be defined. The pre-existing enumeration -values shall not change. -In the following definitions, R = red, G = green, B = blue, C = cyan, M = magenta, Y = yellow. The Bayer matrix is -defined with X increasing from left to right, and Y increasing from top to bottom. The pattern repeats every N x M pixels for the -entire pixel array, where N is the height of the Bayer matrix, and M is the width. -RGGB indicates the following matrix: - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 -R -G
    - Y = 1 -G -B
    -
    - CMYG indicates the following matrix: - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 -Y -C
    - Y = 1 -G -M
    -
    - CMYG2 indicates the following matrix: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1
    - Y = 0 -C -Y
    - Y = 1 -M -G
    - Y = 2 -C -Y
    - Y = 3 -G -M
    -
    - LRGB indicates the following matrix (Kodak TRUESENSE): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - X = 0 - X = 1 - X = 2 - X = 3
    - Y = 0 -L -R -L -G
    - Y = 1 -R -L -G -L
    - Y = 2 -L -G -L -B
    - Y = 3 -G -L -B -L
    -
    - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure that -the driver is aware of the capabilities of the specific camera model. -
    -
    - - - Returns the width of the video frame in pixels. - - The video frame width. - Must throw exception if the value is not known. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - For analogue video cameras working via a frame grabber the dimensions of the video frames may be different than the dimension of the CCD chip -
    -
    - - - Returns the height of the video frame in pixels. - - The video frame height. - Must throw exception if the value is not known. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - For analogue video cameras working via a frame grabber the dimensions of the video frames may be different than the dimension of the CCD chip -
    -
    - - - Returns the width of the CCD chip pixels in microns. - - The pixel size X if known. - Must throw exception if not implemented. - - - - Returns the height of the CCD chip pixels in microns. - - The pixel size Y if known. - Must throw exception if not implemented. - - - - Reports the bit depth the camera can produce. - - The bit depth per pixel. Typical analogue videos are 8-bit while some digital cameras can provide 12, 14 or 16-bit images. - Must throw exception if data unavailable. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - Returns the video codec used to record the video file. - - Must throw exception if not implemented. - For AVI files this is usually the FourCC identifier of the codec- e.g. XVID, DVSD, YUY2, HFYU etc. - If the recorded video file doesn't use codecs an empty string must be returned. - - - - - Returns the file format of the recorded video file, e.g. AVI, MPEG, ADV etc. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - The size of the video frame buffer. - - The size of the video frame buffer. -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    When retrieving video frames using the property - the driver may use a buffer to queue the frames waiting to be read by the client. This property returns the size of the buffer in frames or - if no buffering is supported then the value of less than 2 should be returned. The size of the buffer can be controlled by the end user from the driver setup dialog. -
    -
    - - - Starts recording a new video file. - - The file name requested by the client. Some systems may not allow the file name to be controlled directly and they should ignore this parameter. - The actual file name of the file that is being recorded. - Must throw exception if not implemented. - Must throw exception if not connected. - Must throw exception if the current camera state doesn't allow to begin recording a file. - Must throw exception if there is any other problem as result of which the recording cannot begin. - - - - Stops the recording of a video file. - - Must throw exception if not implemented. - Must throw exception if not connected. - Must throw exception if the current camera state doesn't allow to stop recording the file or no file is currently being recorded. - Must throw exception if there is any other problem as result of which the recording cannot stop. - - - - Returns the current camera operational state. - - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    - Returns one of the following status information: - - Value State Meaning - 0 CameraRunning The camera is running and video frames are available for viewing and recording - 1 CameraRecording The camera is running and recording a video - 2 CameraError Camera error condition serious enough to prevent further operations (connection fail, etc.). - - CameraIdle and CameraBusy are optional states. Free running cameras cannot be stopped and don't have a CameraIdle state. When those cameras are powered they immediately enter CameraRunning state. - Some digital cameras or vdeo systems may suport operations that take longer to complete. Whlie those longer operations are running the camera will remain in the state it was before the operation started. - The video camera state diagram is shown below: - - -
    - The state of the camera. - Must return an exception if the camera status is unavailable. -
    - - - Maximum value of . - - Short integer representing the maximum gain value supported by the camera. - The maximum gain value that this camera supports - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if GainMax is not supported. - When specifying the gain setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - - - - - Minimum value of . - - The minimum gain value that this camera supports - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if GainMin is not supported. - When specifying the gain setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - - - - - Index into the array for the selected camera gain. - - Short integer index for the current camera gain in the string array. - Index into the Gains array for the selected camera gain - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. - Must throw an exception if gain is not supported. - - can be used to adjust the gain setting of the camera, if supported. There are two typical usage scenarios: -
      -
    • Discrete gain video cameras will return a 0-based array of strings - , which correspond to different discrete gain settings supported by the camera. must be set to an integer in this range. and must thrown an exception if - this mode is used.
    • -
    • Adjustable gain video cameras - and return integers, which specify the valid range for .
    • -
    - The driver must default to a valid value. -
    -
    - - - Gains supported by the camera. - - An ArrayList of gain names or values - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if Gains is not supported - provides a 0-based array of available gain settings. - Typically the application software will display the available gain settings in a drop list. The application will then supply - the selected index to the driver via the property. - The setting may alternatively be specified using integer values; if this mode is used then is invalid - and must throw an exception. Please see and for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, - to ensure that the driver is aware of the capabilities of the specific camera model. - - - - - Maximum value of . - - Short integer representing the maximum gamma value supported by the camera. - The maximum gain value that this camera supports - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if GammaMax is not supported - When specifying the gamma setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - - - - - Minimum value of . - - The minimum gamma value that this camera supports - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if GammaMin is not supported. - When specifying the gamma setting with an integer value, is used in conjunction with to - specify the range of valid settings. - shall be greater than . If either is available, then both must be available. - Please see for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, to ensure - that the driver is aware of the capabilities of the specific camera model. - - - - - Index into the array for the selected camera gamma. - - Short integer index for the current camera gamma in the string array. - Index into the Gammas array for the selected camera gamma - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if not valid. - Must throw an exception if Gamma is not supported. - - can be used to adjust the gamma setting of the camera, if supported. There are two typical usage scenarios: -
      -
    • Discrete gamma video cameras will return a 0-based array of strings - , which correspond to different discrete gamma settings supported by the camera. must be set to an integer in this range. and must thrown an exception if - this mode is used.
    • -
    • Adjustable gain video cameras - and return integers, which specify the valid range for .
    • -
    - The driver must default to a valid value. -
    -
    - - - Gammas supported by the camera. - - An ArrayList of gamma names or values - Must throw an exception if the information is not available. (Some drivers may require an - active connection in order to retrieve necessary information from the camera.) - Must throw an exception if Gammas is not supported - provides a 0-based array of available gamma settings. This list can contain the widely used values of OFF, LO and HI that correspond to gammas of 1.00, 0.45 and 0.35 as well as other extended values. - Typically the application software will display the available gamma settings in a drop list. The application will then supply - the selected index to the driver via the property. - The setting may alternatively be specified using integer values; if this mode is used then is invalid - and must throw an exception. Please see and for more information. - It is recommended that this function be called only after a connection is established with the camera hardware, - to ensure that the driver is aware of the capabilities of the specific camera model. - - - - - Returns True if the driver supports custom device properties configuration via the method. - -

    Must be implemented, must not throw an ASCOM.PropertyNotImplementedException.

    -
    -
    - - - Displays a device properties configuration dialog that allows the configuration of specialized settings. - - Must throw an exception if the camera is not connected. - Must throw an exception if not implemented. - - The dialog could also provide buttons for cameras that can be controlled via 'on screen display' menues and a set of navigation buttons such as Up, Down, Left, Right and Enter. - This dialog is not intended to be used in unattended mode but can give greater control over video cameras that provide special features. The dialog may also allow - changing standard interface settings such as Gamma and Gain. If a client software - displays any interface settings then it should take care to keep in sync the values changed by this method and those changed directly via the interface. - To support automated and unattended control over the specialized device settings or functions available on this dialog the driver should also allow their control via . - This dialog is meant to be used by the applications to allow the user to adjust specialized device settings when those applications don't specifically use the specialized settings in their functionality. - Examples for specialized settings that could be supported are white balance and sharpness. - - - - - Defines the ISafetyMonitor Interface - - - - - Set True to connect to the device hardware. Set False to disconnect from the device hardware. - You can also read the property to check whether it is connected. This reports the current hardware state. - - true if connected to the hardware; otherwise, false. - Must throw an exception if the call was not successful - -

    Must be implemented

    Do not use a NotConnectedException here, that exception is for use in other methods that require a connection in order to succeed. - The Connected property sets and reports the state of connection to the device hardware. - For a hub this means that Connected will be true when the first driver connects and will only be set to false - when all drivers have disconnected. A second driver may find that Connected is already true and - setting Connected to false does not report Connected as false. This is not an error because the physical state is that the - hardware connection is still true. - Multiple calls setting Connected to true or false will not cause an error. -
    -
    - - - Returns a description of the device, such as manufacturer and modelnumber. Any ASCII characters may be used. - - The description. - If the device is not connected and this information is only available when connected. - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Descriptive and version information about this ASCOM driver. - - Must throw an exception if the call was not successful - -

    Must be implemented

    This string may contain line endings and may be hundreds to thousands of characters long. - It is intended to display detailed information on the ASCOM driver, including version and copyright data. - See the property for information on the device itself. - To get the driver version in a parseable string, use the property. -
    -
    - - - A string containing only the major and minor version of the driver. - - Must throw an exception if the call was not successful -

    Must be implemented

    This must be in the form "n.n". - It should not to be confused with the property, which is the version of this specification supported by the - driver. -
    -
    - - - The interface version number that this device supports. Should return 2 for this interface version. - - Must throw an exception if the call was not successful -

    Must be implemented

    Clients can detect legacy V1 drivers by trying to read ths property. - If the driver raises an error, it is a V1 driver. V1 did not specify this property. A driver may also return a value of 1. - In other words, a raised error or a return value of 1 indicates that the driver is a V1 driver. -
    -
    - - - The short name of the driver, for display purposes - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Launches a configuration dialog box for the driver. The call will not return - until the user clicks OK or cancel manually. - - Must throw an exception if the call was not successful -

    Must be implemented

    -
    - - - Invokes the specified device-specific action. - - - A well known name agreed by interested parties that represents the action to be carried out. - - List of required parameters or an Empty String if none are required. - - A string response. The meaning of returned strings is set by the driver author. - Throws this exception if no actions are suported. - It is intended that the SupportedActions method will inform clients - of driver capabilities, but the driver must still throw an ASCOM.ActionNotImplemented exception if it is asked to - perform an action that it does not support. - If the driver is not connected. - Must throw an exception if the call was not successful - Suppose filter wheels start to appear with automatic wheel changers; new actions could - be “FilterWheel:QueryWheels†and “FilterWheel:SelectWheelâ€. The former returning a - formatted list of wheel names and the second taking a wheel name and making the change, returning appropriate - values to indicate success or failure. - -

    Can throw a not implemented exception

    - This method is intended for use in all current and future device types and to avoid name clashes, management of action names - is important from day 1. A two-part naming convention will be adopted - DeviceType:UniqueActionName where: - - DeviceType is the same value as would be used by e.g. Telescope, Camera, Switch etc. - UniqueActionName is a single word, or multiple words joined by underscore characters, that sensibly describes the action to be performed. - - - It is recommended that UniqueActionNames should be a maximum of 16 characters for legibility. - Should the same function and UniqueActionName be supported by more than one type of device, the reserved DeviceType of - “General†will be used. Action names will be case insensitive, so FilterWheel:SelectWheel, filterwheel:selectwheel - and FILTERWHEEL:SELECTWHEEL will all refer to the same action. - The names of all supported actions must be returned in the property. -
    -
    - - - Returns the list of action names supported by this driver. - - An ArrayList of strings (SafeArray collection) containing the names of supported actions. - Must throw an exception if the call was not successful -

    Must be implemented

    This method must return an empty arraylist if no actions are supported. Please do not throw a - . - This is an aid to client authors and testers who would otherwise have to repeatedly poll the driver to determine its capabilities. - Returned action names may be in mixed case to enhance presentation but will be recognised case insensitively in - the Action method. -An array list collection has been selected as the vehicle for action names in order to make it easier for clients to - determine whether a particular action is supported. This is easily done through the Contains method. Since the - collection is also ennumerable it is easy to use constructs such as For Each ... to operate on members without having to be concerned - about hom many members are in the collection. - Collections have been used in the Telescope specification for a number of years and are known to be compatible with COM. Within .NET - the ArrayList is the correct implementation to use as the .NET Generic methods are not compatible with COM. -
    -
    - - - Transmits an arbitrary string to the device and does not wait for a response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a boolean response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the interpreted boolean response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Transmits an arbitrary string to the device and waits for a string response. - Optionally, protocol framing characters may be added to the string before transmission. - - The literal command string to be transmitted. - - if set to true the string is transmitted 'as-is'. - If set to false then protocol framing characters may be added prior to transmission. - - - Returns the string response received from the device. - - If the method is not implemented - If the driver is not connected. - Must throw an exception if the call was not successful -

    Can throw a not implemented exception

    -
    - - - Dispose the late-bound interface, if needed. Will release it via COM - if it is a COM object, else if native .NET will just dereference it - for GC. - - - - - Indicates whether the monitored state is safe for use. - - True if the state is safe, False if it is unsafe. - -

    Must be implemented and must not throw a PropertyNotImplementedException.

    -
    -
    -
    -
    diff --git a/MeadeAutostar497/bin/Debug/ASCOM.Exceptions.xml b/MeadeAutostar497/bin/Debug/ASCOM.Exceptions.xml deleted file mode 100644 index d5c6d57..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.Exceptions.xml +++ /dev/null @@ -1,693 +0,0 @@ - - - - ASCOM.Exceptions - - - - - Exception thrown by a driver when it receives an unknown command through the Action method. - - - If you need to throw this error as a COM exception use the error number: 0x8004040C. - - - - - Create a new exception object and identify the specified driver method as the source. - - The name of the action that caused the exception. - - - - Create a new exception object and identify the specified driver method as the source, - and include an inner exception object containing a caught exception. - - The name of the driver method that caused the exception - The caught exception - - - - For Code Analysis, please don't use - - - - - Initializes a new instance of the class. - - The that holds the serialized object data about the exception being thrown. - The that contains contextual information about the source or destination. - - The parameter is null. - - - The class name is null or is zero (0). - - - - - The method that is not implemented - - - - - Exception thrown by DriverAccess to return a driver COM error to the client. This exception appears as a COMException - to the client having the original exception's description and error number as well as the original exception as - the inner exception. - - - - - Creates a new DriverAccessCOException - - The error message to display - The COM error code to attach to this exception - Any inner exception that is to be attached to the exception, or null if there is no inner exception - - - - This exception should be raised by the driver to reject a command from the client. - - - The exception is intended to be used for "logical" errors e.g. trying to use a command when the current configuration of the device does - not allow it rather than for device errors such as a communications error. - Its the error to use when the client attempts something, which at another time would be sensible, - but which is not sensible right now. If you expect the condition causing the issue to be short - lived, you may choose to stall the request until the condition is cleared rather than throwing this exception. - Clearly, that is a judgement that you can only make given a specific scenario. - If you need to throw this error as a COM exception use the error number: 0x8004040B. - - - - - Default public constructor for NotConnectedException takes no parameters. - - - - - Initializes a new instance of the class - from another exception. - - The inner exception. - - - - Initializes a new instance of the class - with a non-default error message. - - A descriptive human-readable message. - - - - Initializes a new instance of the class - based on another exception. - - Descriptive text documenting the cause or source of the error. - The inner exception the led to the throwing of this exception. - - - - Added to keep Code Analysis happy - - - - - - - All methods defined by the relevant ASCOM standard interface must exist in each driver. However, those methods do not all have to be implemented. The minimum requirement - for each defined method is to throw the ASCOM.MethodNotImplementedException. Note that no default constructor is supplied. Throwing this requires the the method name. - - - If you need to throw this error as a COM exception use the error number: 0x80040400. - - - - - Create a new exception object and identify the specified driver method as the source. - - The name of the driver method that caused the exception. - - - - Create a new exception object and identify the specified driver method as the source, - and include an inner exception object containing a caught exception. - - The name of the driver method that caused the exception - The caught exception - - - - For Code Analysis, please don't use - - - - - Initializes a new instance of the class. - - The that holds the serialized object data about the exception being thrown. - The that contains contextual information about the source or destination. - - The parameter is null. - - - The class name is null or is zero (0). - - - - - The method that is not implemented - - - - - This is the generic driver exception. Drivers are permitted to directly throw this - exception as well as any derived exceptions. Note that the Message property is - a member of , the base class of DriverException. The - property of is simply renamed to Number. - This exception should only be thrown if there is no other more appropriate exception already defined, e.g. PropertyNotImplemented, - InvalidOperationException, InvalidValueException, NotConnectedException etc. These specific exceptions should be thrown where appropriate - rather than using the more generic DriverException. Conform will not accept DriverExceptions where more appropriate exceptions - are already defined. - As good programming practice, the Message property should not be empty, so that users understand why the exception was thrown. - - - - - Create a new ASCOM exception using the specified text message and error code. - - Descriptive text describing the cause of the exception - Error code for the exception (80040400 - 80040FFF). - - - - Create a new ASCOM exception based on another exception plus additional descriptive text and error code. This member is - required for a well-behaved exception class. For example, if a driver receives an exception - (perhaps a COMException) from some other component yet it wants to report some meaningful - error that resulted from the other error, it can package the original error in the - InnerException member of the exception it generates. - - Descriptive text describing the cause of the exception - Error code for the exception (80040400 - 80040FFF). - The inner exception that led to throwing this exception - - - - Initializes a new instance of the class that will return the 'unspecified error' number: 0x800404FF. - Sets the COM HResult to . - - - - - Initializes a new instance of the class - with a human-readable descriptive message. - - The human-readable description of the problem. - - - - Initializes a new instance of the class from another caught exception and a human-readable descriptinve message. - - The human-readable description of the problem. - The caught (inner) exception. - - - - Initializes a new instance of the class. - - The that holds the serialized object data about the exception being thrown. - The that contains contextual information about the source or destination. - - The parameter is null. - - - The class name is null or is zero (0). - - - - - The COM error code for this exception (hex 80040400 - 800404FF) - - - - - Error numbers for use by drivers. - - - The range of permitted values falls within the class FACILTY_ITF as - defined by the operating system and COM. These values will never clash with - COM, RPC, or OS error codes. - - Driver developers may extend this class by making use of the partial keyword. - - - - - - Reserved error number (0x80040400) for property or method not implemented. - - - See ASCOM.Exception.NotImplementedException. - - - - - Reserved error code (0x80040401) for reporting an invalid value. - - - See ASCOM.Exception.InvalidValueException. - - - - - Reserved error code (0x80040402) for reporting that a value has not been set. - - - See ASCOM.Exception.ValueNotSetException. - - - - - Reserved error code (0x80040407) used to indicate that the communications channel is not connected. - - - - - Reserved error code (0x80040408) used to indicate that the attempted operation is invalid because the mount - is currently in a Parked state. - - - - - Reserved error code (0x80040409) used to indicate that the attempted operation is invalid because the mount - is currently in a Slaved state. - - - - - Reserved error code (0x8004040A) related to settings. - - - - - Reserved error code (0x8004040B) to indicate that the requested operation can not be undertaken at this time. - - - - - Reserved error code (0x8004040C) to indicate that the requested action is not implemented in this driver. - - - - - Reserved error code (0x8004040D) to indicate that the requested item is not present in the ASCOM cache. - - - The exception is defined in the ASCOM.Cache component rather than ASCOM.Exceptions. - - - - - Reserved 'catch-all' error code (0x800404FF) used when nothing else was specified. - - - - - The starting value (0x80040500) for driver-specific error numbers. - - - Drivers are free to choose their own numbers starting with DriverBase, up to and including DriverMax. - - - - - The maximum value (0x80040FFF) for driver-specific error numbers. - - - Drivers are free to choose their own numbers starting with DriverBase, up to and including DriverMax. - - - - - Exception to report an invalid value supplied to a driver. - - - The most useful way to use this exception is to inform the user which property/method/parameter received the invalid value and also the range of allowed values. - If you need to throw this error as a COM exception use the error number: 0x80040401. - - - - - Create a new exception object and identify the specified driver property or method as the source. - - The name of the driver property/accessor or method that caused the exception - The invalid value that was supplied - - - - - - Create a new exception object and identify the specified driver property or method as the source. - - The name of the driver property/accessor or method that caused the exception - The invalid value that was supplied - The valid value range - - - - Create a new exception object and identify the specified driver property as the source, - and include an inner exception object containing a caught exception. - - The name of the driver property/accessor or method that caused the exception - The invalid value that was supplied - The caught exception - The valid value range - - - - Create a new exception - - Exception description - - - - Create a new exception - - Exception description - The underlying exception that caused this exception to be thrown. - - - - Create a new exception object - - - - - Added to keep Code Analysis happy - - - - - - - The property/accessor or method that has an invalid value. - - - - - The invalid value. - - - - - The valid range for this property. - - - - - The lower value of the valid range. - - - - - The higher end of the valid range. - - - - - This exception should be raised when an operation is attempted that requires communication with the device, but the device is disconnected. - - - If you need to throw this error as a COM exception use the error number: 0x80040400. - - - - - Default public constructor for NotConnectedException takes no parameters. - - - - - Initializes a new instance of the class - from another exception. - - The inner exception. - - - - Initializes a new instance of the class - with a non-default error message. - - A descriptive human-readable message. - - - - Initializes a new instance of the class - based on another exception. - - Descriptive text documenting the cause or source of the error. - The inner exception the led to the throwing of this exception. - - - - Added to keep Code Analysis happy - - - - - - - All properties and methods defined by the relevant ASCOM standard interface must exist in each driver. However, - those properties and methods do not all have to be implemented. This exception is a base class for - PropertyNotImplementedException and MethodNotImplementedException, which drivers should use for throwing - the relevant exception(s). This class is intended to be used by clients who wish to catch either of - the two specific exceptions in a single catch() clause. - - - If you need to throw this error as a COM exception use the error number: 0x80040400. - - - - - A format string used to create the exception's human-readable message. - - - - - Create a new exception object and identify the specified driver property or method as the source. - - The name of the driver property/accessor or method that caused the exception - - - - Create a new exception object and identify the specified driver property as the source, - and include an inner exception object containing a caught exception. - - The name of the driver property/accessor or method that caused the exception - The caught exception - - - - Added to keep Code analysis happy, please don't use it. - - - - - Added to keep Code Analysis happy - - - - - - - The property/accessor or method that is not implemented - - - - - This exception should be used to indicate that movement (or other invalid operation) was attempted while the device was in a parked state. - - - If you need to throw this error as a COM exception use the error number: 0x80040408. - - - - - Initializes a new instance of the class - using default error text and error codes. - - - - - Initializes a new instance of the class - with a caught (inner) exception. - - The inner. - - - - Create a new exception - - Exception description - - - - Create a new exception - - Exception description - Underlying exception that caused this exception to be thrown. - - - - Added to keep Code Analysis happy - - - - - - - All properties defined by the relevant ASCOM standard interface must exist in each driver. However, those properties do not all have to be implemented. The minimum requirement - for each defined property is to throw the ASCOM.PropertyNotImplementedException for each of its accessors. Note that no default constructor is supplied. Throwing this requires both the - property name and unimplemented accessor type to be supplied. - - - If you need to throw this error as a COM exception use the error number: 0x80040400. - - - - - Create a new exception object and identify the specified driver property and accessor as the source. - - The name of the driver property that caused the exception. - True if the exception is being thrown for the 'set' accessor, else false - - - - Create a new exception object and identify the specified driver property as the source, - and include an inner exception object containing a caught exception. - - The name of the driver property that caused the exception - True if the exception is being thrown for the 'set' accessor, else false - The caught exception - - - - Create a new exception - - Exception description - Underlying exception that caused this exception to be thrown. - - - - Create a new exception - - - - - Create a new exception - - Exception description - - - - Initializes a new instance of the class. - - The that holds the serialized object data about the exception being thrown. - The that contains contextual information about the source or destination. - - The parameter is null. - - - The class name is null or is zero (0). - - - - - The property that is not implemented - - - - - True if the 'set' accessor is not implemented, else false - - - - - This exception should be used to indicate that movement (or other invalid operation) was attempted while the device was in slaved mode. This applies primarily to domes drivers. - - - If you need to throw this error as a COM exception use the error number: 0x80040409. - - - - - Initializes a new instance of the class. - - - - - Initializes a new instance of the class - with a caught (inner) exception. - - Inner exception - - - - Create a new exception - - Exception description - - - - Create a new exception - - Exception description - Underlying exception that caused this exception to be thrown. - - - - Create a new exception - - Information required to serialise the exception - Information of the serialising stream context. - - - - Exception to report that no value has yet been set for this property. - - - If you need to throw this error as a COM exception use the error number: 0x80040402. - - - - - Create a new exception object and identify the specified driver property or method as the source. - - The name of the driver property/accessor or method that caused the exception - - - - Create a new exception object and identify the specified driver property as the source, - and include an inner exception object containing a caught exception. - - The name of the driver property/accessor or method that caused the exception - The caught exception - - - - Added to keep Code Analysis happy - - - - - Added to keep Code Analysis happy - - - - - - - The property/accessor or method that has no value - - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.Internal.Extensions.xml b/MeadeAutostar497/bin/Debug/ASCOM.Internal.Extensions.xml deleted file mode 100644 index 2478a6c..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.Internal.Extensions.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - ASCOM.Internal.Extensions - - - - - Extension methods relating to . - - - - - The recognized ASCOM device classes. - - - This list is specifically intended to support the Template Project Wizard - and contains a list of the device types for which the Wizard can expand - a project template. - - - - - Determines whether the specified file is device specific. - - The file. - - true if it is device specific; otherwise, false. - - - A file is considered 'device specific' if it meets the following criteria: - - - The filename contains at least two dots ('.'); - - - The first dot-delimited segment of the filename matches one of the - recognized interface types contained in - - - - - - - tring extension methods - - - - - Defines a lookup table of bit masks, for a fast method of determining - a mask for any given bit position. - N.B. It might just be quicker to raise to a power of two, - the compiler might be smart enough to optimize that. - - - - - Returns a boolean value corresponding to the value at the specified bit position. - - The register, an unsigned integer, containing bit values. - The bit position to be tested, where bit 0 is the least significant bit. - A boolean value corresponding to the bit at the specified bit position. - - - - Returns a boolean value corresponding to the value at the specified bit position. - - The register, an integer, containing bit values. - The bit position to be tested, where bit 0 is the least significant bit. - A boolean value corresponding to the bit at the specified bit position. - - - - String extension methods. - - - Internal use only. Driver and application developers should not rely on this class, - because the interface and method signatures may change at any time. - - - - - Returns the specified number of characters from the head of a string. - - The source string. - The number of characters to be returned, must not be greater than the length of the string. - The specified number of characters from the head of the source string, as a new string. - Thrown if the requested number of characters exceeds the string length. - - - - Returns the specified number of characters from the tail of a string. - - The source string. - The number of characters to be returned, must not be greater than the length of the string. - The specified number of characters from the tail of the source string, as a new string. - Thrown if the requested number of characters exceeds the string length. - - - - Cleans (that is, removes all unwanted characters) from the string. - - The source string. - A list of the allowed characters. All other characters will be removed. - A new string with all of the unwanted characters deleted. - - - - Remove the head of the string, leaving the tail. - - The source string. - Number of characters to remove from the head. - - A new string containing the old string with characters removed from the head. - - - - - Remove the tail of the string, leaving the head. - - The source string. - Number of characters to remove from the tail. - A new string containing the old string with characters removed from the tail. - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.MeadeAutostar497.Telescope.dll.config b/MeadeAutostar497/bin/Debug/ASCOM.MeadeAutostar497.Telescope.dll.config deleted file mode 100644 index e4eb090..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.MeadeAutostar497.Telescope.dll.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - -
    - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.SettingsProvider.xml b/MeadeAutostar497/bin/Debug/ASCOM.SettingsProvider.xml deleted file mode 100644 index 18d293e..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.SettingsProvider.xml +++ /dev/null @@ -1,188 +0,0 @@ - - - - ASCOM.SettingsProvider - - - - - The Diagnostics class provides a few helper methods that make it easier to produce coherent - debugging output. The class is implemented as a singleton that is created as soon as the assembly - is loaded. The level of trace output that is produced is controlled by a - that in turn loads its configuration from the App.config file. If there is no App.Config file, - the default is to produce verbose output for debug builds and errors/warnings for release builds. - - We recommend SysInternals DbgView for viewing and capturing the trace output. - See http://www.sysinternals.com - - - - - - Text versions of the various trace levels. - - - - - Construct and initialise diagnostics. - - - - - Gets a reference to the one and only instance of this singleton class. - - a reference to the one and only instance of this singleton class. - - - - Send an object to the trace channel at severity level Error. - - The object (which may be a string) to display. - - - - Format and send a list of objects to the trace channel at severity level Error. - - Format string used to format the objects. - List of objects to be displayed. - - - - Send an object to the trace channel at severity level Warning. - - The object (which may be a string) to display. - - - - Format and send a list of objects to the trace channel at severity level Warning. - - Format string used to format the objects. - List of objects to be displayed. - - - - Send an object to the trace channel at severity level Information. - - The object (which may be a string) to display. - - - - Format and send a list of objects to the trace channel at severity level Information. - - Format string used to format the objects. - List of objects to be displayed. - - - - Send an object to the trace channel at severity level Verbose Information. - - The object (which may be a string) to display. - - - - Format and send a list of objects to the trace channel at severity level Verbose Information. - - Format string used to format the objects. - List of objects to be displayed. - - - - Provides settings storage for ASCOM device drivers. - Settings are persisted in the ASCOM Device Profile store. - - - Original version by Tim Long, March 2009. - Copyright © 2009 TiGra Astronomy, all rights reserved. - http://www.tigranetworks.co.uk/Astronomy - - - - - A reference to an ASCOM profile provider. Normally, this will be the default implementation defined in - , but unit tests can also use dependency injection to provide - a mock provider. This value will be initialized (once) in the constructor. - - - - - Backing store for the ApplicationName property. - - - - - Initializes a new instance of the class with the default - profile provider . - - - - - Initializes a new instance of the class with the supplied - Profile Provider. This is useful for injecting a mock profile object during unit testing. - - The to be used. - - - - Returns the provider's friendly name used during configuration. - - - - - Gets the provider's friendly description. - - - - - Gets the name of the driver or application for which settings are being managed. - This value is set during provider initialization and cannot be changed thereafter. - - - - - Initializes the ASCOM Settings Provider. - - Ignored. - Not used. - - This method is called by to initialize the settings provider. - Normally, this will set the provider's property to the assembly name - of the application. This is later used to determine the storage location of each of the settings. - However, for ASCOM purposes, we can't use the application name and we need to key off the - ASCOM DeviceID of the driver, so in ASCOM.SettingsProvider, the application name is set but never used. - - - - - Retrieves a collection of settings values from the underlying ASCOM Profile store. - - Not used. - The list of properties to be retrieved. - - Returns a collection of the retrieved property values as a - . - - - If any properties are absent in the underlying store, or if an error occurs while - retrieving them, then the property's default value is used. This will be the case - if the driver has never been registered with ASCOM. - - - - - Persists a collection of settings values to the underlying ASCOM Profile store. - - Context to which the settings will be saved - Settings to be saved - - - - Checks whether the driver is registered with ASCOM and, if not, registers it. - - - A reference to a object - that is used to query the ASCOM Device Profile. - - The full ASCOM DeviceID to be verified. - - - diff --git a/MeadeAutostar497/bin/Debug/ASCOM.Utilities.xml b/MeadeAutostar497/bin/Debug/ASCOM.Utilities.xml deleted file mode 100644 index 84210d5..0000000 --- a/MeadeAutostar497/bin/Debug/ASCOM.Utilities.xml +++ /dev/null @@ -1,3867 +0,0 @@ - - - - -ASCOM.Utilities - - - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Class that represents a whole device Profile and which contains a set of methods for for manipulating its contents - - - This class is used by the Profile.GetProfile and Profile.SetProfile methods, do not confuse it with the Profile Class itself. - - - - - Add a new subkey - - Name of the subkey - - - - - Clears all contents - - - - - - Retrieve a registry value - - Name of the value - "SubKey in which the value is located - String value - - - - - Removes a complete subkey - - Subkey to be removed - - - - - Remove a value - - Name of the value to be removed - "SubKey containing the value - - - - - Set a value - - Name of the value to set - Value to be set - "Subkey continaining the value - Changing a value with this method does NOT change the underlying profile store, only the value in this class. - In order to persist the new value, the class should be written back to the profile store through Profile.SetProfile. - - - - Get the collection of values in this profile - - All values in the collection - SortedList(Of SubKey as String, SortedList(Of ValueName as String, Value as String)) - - - - - Retrieve a registry value from the driver top level subkey - - Name of the value - String value - - - - - Remove a value from the driver top level subkey - - Name of the value to be removed - - - - - Set a value in the driver top level subkey - - Name of the value to set - Value to be set - - - - - List of available conversion units for use in the Util.ConvertUnits method - - - - - The Chooser object provides a way for your application to let your user select the telescope to use. - - - Calling Chooser.Choose() causes a chooser window to appear, with a drop down selector list containing all of the registered Telescope - drivers, listed by the driver's friendly/display name. The user sees a list of telescope types and selects one. - Before the OK button will light up, however, the user must click the Setup button, causing the selected driver's setup dialog to appear - (it calls the driver's Telescope.SetupDialog() method). When the setup dialog is closed, the OK button will light and allow the user - to close the Chooser itself. - - The Choose() method returns the DriverID of the selected driver. Choose() allows you to optionally pass the DriverID of a "current" - driver (you probably save this in the registry), and the corresponding telescope type is pre-selected in the Chooser's list. In this case, - the OK button starts out enabled (lit-up); the assumption is that the pre-selected driver has already been configured. - - - - - Creates a new Chooser object - - - - - - Does the work of cleaning up objects used by Chooser - - True if called by the user, false if called by the system - You can't call this directly, use Dispose with no arguments instead. - - - - Cleans up and disposes objects used by Chooser - - - - - - The type of device for which the Chooser will select a driver. (String, default = "Telescope") - - The type of device for which the Chooser will select a driver. (String, default = "Telescope") - - The device type that has been set - Thrown on setting the device type to empty string - This property changes the "personality" of the Chooser, allowing it to be used to select a driver for any arbitrary - ASCOM device type. The default value for this is "Telescope", but it could be "Focuser", "Camera", etc. - This property is independent of the Profile object's DeviceType property. Setting Chooser's DeviceType - property doesn't set the DeviceType property in Profile, you must set that also when needed. - - - - - Select ASCOM driver to use including pre-selecting one in the dropdown list - - Driver to preselect in the chooser dialogue - Driver ID of chosen driver - Thrown if the Chooser.DeviceType property has not been set before Choose is called. - It must be set in order for Chooser to know which list of devices to display. - The supplied driver will be pre-selected in the Chooser's list when the chooser window is first opened. - - - - - Select ASCOM driver to use without pre-selecting in the dropdown list - - Driver ID of chosen driver - No driver will be pre-selected in the Chooser's list when the chooser window is first opened. - Thrown if the Chooser.DeviceType property has not been set before Choose is called. - It must be set in order for Chooser to know which list of devices to display. - This overload is not available through COM, please use "Choose(ByVal DriverProgID As String)" - with an empty string parameter to achieve this effect. - - - - - Class that returns a key and associated value - - This class is used by some Profile properties and methods and - compensates for the inability of .NET to return Generic classes to COM clients. - The properties and methods are: - Profile.RegisteredDevices, - Profile.SubKeys and - Profile.Values. - - - - COM visible default constructor - - - - - - Constructor that can set the key and value simultaneously. - - The Key element of a key value pair - The Value element of a key value pair - - - - - The Key element of a key value pair - - Key - Key as a string - - - - - The Value element of a key value pair. - - Value - Value as a string - - - - - Enum containing all the possible registry access rights values. The buit-in RegistryRights enum only has a partial collection - and often returns values such as -1 or large positive and negative integer values when converted to a string - The Flags attribute ensures that the ToString operation returns an aggregate list of discrete values - - - - - Common code for the new method - - If true, suppresses the exception normally thrown if a valid profile is not present - - - - - Base exception for the Utilities components - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message and inner exception - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when the profile is not found. This is internally trapped and should not appear externally to an application. - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an invalid value is passed to a Utilities component - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when a serial port method is already in progress and a second attempt is made to use the serial port. - - This exception is only thrown after 5 attempts, each with a 1 second timeout, have been made to - acquire the serial port. It may indicate that you have more than one thread attempting to access the serial - port and that you have not synchronised these within your application. The serial port can only handle - one transaction at a time e.g. Serial.Receive or Serial.Transmit etc. - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown if there is any problem in reading or writing the profile from or to the file system - - This is an ifrastructural exception indicatig that there is a problem at the file access layer - in the profile code. Possible underlying reasons are security access permissions, file system full and hardware failure. - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when a profile request is made for a driver that is not registered - - Drivers must be registered before other profile commands are used to manipulate their - values. - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an attempt is made to write to a protected part of the the Profile store that is - reserved for Platform use. An example is attempting to write to the the default value of a device driver - profile. This value is reserved for use by the Chooser to display the device description and is set by the - Profile.Register method. - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Exception thrown when an attempt is made to read a value that has not yet been set. - - - - - - - Create a new exception with message - - Message to be reported by the exception - - - - - Create a new exception with message - - Message to be reported by the exception - Exception to be reported as the inner exception - - - - - Serialise the exception - - Serialisation information - Serialisation context - - - - - Interface for KeyValuePair class - - This is a return type only used by a small number of the Profile.XXXCOM commands. Including - IProfile.RegisteredDevices, - IProfile.SubKeys and - IProfile.Values. - - - - Key member of a key value pair - - Key - Ky as string - - - - - Value memeber of a key value pair - - Value - Value as string - - - - - Interface to the TraceLogger component - - - - - - Writes the time and identifier to the log, leaving the line ready for further content through LogContinue and LogFinish - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - Use this to start a log line where you want to write further information on the line at a later time. - E.g. You might want to use this to record that an action has started and then append the word OK if all went well. - You would then end up with just one line to record the whole transaction even though you didn't know that it would be - successful when you started. If you just used LogMsg you would have ended up with two log lines, one showing - the start of the transaction and the next the outcome. - Will create a LOGISSUE message in the log if called before a line started by LogStart has been closed with LogFinish. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Appends further message to a line started by LogStart, appends a hex translation of the message to the line, does not terminate the line. - - The additional message to appear in the line - True to append a hex translation of the message at the end of the message - - This can be called multiple times to build up a complex log line if required. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Closes a line started by LogStart with option to append a translation of the supplied message into HEX - - The final message to appear in the line - True to append a hex translation of the message at the end of the message - - - - - Closes a line started by LogStart with the supplied message and a hex translation of the message - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - The final message to terminate the line - True to append a hex translation of the message at the end of the message - - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Enables or disables logging to the file. - - True to enable logging - Boolean, current logging status (enabled/disabled). - If this property is false then calls to LogMsg, LogStart, LogContinue and LogFinish do nothing. If True, - supplied messages are written to the log file. - - - - Logs an issue, closing any open line and opening a continuation line if necessary after the - issue message. - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - Use this for reporting issues that you don't want to appear on a line already opened - with StartLine - - - - Sets the log filename and type if the constructor is called without parameters - - Fully qualified trace file name or null string to use automatic file naming (recommended) - String identifying the type of log e,g, Focuser, LX200, GEMINI, MoonLite, G11 - The LogFileType is used in the file name to allow you to quickly identify which of several logs contains the - information of interest. - Note This command is only required if the tracelogger constructor is called with no - parameters. It is provided for use in COM clients that can not call constructors with parameters. - If you are writing a COM client then create the trace logger as: - - TL = New TraceLogger() - TL.SetLogFile("","TraceName") - - If you are writing a .NET client then you can achieve the same end in one call: - - TL = New TraceLogger("",TraceName") - - - - - - Insert a blank line into the log file - - - - - - Return the full filename of the log file being created - - Full filename of the log file - String filename - This call will return an empty string until the first line has been written to the log file - as the file is not created until required. - - - - Displays a message respecting carriage return and linefeed characters - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - The final message to terminate the line - - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Set or return the path to a directory in which the log file will be created - - Path to the log directory - String path - Introduced with Platform 6.4.If set, this path will be used instead of the the user's Documents directory default path. This must be Set before the first message Is logged. - - - - Set or return the width of the identifier field in the log message - - Width of the identifier field - Integer width - Introduced with Platform 6.4.If set, this width will be used instead of the default identifier field width. - - - - Addiitonal methods that are only visible to .NET clients and not to COM clients - - - - - - Appends further message to a line started by LogStart, does not terminate the line. - - The additional message to appear in the line - - This can be called multiple times to build up a complex log line if required. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogContinue(ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Closes a line started by LogStart with the supplied message - - The final message to terminate the line - - Can only be called once for each line started by LogStart. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogFinish(ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Logs a complete message in one call - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - - Use this for straightforward logging requrements. Writes all information in one command. - Will create a LOGISSUE message in the log if called before a line started by LogStart has been closed with LogFinish. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogMessage(ByVal Identifier As String, ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Interface to the .NET Chooser component - - - - - - The type of device for which the Chooser will select a driver. (String, default = "Telescope") - - The type of device for which the Chooser will select a driver. (String, default = "Telescope") - - The device type that has been set - This property changes the "personality" of the Chooser, allowing it to be used to select a driver for any arbitrary - ASCOM device type. The default value for this is "Telescope", but it could be "Focuser", "Camera", etc. - This property is independent of the Profile object's DeviceType property. Setting Chooser's DeviceType - property doesn't set the DeviceType property in Profile, you must set that also when needed. - - - - - Select ASCOM driver to use including pre-selecting one in the dropdown list - - Driver to preselect in the chooser dialogue - Driver ID of chosen driver - The supplied driver will be pre-selected in the Chooser's list when the chooser window is first opened. - - - - - Addiitonal methods that are only visible to .NET clients and not to COM clients - - - - - - Select ASCOM driver to use without pre-selecting in the dropdown list - - Driver ID of chosen driver - No driver will be pre-selected in the Chooser's list when the chooser window is first opened. - This overload is not available through COM, please use "Choose(ByVal DriverProgID As String)" - with an empty string parameter to achieve this effect. - - - - - Interface to the .NET Util component - - - - - - Pauses for a given interval in milliseconds. - - The number of milliseconds to wait - Repeatedly puts the calling Win32 process to sleep, totally freezing it, for 10 milliseconds, - then pumps events so the script or program calling it will receive its normal flow of events, until the - pause interval elapses. If the pause interval is 20 milliseconds or less, the sleep interval is reduced - to 0, causing the calling Win32 process to give up control to the kernel scheduler and then immediately - become eligible for scheduling. - - - - Convert sexagesimal degrees to binary double-precision degrees - - The sexagesimal input string (degrees) - The double-precision binary value (degrees) represented by the sexagesimal input - The sexagesimal to real conversion methods such as this one are flexible enough to convert just - about anything that resembles sexagesimal. Thee way they operate is to first separate the input string - into numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. Of course it - would not be normal (for example) for both the minutes and seconds parts to have fractional parts, but it - would be legal. So 00:30.5:30 would convert to 1.0 unit. - Note that plain units, for example 23.128734523 are acceptable to the method. - - - - - Convert sexagesimal hours to binary double-precision hours - - The sexagesimal input string (hours) - The double-precision binary value (hours) represented by the sexagesimal input - - The sexagesimal to real conversion methods such as this one are flexible enough to convert just about - anything that resembles sexagesimal. Thee way they operate is to first separate the input string into - numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. - - Of course it would not be normal (for example) for both the minutes and seconds parts to have - fractional parts, but it would be legal. So 00:30.5:30 would convert to 1.0 unit. Note that plain units, - for example 23.128734523 are acceptable to the method. - - - - - Convert sexagesimal hours to binary double-precision hours - - The sexagesimal input string (hours) - The double-precision binary value (hours) represented by the sexagesimal input - - The sexagesimal to real conversion methods such as this one are flexible enough to convert just about - anything that resembles sexagesimal. Thee way they operate is to first separate the input string into - numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. - - Of course it would not be normal (for example) for both the minutes and seconds parts to have - fractional parts, but it would be legal. So 00:30.5:30 would convert to 1.0 unit. Note that plain units, - for example 23.128734523 are acceptable to the method. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with specified second decimal places - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with specified number of second decimal places - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal degrees and minutes with the specified number of minute decimal places - - The degrees value to convert - The delimiter string separating degrees - The delimiter string to append to the minutes - The number of digits after the decimal point on the minutes part - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert hours to sexagesimal hours and minutes with supplied number of minute decimal places - - The hours value to convert - The delimiter string separating hours - The delimiter string to append to the minutes part - The number of digits after the decimal point on the minutes part - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the specified number of second decimal places - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal hours and minutes with supplied number of minute decimal places - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - The number of minutes decimal places - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - - - - - Current Platform version in m.n form - - Current Platform version in m.n form - - - - - Change the serial trace file (default C:\SerialTrace.txt) - - Serial trace file name including fully qualified path e.g. C:\SerialTrace.txt - Serial trace file name - Change this before setting the SerialTrace property to True. - - - - Enable/disable serial I/O tracing - - Boolean - Enable/disable serial I/O tracing - Enabled - disabled state of serial tracing - If you want to change the serial trace file path, change the SerialTraceFile property before setting this to True. - After setting this to True, serial trace info will be written to the last-set serial trace file. - - - - The name of the computer's time zone - - The name of the computer's time zone - This will be in the local language of the operating system, and will reflect any daylight/summer time that may be in - effect. - - - - UTC offset (hours) for the computer's clock - - UTC offset (hours) for the computer's clock - The offset is in hours, such that UTC = local + offset. The offset includes any daylight/summer time that may be - in effect. - - - - The current UTC Date - - The current UTC Date - - - - - Current Julian date - - Current Julian date - This is quantised to the second in the COM component but to a small decimal fraction in the .NET component - - - - Convert local-time Date to Julian date - - Date in local-time - Julian date - Julian dates are always in UTC - - - - Convert Julian date to local-time Date - - Julian date to convert - Date in local-time for the given Julian date - Julian dates are always in UTC - - - - Convert UTC Date to Julian date - - UTC date to convert - Julian date - Julian dates are always in UTC - - - - Convert Julian date to UTC Date - - Julian date - Date in UTC for the given Julian date - Julian dates are always in UTC - - - - Convert UTC Date to local-time Date - - Date in UTC - Date in local-time - - - - - Convert local-time Date to UTC Date - - Date in local-time - Date in UTC - - - - - Tests whether the current platform version is at least equal to the supplied major and minor - version numbers, returns false if this is not the case - - The required major version number - The required minor version number - True if the current platform version equals or exceeds the major and minor values provided - This function provides a simple way to test for a minimum platform level. - If for example, your application requires at least platform version 5.5 then you can use - code such as this to make a test and display information as appropriate. - Const Int requiredMajorVersion = 5; - Const Int requiredMinorVersion = 5; // Requires Platform version 5.5 - Bool isOK = ASCOM.Utilities.IsMinimumRequiredVersion(requiredMajorVersion, - requiredMinorVersion); - If (isOK) - // Do the install (or whatever) - Else - // Abort, throw exception, print an error. - - - - - Converts a safearray of strings to a collection that can be used in scripting. - This is required to do things such as handling the array of names returned by the FilterWheel.Names property. - This string array won't work in scripting languages. - - array of strings - Collection of strings - - - - - Converts a safearray of integers to a collection that can be used in scripting languages. - This is required to handle properties that are returned as safearrays of integers, for example FilterWheel.FocusOffsets - SafeArrays don't work in scripting languages. - - array of integers - Collection of Integers - - - - - Convert an array of .NET built-in types to an equivalent Variant arrray (array of .NET Objects) - - The array to convert to variant types - A Variant array - If the supplied array contains elements of an unsuported Type. - If the array rank is outside the range 1 to 5. - If the supplied object is not an array. - This function will primarily be of use to Scripting Language programmers who need to convert Camera and Video ImageArrays from their native types to Variant types. If this is not done, - the scripting language will throw a type mismatch exception when it receives, for example, Int32 element types instead of the expected Variant types. - A VBScript Camera usage example is: Image = UTIL.ArrayToVariantArray(CAMERA.ImageArray) This example assumes that the camera and utilities objects have already been created with CreateObject statements. - The supported .NET types are: - - Int16 - Int32 - UInt16 - UInt32 - UInt64 - Byte - SByte - Single - Double - Boolean - DateTime - String - - - The function supports arrays with 1 to 5 dimensions (Rank = 1 to 5). If the supplied array already contains elements of Variant type, it is returned as-is without any processing. - - - - Platform major version number - - Platform major version number - Integer version number - - - - - Platform minor version number - - Platform minor version number - Integer version number - - - - - Platform service pack number - - Platform service pack number - Integer service pack number - - - - - Platform build number - - Platform build number - Integer build number - - - - - Convert from one set of units to another - - Value to convert - Integer value from the Units enum indicating the value's current units - Integer value from the Units enum indicating the units to which the input value should be converted - Input value converted to the new specified units - - - - Calculate the dew point given the ambient temperature and humidity - - Humidity expressed in percent (0.0 .. 100.0) - Ambient temperature in degrees C - Dew point in degrees C - - - - Calculate the humidity given the ambient temperature and dew point - - Dewpoint in degrees C - Ambient temperature in degrees C - Humidity expressed in percent (0.0 .. 100.0) - - - - Convert atmospheric pressure from one altitude above mean sea level to another - - Measured pressure in hPa at the "From" altitude - "Altitude at which the input pressure was measured - Altitude to which the pressure is to be converted - Pressure in hPa at the "To" altitude - - - - Addiitonal methods that are only visible to .NET clients and not to COM clients - - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with default delimiters DD° MM' SS" - - The degrees value to convert - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use "Choose(ByVal DriverProgID As String)" - with an empty string parameter to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with with default minute and second delimiters MM' SS" - - The degrees value to convert - The delimiter string separating degrees and minutes - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with default second delimiter SS" - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - The delimiter string to append to the seconds part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default delimiters HH:MM:SS - - The hours value to convert - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default minutes and seconds delimters MM:SS - - The hours value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default second delimiter of null string - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes with default delimiters DD° MM' - - The degrees value to convert - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes with the default minutes delimeter MM' - - The degrees value to convert - The delimiter string separating degrees - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes - - The degrees value to convert - The delimiter string separating degrees - The delimiter string to append to the minutes - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes with default delimiters HH:MM - - The hours value to convert - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes with default minutes delimiter MM (null string) - - The hours value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with default delimters of HH:MM:SS - - The degrees value to convert - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the default second and minute delimiters of MM:SS - - The degrees value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the default second delimiter SS (null string) - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes with default delimiters HH:MM - - The degrees value to convert - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes with default minute delimiter MM (null string) - - The degrees value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Interface to the .NET Timer component - - - - - - The interval between Tick events when the timer is Enabled in milliseconds, (default = 1000) - - The interval between Tick events when the timer is Enabled (milliseconds, default = 1000) - The interval between Tick events when the timer is Enabled in milliseconds - - - - - Enable the timer tick events - - True means the timer is active and will deliver Tick events every Interval milliseconds. - Enabled state of timer tick events - - - - - Timer event interface - - - - - - Fired once per Interval when timer is Enabled. - - To sink this event in Visual Basic, declare the object variable using the WithEvents keyword. - - - - Interface to the .NET Profile component - - - - - - The type of ASCOM device for which profile data and registration services are provided - (String, default = "Telescope") - - String describing the type of device being accessed - String describing the type of device being accessed - - - - - List the device types registered in the Profile store - - List of registered device types - An ArrayList of device types - Use this to find which types of device are registered in the Profile store. - - - - List the devices of a given device type that are registered in the Profile store - - Type of devices to list - An ArrayList of KeyValuePair objects of installed devices and associated device descriptions - Throw if the supplied DeviceType is empty string or - null value. - - Use this to find all the registerd devices of a given type that are in the Profile store. - If a DeviceType is supplied, where no device of that type has been registered before on this system, - an empty list will be returned - Platform 6 Profile.RegisteredDevices was introduced in Platform 5.5 as a read only property that took - DeviceType as a parameter, which is legal syntax in Visual Basic .NET but is not interpreted correctly in C#. Consequently, - a breaking change has been introduced in Platform 6 that changes the property into a parameterised method which works correctly in - all .NET languages. - This change does not require you to alter your source code but you may need to recompile your application under Platform 6 - to ensure that there are no runtime errors. - - - - - Confirms whether a specific driver is registered ort unregistered in the profile store - - String reprsenting the device's ProgID - Boolean indicating registered or unregisteredstate of the supplied DriverID - - - - - Registers a supplied DriverID and associates a descriptive name with the device - - ProgID of the device to register - Descriptive name of the device - Does nothing if already registered, so safe to call on driver load. - - - - Remove all data for the given DriverID from the registry. - - ProgID of the device to unregister - This deletes the entire device profile tree, including the DriverID root key. - - - - Retrieve a string value from the profile using the supplied subkey for the given Driver ID - and variable name. Set and return the default value if the requested variable name has not yet been set. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root from which to read the value - Default value to be used if there is no value currently set - Retrieved variable value - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - If a default value is supplied and the value is not already present in the profile store, - the default value will be set in the profile store and then returned as the value of the - DriverID/SubKey/Name. If the default value is set to null (C#) or Nothing (VB) then no value will - be set in the profile and an empty string will be returned as the value of the - DriverID/SubKey/Name. - - - - - Writes a string value to the profile using the supplied subkey for the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - The string value to be written - Subkey from the profile root in which to write the value - - - - - Return a list of the (unnamed and named variables) under the given DriverID and subkey. - - ProgID of the device to read from - Subkey from the profile root from which to return values - An ArrayList of KeyValuePair objects. - The returned object contains entries for each value. For each entry, - the Key property is the value's name, and the Value property is the string value itself. Note that the unnamed (default) - value will be included if it has a value, even if the value is a blank string. The unnamed value will have its entry's - Key property set to an empty string. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Delete the value from the registry. Name may be an empty string for the unnamed value. Value will be deleted from the subkey supplied. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root in which to write the value - Specify "" to delete the unnamed value which is also known as the "default" value for a registry key. - - - - Create a registry key for the given DriverID. - - ProgID of the device to read from - Subkey from the profile root in which to write the value - If the SubKey argument contains a \ separated path, the intermediate keys will be created if needed. - - - - Return a list of the sub-keys under the given DriverID (for COM clients) - - ProgID of the device to read from - Subkey from the profile root in which to search for subkeys - An ArrayList of key-value pairs - The returned object (scripting.dictionary) contains entries for each sub-key. For each KeyValuePair in the list, - the Key property is the sub-key name, and the Value property is the value. The unnamed ("default") value for that key is also returned. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Delete a registry key for the given DriverID. SubKey may contain \ separated path to key to be deleted. - - ProgID of the device to read from - Subkey from the profile root in which to write the value - The sub-key and all data and keys beneath it are deleted. - - - - Read an entire device profile - - The ProgID of the device - Device profile encoded in XML - This method will be implemented in a future update - This is not implemented and returns a MethodNotImplemented exception, - it will be implemented in a future update. An XML schema will also be made available to support - this method. - - - - Set an entire device profile - - The ProgID of the device - An XML encoding of the profile - This method will be implemented in a future update - This is not implemented and returns a MethodNotImplemented exception, - it will be implemented in a future update. An XML schema will also be made available to support - this method. - - - - Addiitonal methods that are only visible to .NET clients and not to COM clients - - - - - - Migrate the ASCOM profile from registry to file store - - The platform version number of the current profile store beig migrated - - - - - Delete the value from the registry. Name may be an empty string for the unnamed value. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Specify "" to delete the unnamed value which is also known as the "default" value for a registry key. - This overload is not available through COM, please use - "DeleteValue(ByVal DriverID As String, ByVal Name As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Retrieve a string value from the profile for the given Driver ID and variable name - - ProgID of the device to read from - Name of the variable whose value is retrieved - Retrieved variable value - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - This overload is not available through COM, please use - "GetValue(ByVal DriverID As String, ByVal Name As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Retrieve a string value from the profile using the supplied subkey for the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root from which to read the value - Retrieved variable value - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - - - - - Return a list of the sub-keys under the root of the given DriverID - - ProgID of the device to read from - An ArrayList of key-value pairs - The returned object (scripting.dictionary) contains entries for each sub-key. For each KeyValuePair in the list, - the Key property is the sub-key name, and the Value property is the value. The unnamed ("default") value for that key is also returned. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Return a list of the (unnamed and named variables) under the given DriverID. - - ProgID of the device to read from - An ArrayList of KeyValuePair objects. - The returned object contains entries for each value. For each entry, - the Key property is the value's name, and the Value property is the string value itself. Note that the unnamed (default) - value will be included if it has a value, even if the value is a blank string. The unnamed value will have its entry's - Key property set to an empty string. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Writes a string value to the profile using the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - The string value to be written - - This overload is not available through COM, please use - "WriteValue(ByVal DriverID As String, ByVal Name As String, ByVal Value As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Read an entire device profile and return it as an XML encoded string - - The ProgID of the device - Device profile represented as a recusrive class - Returns a whole driver profile encoded as an XML string - - - - Set an entire device profile from an XML encoded string - - The ProgID of the device - A class representing the profile - Set a whole device Profile in one call using a recusrive ProfileKey class - - - - Interface to the .NET Serial component - - - - - - Returns a list of all available ASCOM serial ports with COMnnn ports sorted into ascending port number order - - String array of available serial ports - A string array of available serial ports - Update in platform 6.0.0.0 This call uses the .NET Framework to retrieve available - COM ports and this has been found not to return names of some USB serial adapters. Additional - code has been added to attempt to open all COM ports up to COM32. Any ports that can be - successfully opened are now returned alongside the ports returned by the .NET call. - If this new approach still does not detect a COM port it can be forced to appear in the list by adding its name - as a string entry in the ForceCOMPorts key of the ASCOM Profile. In the event that this scanning causes issues, a COM port can be - omitted from the scan by adding its name as a string entry in the IgnoreCOMPorts key of the ASCOM Profile. - - - - Gets or sets the number of data bits in each byte - - The number of data bits in each byte, default is 8 data bits - Integer number of data bits in each byte - The data bits value is less than 5 or more than 8 - - - - - Gets or sets the state of the DTR line - - The state of the DTR line, default is enabled - Boolean true/false indicating enabled/disabled - - - - - Gets or sets the type of parity check used over the serial link - - The type of parity check used over the serial link, default none - One of the Ports.Parity enumeration values - - - - - Gets or sets the number of stop bits used on the serial link - - the number of stop bits used on the serial link, default 1 - One of the Ports.StopBits enumeration values - - - - - Gets or sets the type of serial handshake used on the serial line - - The type of handshake used on the serial line, default is none - One of the Ports.Handshake enumeration values - Use of the RTS line can additionally be controlled by the property. - - - - Gets or sets the connected state of the ASCOM serial port. - - Connected state of the serial port. - True if the serial port is connected. - Set this property to True to connect to the serial (COM) port. You can read the property to determine if the object is connected. - - - - Gets or sets the number of the ASCOM serial port (Default is 1, giving COM1 as the serial port name). - - COM port number of the ASCOM serial port. - Integer, number of the ASCOM serial port - This works for serial port names of the form COMnnn. Use PortName if your COM port name does not fit the form COMnnn. - - - - The maximum time that the ASCOM serial port will wait for incoming receive data (seconds, default = 5) - - Integer, serial port timeout in seconds - Integer, serial port timeout in seconds. - The minimum delay timout that can be set through this command is 1 seconds. Use ReceiveTimeoutMs to set a timeout less than 1 second. - - - - The maximum time that the ASCOM serial port will wait for incoming receive data (milliseconds, default = 5000) - - Integer, serial port timeout in milli-seconds - Integer, serial port timeout in milli-seconds - If a timeout occurs, an IO timeout error is raised. See ReceiveTimeout for an alternate form - using the timeout in seconds. - - - - Sets the ASCOM serial port name as a string - - Serial port name to be used - Current serial port name - This property allows any serial port name to be used, even if it doesn't conform to a format of COMnnn - If the required port name is of the form COMnnn then Serial.Port=nnn and Serial.PortName="COMnnn" are - equivalent. - - - - Gets and sets the baud rate of the ASCOM serial port - - Port speed using the PorSpeed enum - Port speed using the PortSpeed enum - This is modelled on the COM component with possible values enumerated in the PortSpeed enum. - - - - Clears the ASCOM serial port receive and transmit buffers - - - - - - Transmits a string through the ASCOM serial port - - String to transmit - - - - - Transmit an array of binary bytes through the ASCOM serial port - - Byte array to transmit - - - - - Adds a message to the ASCOM serial trace file - - String identifying the module logging the message - Message text to be logged. - - This can be called regardless of whether logging is enabled - - - - - Receive at least one text character from the ASCOM serial port - - The characters received - This method reads all of the characters currently in the serial receive buffer. It will not return - unless it reads at least one character. A timeout will cause a TimeoutException to be raised. Use this for - text data, as it returns a String. - - - - Receive one binary byte from the ASCOM serial port - - The received byte - Use this for 8-bit (binary data). If a timeout occurs, a TimeoutException is raised. - - - - Receive exactly the given number of characters from the ASCOM serial port and return as a string - - The number of characters to return - String of length "Count" characters - If a timeout occurs a TimeoutException is raised. - - - - Receive exactly the given number of characters from the ASCOM serial port and return as a byte array - - The number of characters to return - Byte array of size "Count" elements - - If a timeout occurs, a TimeoutException is raised. - This function exists in the COM component but is not documented in the help file. - - - - - Receive characters from the ASCOM serial port until the given terminator string is seen - - The character string that indicates end of message - Received characters including the terminator string - If a timeout occurs, a TimeoutException is raised. - - - - Receive characters from the ASCOM serial port until the given terminator bytes are seen, return as a byte array - - Array of bytes that indicates end of message - Byte array of received characters - - If a timeout occurs, a TimeoutException is raised. - This function exists in the COM component but is not documented in the help file. - - - - - Gets or sets use of the RTS handshake control line - - The state of RTS line use, default is disabled (false) - Boolean true/false indicating RTS line use enabled/disabled - By default the serial component will not drive the RTS line. If RTSEnable is true, the RTS line will be raised before - characters are sent. Please also see the associated property. - - - - Update a COM registration assembly executable reference (mscoree.dll) from a relative path to an absolute path - - This is necessary to ensure that the mscoree.dll can be found when the SetSearchDirectories function has been called in an application e.g. by Inno installer post v5.5.9. - The COM class name and ClassID are determined from the supplied type definition. If the ClassID cannot be determined it is looked up through the COM registration registry entry through the class's ProgID - - - - - Add an event record to the ASCOM Windows event log - - Name of routine creating the event - Event message - Event severity - Id number - Initiating exception or Nothing - - - - - Returns true when the application is 32bit and running on a 64bit OS - - True when the application is 32bit and running on a 64bit OS - - - - - Determines whether the specified process is running under WOW64 i.e. is a 32bit application running on a 64bit OS. - - A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. - For more information, see Process Security and Access Rights.Windows Server 2003 and Windows XP: - The handle must have the PROCESS_QUERY_INFORMATION access right. - A pointer to a value that is set to TRUE if the process is running under WOW64. If the process is running under - 32-bit Windows, the value is set to FALSE. If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE. - If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended - error information, call GetLastError. - - - - - Return a message when a driver is not compatible with the requested 32/64bit application type. Returns an empty string if the driver is compatible - - ProgID of the driver to be assessed - Application bitness for which application compatibility should be tested - String compatibility message or empty string if driver is fully compatible - - - - - - - - - - ASCOM Scope Driver Helper Registry Profile Object - - - This object provides facilities for registering ASCOM drivers with the Chooser, and for storing - persistence information in a shared area of the file system. - Please code to the IProfile interface - - - - - Create a new Profile object - - - - - - Create a new profile object ignoring profile not found exceptions if generated - - Ignore ProfileNotFound exceptions - - - - - Disposes of resources used by the profile object - called by IDisposable interface - - - - - - - Disposes of resources used by the profile object - - - - - - The type of ASCOM device for which profile data and registration services are provided - (String, default = "Telescope") - - String describing the type of device being accessed - String describing the type of device being accessed - Thrown on setting the device type to empty string - - - - - List the device types registered in the Profile store - - List of registered device types - A sorted arraylist of device type strings - Use this to find the types of device that are registered in the Profile store. - Device types are returned without the suffix " Devices" that is used in key names within the - profile store; this allows direct use of returned device types inside For Each loops as shown in - the Profile code example. - - - - - List the devices of a given device type that are registered in the Profile store - - Type of devices to list - An ArrayList of installed devices and associated device descriptions - Throw if the supplied DeviceType is empty string or - null value. - - Use this to find all the registerd devices of a given type that are in the Profile store - If a DeviceType is supplied, where no device of that type has been registered before on this system, - an empty list will be returned - - - - - Confirms whether a specific driver is registered ort unregistered in the profile store - - String reprsenting the device's ProgID - Boolean indicating registered or unregisteredstate of the supplied DriverID - - - - - Registers a supplied DriverID and associates a descriptive name with the device - - ProgID of the device to register - Descriptive name of the device - Does nothing if already registered, so safe to call on driver load. - - - - Remove all data for the given DriverID from the registry. - - ProgID of the device to unregister - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - This deletes the entire device profile tree, including the DriverID root key. - Unregister must only be called if the driver has already been registered. If you are not sure - use the IsRegistered function to check the status and only unregister if the driver is registered. - - - - - Retrieve a string value from the profile using the supplied subkey for the given Driver ID - and variable name. Set and return the default value if the requested variable name has not yet been set. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root from which to read the value - Default value to be used if there is no value currently set - Retrieved variable value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - If a default value is supplied and the value is not already present in the profile store, - the default value will be set in the profile store and then returned as the value of the - DriverID/SubKey/Name. If the default value is set to null (C#) or Nothing (VB) then no value will - be set in the profile and an empty string will be returned as the value of the - DriverID/SubKey/Name. - - - - - Writes a string value to the profile using the supplied subkey for the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - The string value to be written - Subkey from the profile root in which to write the value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - Thrown if Name and SubKey are both empty strings. This - value is reserved for the device description as it appears in Chooser and is set by Profile.Register - - - - - Return a list of the (unnamed and named variables) under the given DriverID and subkey. - - ProgID of the device to read from - Subkey from the profile root in which to write the value - An ArrayList of KeyValuePairs - The returned object contains entries for each value. For each entry, - the Key property is the value's name, and the Value property is the string value itself. Note that the unnamed (default) - value will be included if it has a value, even if the value is a blank string. The unnamed value will have its entry's - Key property set to an empty string. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Delete the value from the registry. Name may be an empty string for the unnamed value. Value will be deleted from the subkey supplied. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root in which to write the value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - Specify "" to delete the unnamed value which is also known as the "default" value for a registry key. - - - - Create a registry key for the given DriverID. - - ProgID of the device to read from - Subkey from the profile root in which to write the value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - If the SubKey argument contains a \ separated path, the intermediate keys will be created if needed. - - - - Return a list of the sub-keys under the given DriverID - - ProgID of the device to read from - Subkey from the profile root in which to write the value - An ArrayList of key-value pairs - The returned object contains entries for each sub-key. For each KeyValuePair in the list, - the Key property is the sub-key name, and the Value property is the value. The unnamed ("default") value for that key is also returned. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Delete a registry key for the given DriverID. SubKey may contain \ separated path to key to be deleted. - - ProgID of the device to read from - Subkey from the profile root in which to write the value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - The sub-key and all data and keys beneath it are deleted. - - - - Read an entire device profile and return it as an XML encoded string - - The ProgID of the device - Device profile encoded in XML - Please see the code examples in this help file for a description of how to use this method. -The format of the returned XML is shown below. The SubKey element repeats for as many subkeys as are present while the Value element with its - Name and Data memebers repeats as often as there are values in a particular subkey. -
    - <?xml version="1.0" encoding="utf-8" ?> 
    - <ASCOMProfileAL>
    - <SubKey>
    - <SubKeyName /> 
    - <DefaultValue>Default text value</DefaultValue> 
    -    <Values>
    -      <Value>
    -        <Name>Valuename 1</Name> 
    -        <Data>False</Data> 
    -      </Value>
    -      <Value>
    -        <Name>Valuename 2</Name> 
    -        <Data>True</Data> 
    -      </Value>
    -    </Values>
    -  </SubKey>
    -  <SubKey>
    -    <SubKeyName>Settings</SubKeyName> 
    -    <DefaultValue /> 
    -    <Values>
    -      <Value>
    -        <Name>Valuename 3</Name> 
    -        <Data>1</Data> 
    -      </Value>
    -      <Value>
    -        <Name>Valuename 4</Name> 
    -        <Data>53.4217</Data> 
    -      </Value>
    -    </Values>
    -  </SubKey>
    - </ASCOMProfileAL>
    - 
    -
    - - - Set an entire device profile from an XML encoded string - - The ProgID of the device - An XML encoding of the profile - Please see the code examples in this help file for a description of how to use this method. See GetProfileXML for a - description of the XML format. - - - - Read an entire device profile and return it as an ASCOMProfile class instance - - The ProgID of the device - Device profile represented as a recusrive class - Please see the code examples in this help file for a description of how to use this method. - - - - Set an entire device profile from an ASCOMProfile class instance - - The ProgID of the device - A class representing the profile - Please see the code examples in this help file for a description of how to use this method. - - - - Migrate the ASCOM profile from registry to file store - - The platform version number of the current profile store beig migrated - - - - - Delete the value from the registry. Name may be an empty string for the unnamed value. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - Specify "" to delete the unnamed value which is also known as the "default" value for a registry key. - This overload is not available through COM, please use - "DeleteValue(ByVal DriverID As String, ByVal Name As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Retrieve a string value from the profile for the given Driver ID and variable name - - ProgID of the device to read from - Name of the variable whose value is retrieved - Retrieved variable value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - This overload is not available through COM, please use - "GetValue(ByVal DriverID As String, ByVal Name As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Retrieve a string value from the profile using the supplied subkey for the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - Subkey from the profile root from which to read the value - Retrieved variable value - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - - Name may be an empty string for the unnamed value. The unnamed value is also known as the "default" value for a registry key. - Does not provide access to other registry data types such as binary and doubleword. - - - - - Return a list of the sub-keys under the root of the given DriverID - - ProgID of the device to read from - An ArrayList of key-value pairs - The returned object contains entries for each sub-key. For each KeyValuePair in the list, - the Key property is the sub-key name, and the Value property is the value. The unnamed ("default") value for that key is also returned. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Return a list of the (unnamed and named variables) under the root of the given DriverID. - - ProgID of the device to read from - An ArrayList of KeyValuePairs - The returned object contains entries for each value. For each entry, - the Key property is the value's name, and the Value property is the string value itself. Note that the unnamed (default) - value will be included if it has a value, even if the value is a blank string. The unnamed value will have its entry's - Key property set to an empty string. - The KeyValuePair objects are instances of the KeyValuePair class - - - - - Writes a string value to the profile using the given Driver ID and variable name. - - ProgID of the device to read from - Name of the variable whose value is retrieved - The string value to be written - Thrown if DriverID is an empty string. - Thrown if the driver is not registered, - - This overload is not available through COM, please use - "WriteValue(ByVal DriverID As String, ByVal Name As String, ByVal Value As String, ByVal SubKey As String)" - with SubKey set to empty string achieve this effect. - - - - - Enumeration of serial port speeds for use with the Serial port - - This contains an additional speed 230,400 baud that the COM component doesn't support. - - - - Number of stop bits appended to a serial character - - - This enumeration specifies the number of stop bits to use. Stop bits separate each unit of data - on an asynchronous serial connection. - The None option is not supported. Setting the StopBits property to None raises an - ArgumentOutOfRangeException. - - - - - No stop bits are used. This value is not supported. Setting the StopBits property to None raises an ArgumentOutOfRangeException. - - - - - - One stop bit is used. - - - - - - 1.5 stop bits are used. - - - - - - Two stop bits are used. - - - - - - The type of parity used on the serial port - - - Parity is an error-checking procedure in which the number of 1s must always be the - same — either even or odd — for each group of bits that is transmitted without error. - Parity is one of the parameters that must be - agreed upon by both sending and receiving parties before transmission can take place. - - - - - Sets the parity bit so that the count of bits set is an even number. - - - - - - Leaves the parity bit set to 1. - - - - - - No parity check occurs. - - - - - - Sets the parity bit so that the count of bits set is an odd number. - - - - - - Leaves the parity bit set to 0. - - - - - - The control protocol used by the serial port - - - - - - No control is used for the handshake. - - - - - - Request-to-Send (RTS) hardware flow control is used. RTS signals that data is available - for transmission. If the input buffer becomes full, the RTS line will be set to false. - The RTS line will be set to true when more room becomes available in the input buffer. - - - - - - Both the Request-to-Send (RTS) hardware control and the XON/XOFF software controls are used. - - - - - - The XON/XOFF software control protocol is used. The XOFF control is sent to stop - the transmission of data. The XON control is sent to resume the transmission. - These software controls are used instead of Request to Send (RTS) and Clear to Send (CTS) - hardware controls. - - - - - - Creates a .NET serial port and provides a simple set of commands to use it. - - This object provides an easy to use interface to a serial (COM) port. - It provides ASCII and binary I/O with controllable timeout. - The interface is callable from any .NET client. - The platform allows you to control use of the DTR and RTS/CTS lines for a particular - COM port and to remove or force listing of individual COM ports in the AvailableComPorts - list through configuration in the ASCOM Profile. - Please see the Tools and Features section of this help file for further details. - - - Example of how to create and use an ASCOM serial port. - - - - - - Disposes of resources used by the profile object - - - - - - Disposes of resources used by the profile object - called by IDisposable interface - - - - - - - Gets or sets the number of data bits in each byte - - The number of data bits in each byte, default is 8 data bits - Integer number of data bits in each byte - The data bits value is less than 5 or more than 8 - - - - - Gets or sets the state of the DTR line - - The state of the DTR line, default is enabled - Boolean true/false indicating enabled/disabled - - - - - Gets or sets use of the RTS handshake control line - - The state of RTS line use, default is disabled (false) - Boolean true/false indicating RTS line use enabled/disabled - By default the serial component will not drive the RTS line. If RTSEnable is true, the RTS line will be raised before - characters are sent. Please also see the associated property. - - - - Gets or sets the type of serial handshake used on the serial link - - The type of flow control handshake used on the serial line, default is none - One of the SerialHandshake enumeration values - Use of the RTS line can additionally be controlled by the property. - - - - Gets or sets the type of parity check used over the serial link - - The type of parity check used over the serial link, default none - One of the SerialParity enumeration values - - - - - Gets or sets the number of stop bits used on the serial link - - the number of stop bits used on the serial link, default 1 - One of the SerialStopBits enumeration values - - - - - Gets or sets the connected state of the ASCOM serial port. - - Connected state of the serial port. - True if the serial port is connected. - Set this property to True to connect to the serial (COM) port. You can read the property to determine if the object is connected. - Throws this exception if the requested - COM port does not exist. - - - - Gets or sets the number of the ASCOM serial port (Default is 1, giving COM1 as the serial port name). - - COM port number of the ASCOM serial port. - Integer, number of the ASCOM serial port - This works for serial port names of the form COMnnn. Use PortName if your COM port name does not fit the form COMnnn. - - - - The maximum time that the ASCOM serial port will wait for incoming receive data (seconds, default = 5) - - Integer, serial port timeout in seconds - Integer, serial port timeout in seconds. - The minimum delay timout that can be set through this command is 1 seconds. Use ReceiveTimeoutMs to set a timeout less than 1 second. - Thrown when value is invalid (outside the range 1 to 120 seconds.) - - - - The maximum time that the ASCOM serial port will wait for incoming receive data (milliseconds, default = 5000) - - Integer, serial port timeout in milli-seconds - Integer, serial port timeout in milli-seconds - If a timeout occurs, an IO timeout error is raised. See ReceiveTimeout for an alternate form - using the timeout in seconds. - Thrown when value is invalid. - - - - Gets and sets the baud rate of the ASCOM serial port - - Port speed using the PortSpeed enum - Port speed as a SerialSpeed enum value - This is modelled on the COM component with possible values enumerated in the PortSpeed enum. - - - - Clears the ASCOM serial port receive and transmit buffers - - Thrown when unable to acquire the serial port - - - - - Receive at least one text character from the ASCOM serial port - - The characters received - Thrown when a receive timeout occurs. - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - This method reads all of the characters currently in the serial receive buffer. It will not return - unless it reads at least one character. A timeout will cause a TimeoutException to be raised. Use this for - text data, as it returns a String. - - - - Receive one binary byte from the ASCOM serial port - - The received byte - Thrown when a receive timeout occurs. - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - Use this for 8-bit (binary data). If a timeout occurs, a TimeoutException is raised. - - - - Receive exactly the given number of characters from the ASCOM serial port and return as a string - - The number of characters to return - String of length "Count" characters - Thrown when a receive timeout occurs. - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - If a timeout occurs a TimeoutException is raised. - - - - Receive exactly the given number of characters from the ASCOM serial port and return as a byte array - - The number of characters to return - Byte array of size "Count" elements - Thrown when a receive timeout occurs. - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - - If a timeout occurs, a TimeoutException is raised. - This function exists in the COM component but is not documented in the help file. - - - - - Receive characters from the ASCOM serial port until the given terminator string is seen - - The character string that indicates end of message - Received characters including the terminator string - Thrown when a receive timeout occurs. - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - If a timeout occurs, a TimeoutException is raised. - - - - Receive characters from the ASCOM serial port until the given terminator bytes are seen, return as a byte array - - Array of bytes that indicates end of message - Byte array of received characters - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - - If a timeout occurs, a TimeoutException is raised. - This function exists in the COM component but is not documented in the help file. - - - - - Transmits a string through the ASCOM serial port - - String to transmit - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - - - - - Transmit an array of binary bytes through the ASCOM serial port - - Byte array to transmit - Thrown when unable to acquire the serial port - Thrown when this command is used before setting Connect = True - - - - - Sets the ASCOM serial port name as a string - - Serial port name to be used - Current serial port name - This property allows any serial port name to be used, even if it doesn't conform to a format of COMnnn - If the required port name is of the form COMnnn then Serial.Port=nnn and Serial.PortName="COMnnn" are - equivalent. - - - - Returns a list of all available ASCOM serial ports with COMnnn ports sorted into ascending port number order - - String array of available serial ports - A string array of available serial ports - Update in platform 6.0.0.0 This call uses the .NET Framework to retrieve available - COM ports and this has been found not to return names of some USB serial adapters. Additional - code has been added to attempt to open all COM ports up to COM32. Any ports that can be - successfully opened are now returned alongside the ports returned by the .NET call. - If this new approach still does not detect a COM port it can be forced to appear in the list by adding its name - as a string entry in the ForceCOMPorts key of the ASCOM Profile. In the event that this scanning causes issues, a COM port can be - omitted from the scan by adding its name as a string entry in the IgnoreCOMPorts key of the ASCOM Profile. - - - - Adds a message to the ASCOM serial trace file - - String identifying the module logging the message - Message text to be logged. - - This can be called regardless of whether logging is enabled - - - - - Translates a supplied string into hex characters - - The string to convert - A string with each character represented as [xx] - - - - - OS level blocking wait for an event - - The triggering even't handle - Length of time to wait before timing out - Status, 0 = success - - - - - Sleep the calling thread until the worker thread has completed - - ThreadData class holding required inputs, outputs and thread management information - - - - - Worker thread data - - - - - - Initialises a new ThreadData synchronisation object - - - - - - Signals that this thread has completed its work - - - - - - Provides a repeating timer with associated tick event. - - - The interval resolution is about 20ms.If you need beter than this, you could use the WaitForMilliseconds - method to create your own solution. - You can create multiple instances of this object. When enabled, the Timer delivers Tick events periodically - (determined by setting the Interval property). - This component is now considered obsolete for use in .NET clients and drivers. It is reliable under almost - all circumstances but there are some environments, noteably console and some scripted applications, where it fails to fire. - The Platform 6 component improves performance over the Platform 5 component in this respect and can be further tuned - for particular applications by placing an entry in the ForceSystemTimer Profile key. - For .NET applications, use of System.Timers.Timer is recommended but atention must be paid to getting threading correct - when using this control. The Windows.Forms.Timer control is not an improvement over the ASCOM timer which is based upon it. - Developers using non .NET languages are advised to use timers provided as part of their development environment, only falling - back to the ASCOM Timer if no viable alternative can be found. - - - - - Timer tick event handler - - - - - - Fired once per Interval when timer is Enabled. - - To sink this event in Visual Basic, declare the object variable using the WithEvents keyword. - - - - Create a new timer component - - - - - - Disposes of resources used by the profile object - called by IDisposable interface - - - - - - - Disposes of resources used by the profile object - - - - - - The interval between Tick events when the timer is Enabled in milliseconds, (default = 1000) - - The interval between Tick events when the timer is Enabled (milliseconds, default = 1000) - The interval between Tick events when the timer is Enabled in milliseconds - - - - - Enable the timer tick events - - True means the timer is active and will deliver Tick events every Interval milliseconds. - Enabled state of timer tick events - - - - - Timer event handler - - Raises the Tick event - - - - Creates a log file for a driver or application. Uses a similar file name and internal format to the serial logger. Multiple logs can be created simultaneously if needed. - - -In automatic mode the file will be stored in an ASCOM folder within XP's My Documents folder or equivalent places - in other operating systems. Within the ASCOM folder will be a folder named Logs yyyy-mm-dd where yyyy, mm and dd are - today's year, month and day numbers. The trace file will appear within the day folder with the name - ASCOM.Identifier.hhmm.ssffff where hh, mm, ss and ffff are the current hour, minute, second and fraction of second - numbers at the time of file creation. - - Within the file the format of each line is hh:mm:ss.fff Identifier Message where hh, mm, ss and fff are the hour, minute, second - and fractional second at the time that the message was logged, Identifier is the supplied identifier (usually the subroutine, - function, property or method from which the message is sent) and Message is the message to be logged. - - - - - Creates a new TraceLogger instance - - The LogFileType is used in the file name to allow you to quickly identify which of - several logs contains the information of interest. - This call enables automatic logging and sets the filetype to "Default". - - - - Creates a new TraceLogger instance and initialises filename and type - - Fully qualified trace file name or null string to use automatic file naming (recommended) - String identifying the type of log e,g, Focuser, LX200, GEMINI, MoonLite, G11 - The LogFileType is used in the file name to allow you to quickly identify which of several logs contains the information of interest. - - - - Create and enable a new TraceLogger instance with automatic naming based on the supplied log file type - - String identifying the type of log e,g, Focuser, LX200, GEMINI, MoonLite, G11 - The LogFileType is used in the file name to allow you to quickly identify which of several logs contains the information of interest. - - - - Disposes of the TraceLogger object - - True if being disposed by the application, False if disposed by the finalizer. - - - - - Disposes of the TraceLogger object - - - - - - Finalizes the TraceLogger object - - - - - - Logs an issue, closing any open line and opening a continuation line if necessary after the - issue message. - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - Use this for reporting issues that you don't want to appear on a line already opened - with StartLine - - - - Insert a blank line into the log file - - - - - - Logs a complete message in one call, including a hex translation of the message - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - True to append a hex translation of the message at the end of the message - - Use this for straightforward logging requrements. Writes all information in one command. - Will create a LOGISSUE message in the log if called before a line started by LogStart has been closed with LogFinish. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Displays a message respecting carriage return and linefeed characters - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - The final message to terminate the line - - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Writes the time and identifier to the log, leaving the line ready for further content through LogContinue and LogFinish - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - Use this to start a log line where you want to write further information on the line at a later time. - E.g. You might want to use this to record that an action has started and then append the word OK if all went well. - You would then end up with just one line to record the whole transaction even though you didn't know that it would be - successful when you started. If you just used LogMsg you would have ended up with two log lines, one showing - the start of the transaction and the next the outcome. - Will create a LOGISSUE message in the log if called before a line started by LogStart has been closed with LogFinish. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Appends further message to a line started by LogStart, appends a hex translation of the message to the line, does not terminate the line. - - The additional message to appear in the line - True to append a hex translation of the message at the end of the message - - This can be called multiple times to build up a complex log line if required. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Closes a line started by LogStart with the supplied message and a hex translation of the message - - The final message to terminate the line - True to append a hex translation of the message at the end of the message - - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - - - - - Enables or disables logging to the file. - - True to enable logging - Boolean, current logging status (enabled/disabled). - If this property is false then calls to LogMsg, LogStart, LogContinue and LogFinish do nothing. If True, - supplied messages are written to the log file. - - - - Sets the log filename and type if the constructor is called without parameters - - Fully qualified trace file name or null string to use automatic file naming (recommended) - String identifying the type of log e,g, Focuser, LX200, GEMINI, MoonLite, G11 - The LogFileType is used in the file name to allow you to quickly identify which of several logs contains the - information of interest. - Note This command is only required if the tracelogger constructor is called with no - parameters. It is provided for use in COM clients that can not call constructors with parameters. - If you are writing a COM client then create the trace logger as: - - TL = New TraceLogger() - TL.SetLogFile("","TraceName") - - If you are writing a .NET client then you can achieve the same end in one call: - - TL = New TraceLogger("",TraceName") - - - - - - Return the full filename of the log file being created - - Full filename of the log file - String filename - This call will return an empty string until the first line has been written to the log file - as the file is not created until required. - - - - Set or return the path to a directory in which the log file will be created - - String path - Introduced with Platform 6.4.If set, this path will be used instead of the the user's Documents directory default path. This must be Set before the first message Is logged. - - - - Set or return the width of the identifier field in the log message - - Width of the identifier field - Integer width - Introduced with Platform 6.4.If set, this width will be used instead of the default identifier field width. - - - - Logs a complete message in one call - - Identifies the meaning of the the message e.g. name of modeule or method logging the message. - Message to log - - Use this for straightforward logging requrements. Writes all information in one command. - Will create a LOGISSUE message in the log if called before a line started by LogStart has been closed with LogFinish. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogMessage(ByVal Identifier As String, ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Appends further message to a line started by LogStart, does not terminate the line. - - The additional message to appear in the line - - This can be called multiple times to build up a complex log line if required. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogContinue(ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Closes a line started by LogStart with the supplied message - - The final message to terminate the line - - Can only be called once for each line started by LogStart. - Will create a LOGISSUE message in the log if called before a line has been started with LogStart. - Posible reasons for this are exceptions causing the normal flow of code to be bypassed or logic errors. - This overload is not available through COM, please use - "LogFinish(ByVal Message As String, ByVal HexDump As Boolean)" - with HexDump set False to achieve this effect. - - - - - Provides a set of utility functions for ASCOM clients and drivers - - - - - - Disposes of resources used by the profile object - called by IDisposable interface - - - - - - - Disposes of resources used by the profile object - - - - - - Pauses for a given interval in milliseconds. - - The number of milliseconds to wait - Repeatedly puts the calling Win32 process to sleep, totally freezing it, for 10 milliseconds, - then pumps events so the script or program calling it will receive its normal flow of events, until the - pause interval elapses. If the pause interval is 20 milliseconds or less, the sleep interval is reduced - to 0, causing the calling Win32 process to give up control to the kernel scheduler and then immediately - become eligible for scheduling. - - - - Convert sexagesimal degrees to binary double-precision degrees - - The sexagesimal input string (degrees) - The double-precision binary value (degrees) represented by the sexagesimal input - The sexagesimal to real conversion methods such as this one are flexible enough to convert just - about anything that resembles sexagesimal. Thee way they operate is to first separate the input string - into numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. Of course it - would not be normal (for example) for both the minutes and seconds parts to have fractional parts, but it - would be legal. So 00:30.5:30 would convert to 1.0 unit. - Note that plain units, for example 23.128734523 are acceptable to the method. - - - - - Convert sexagesimal hours to binary double-precision hours - - The sexagesimal input string (hours) - The double-precision binary value (hours) represented by the sexagesimal input - - The sexagesimal to real conversion methods such as this one are flexible enough to convert just about - anything that resembles sexagesimal. Thee way they operate is to first separate the input string into - numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. - - Of course it would not be normal (for example) for both the minutes and seconds parts to have - fractional parts, but it would be legal. So 00:30.5:30 would convert to 1.0 unit. Note that plain units, - for example 23.128734523 are acceptable to the method. - - - - - Convert sexagesimal hours to binary double-precision hours - - The sexagesimal input string (hours) - The double-precision binary value (hours) represented by the sexagesimal input - - The sexagesimal to real conversion methods such as this one are flexible enough to convert just about - anything that resembles sexagesimal. Thee way they operate is to first separate the input string into - numeric "tokens", strings consisting only of the numerals 0-9, plus and minus, and period. All other - characters are considered delimiters. Once the input string is parsed into tokens they are converted to - numerics. - - If there are more than three numeric tokens, only the first three are considered, the remainder - are ignored. Left to right positionally, the tokens are assumed to represent units (degrees or hours), - minutes, and seconds. If only two tokens are present, they are assumed to be units and minutes, and if - only one token is present, it is assumed to be units. Any token can have a fractionsl part. - - Of course it would not be normal (for example) for both the minutes and seconds parts to have - fractional parts, but it would be legal. So 00:30.5:30 would convert to 1.0 unit. Note that plain units, - for example 23.128734523 are acceptable to the method. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with default delimiters DD° MM' SS" - - The degrees value to convert - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with with default minute and second delimiters MM' SS" - - The degrees value to convert - The delimiter string separating degrees and minutes - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with default second delimiter SS" - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - The delimiter string to append to the seconds part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - This overload is not available through COM, please use - "DegreesToDMS(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal SecDelim As String)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees, minutes and seconds with specified second decimal places - - The degrees value to convert - The delimiter string separating degrees and minutes - The delimiter string to append to the minutes part - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of degrees input value, degrees, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single - characters. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default delimiters HH:MM:SS - - The hours value to convert - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default minutes and seconds delimters MM:SS - - The hours value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with default second delimiter of null string - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHMS(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours, minutes, and seconds with specified number of second decimal places - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of hours input value, hours, minutes and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with default delimters of HH:MM:SS - - The degrees value to convert - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the default second and minute delimiters of MM:SS - - The degrees value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the default second delimiter SS (null string) - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToHMS(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal SecDelim As String, ByVal SecDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours, minutes, and seconds with the specified number of second decimal places - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string separating minutes and seconds - The delimiter string to append to the seconds part - The number of digits after the decimal point on the seconds part - Sexagesimal representation of degrees input value, as hours, minutes, and seconds - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal degrees and minutes with default delimiters DD° MM' - - The degrees value to convert - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes with the default minutes delimeter MM' - - The degrees value to convert - The delimiter string separating degrees - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes - - The degrees value to convert - The delimiter string separating degrees - The delimiter string to append to the minutes - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "DegreesToDM(ByVal Degrees As Double, ByVal DegDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal degrees and minutes with the specified number of minute decimal places - - The degrees value to convert - The delimiter string separating degrees - The delimiter string to append to the minutes - The number of digits after the decimal point on the minutes part - Sexagesimal representation of degrees input value, as degrees and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert hours to sexagesimal hours and minutes with default delimiters HH:MM - - The hours value to convert - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes with default minutes delimiter MM (null string) - - The hours value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes - - The hours value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - This overload is not available through COM, please use - "HoursToHM(ByVal Hours As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with an suitable parameters to achieve this effect. - - - - - Convert hours to sexagesimal hours and minutes with supplied number of minute decimal places - - The hours value to convert - The delimiter string separating hours - The delimiter string to append to the minutes part - The number of digits after the decimal point on the minutes part - Sexagesimal representation of hours input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters. - - - - - Convert degrees to sexagesimal hours and minutes with default delimiters HH:MM - - The degrees value to convert - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes with default minute delimiter MM (null string) - - The degrees value to convert - The delimiter string separating hours and minutes - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - This overload is not available through COM, please use - "DegreesToHM(ByVal Degrees As Double, ByVal HrsDelim As String, ByVal MinDelim As String, ByVal MinDecimalDigits As Integer)" - with suitable parameters to achieve this effect. - - - - - Convert degrees to sexagesimal hours and minutes with supplied number of minute decimal places - - The degrees value to convert - The delimiter string separating hours and minutes - The delimiter string to append to the minutes part - Number of minutes decimal places - Sexagesimal representation of degrees input value as hours and minutes - - If you need a leading plus sign, you must prepend it yourself. The delimiters are not restricted to single characters - - - - - Current Platform version in Major.Minor form - - Current Platform version in Major.Minor form - Please be careful if you wish to convert this string into a number within your application - because the ASCOM Platform is used internationally and some countries use characters other - than point as the decimal separator. - If your application tries to convert 5.5 into a Double value when running on a PC localised to - France, you will get an exception because the French decimal separater is comma and 5.5 is not - a valid representation of a decimal number in that locale. - If you still wish to turn the Platform Version into a Double value, you can use an - approach such as this: - If Double.Parse(Util.PlatformVersion, CultureInfo.InvariantCulture) < 5.5 Then... - If you just wish to test whether the platform is greater than a particular level, - you can use the IsMinimumRequiredVersion method. - - - - - Tests whether the current platform version is at least equal to the supplied major and minor - version numbers, returns false if this is not the case - - The required major version number - The required minor version number - True if the current platform version equals or exceeds the major and minor values provided - This function provides a simple way to test for a minimum platform level. - If for example, your application requires at least platform version 5.5 then you can use - code such as this to make a test and display information as appropriate. - Const requiredMajorVersion as Integer = 5 - Const requiredMinorVersion as Integer = 5 ' Requires Platform version 5.5 - Dim Utils as New ASCOM.Utilities.Util - isOK = Utils.IsMinimumRequiredVersion(requiredMajorVersion, requiredMinorVersion) - If Not isOK Then - ' Abort, throw exception, print an error or whatever. - End - EndIf - - - - - - Change the serial trace file (default C:\SerialTrace.txt) - - Serial trace file name including fully qualified path e.g. C:\SerialTrace.txt - Serial trace file name - Change this before setting the SerialTrace property to True. - - - - Enable/disable serial I/O tracing - - Boolean - Enable/disable serial I/O tracing - Enabled - disabled state of serial tracing - If you want to change the serial trace file path, change the SerialTraceFile property before setting this to True. - After setting this to True, serial trace info will be written to the last-set serial trace file. - - - - The name of the computer's time zone - - The name of the computer's time zone - This will be in the local language of the operating system, and will reflect any daylight/summer time that may be in - effect. - - - - UTC offset (hours) for the computer's clock - - UTC offset (hours) for the computer's clock - The offset is in hours, such that UTC = local + offset. The offset includes any daylight/summer time that may be - in effect. - - - - The current UTC Date - - The current UTC Date - - - - - Current Julian date - - Current Julian date - This is quantised to the second in the COM component but to a small decimal fraction in the .NET component - - - - Convert local-time Date to Julian date - - Date in local-time - Julian date - Julian dates are always in UTC - - - - Convert Julian date to local-time Date - - Julian date to convert - Date in local-time for the given Julian date - Julian dates are always in UTC - - - - Convert UTC Date to Julian date - - UTC date to convert - Julian date - Julian dates are always in UTC - - - - Convert Julian date to UTC Date - - Julian date - Date in UTC for the given Julian date - Julian dates are always in UTC - - - - Convert UTC Date to local-time Date - - Date in UTC - Date in local-time - - - - - Convert local-time Date to UTC Date - - Date in local-time - Date in UTC - - - - - Convert a string safearray to an ArrayList that can be used in scripting languages - - Array of strings - Collection of integers - - - - - Convert an integer safearray to an ArrayList collection that can be used in scripting languages - - Safearray of integers - Colection of integers - - - - - Convert from one set of speed / temperature / pressure rain rate units to another - - Value to convert - Integer value from the Units enum indicating the value's current units - Integer value from the Units enum indicating the units to which the input value should be converted - Input value expressed in the new units - When the specified from and to units can not refer to the same value. e.g. attempting to convert miles per hour to degrees Celsius - - Conversions available: - - metres per second <==> miles per hour <==> knots - Celsius <==> Farenheit <==> Kelvin - hecto Pascals (hPa) <==> milli bar(mbar) <==> mm of mercury <==> inches of mercury - mm per hour <==> inches per hour - - Knots conversions use the international nautical mile definition (1 nautical mile = 1852m) rather than the orginal UK or US Admiralty definitions. - For convenience, milli bar and hecto Pascals are shown as separate units even though they have numerically identical values and there is a 1:1 conversion between them. - - - - - Calculate the dew point (°Celsius) given the ambient temperature (°Celsius) and relative humidity (%) - - Relative humidity expressed in percent (0.0 .. 100.0) - Ambient temperature (°Celsius) - Dew point (°Celsius) - When relative humidity < 0.0% or > 100.0%> - When ambient temperature < absolute zero or > 100.0C> - 'Calculation uses Vaisala formula for water vapour saturation pressure and is accurate to 0.083% over -20C - +50°C - http://www.vaisala.com/Vaisala%20Documents/Application%20notes/Humidity_Conversion_Formulas_B210973EN-F.pdf - - - - - Calculate the relative humidity (%) given the ambient temperature (°Celsius) and dew point (°Celsius) - - Dewpoint in (°Celsius) - Ambient temperature (°Celsius) - Humidity expressed in percent (0.0 .. 100.0) - When dew point < absolute zero or > 100.0C> - When ambient temperature < absolute zero or > 100.0C> - 'Calculation uses the Vaisala formula for water vapour saturation pressure and is accurate to 0.083% over -20C - +50°C - http://www.vaisala.com/Vaisala%20Documents/Application%20notes/Humidity_Conversion_Formulas_B210973EN-F.pdf - - - - - Convert atmospheric pressure from one altitude above mean sea level to another - - Measured pressure in hPa (mBar) at the "From" altitude - "Altitude at which the input pressure was measured (metres) - Altitude to which the pressure is to be converted (metres) - Pressure in hPa at the "To" altitude - Uses the equation: p = p0 * (1.0 - 2.25577E-05 h)^5.25588 - - - - Convert an array of .NET built-in types to an equivalent Variant arrray (array of .NET Objects) - - The array to convert to variant types - A Variant array - If the supplied array contains elements of an unsuported Type. - If the array rank is outside the range 1 to 5. - If the supplied object is not an array. - This function will primarily be of use to Scripting Language programmers who need to convert Camera and Video ImageArrays from their native types to Variant types. If this is not done, - the scripting language will throw a type mismatch exception when it receives, for example, Int32 element types instead of the expected Variant types. - A VBScript Camera usage example is: Image = UTIL.ArrayToVariantArray(CAMERA.ImageArray) This example assumes that the camera and utilities objects have already been created with CreateObject statements. - The supported .NET types are: - - Int16 - Int32 - UInt16 - UInt32 - UInt64 - Byte - SByte - Single - Double - Boolean - DateTime - String - - - The function supports arrays with 1 to 5 dimensions (Rank = 1 to 5). If the supplied array already contains elements of Variant type, it is returned as-is without any processing. - - - - Turns an array of type T into a variant array of Object - - The type to convert to Variant - The supplied array of Type T as an Object - The supplied array of Type T as an Array - The array with all elements represented as Variant objects - Works for 1 to 5 dimensional arrays of any Type - - - - Platform major version number - - Platform major version number - Integer version number - - - - - Platform minor version number - - Platform minor version number - Integer version number - - - - - Platform service pack number - - Platform service pack number - Integer service pack number - - - - - Platform build number - - Platform build number - Integer build number - - - - - Function that is called by RegAsm when the assembly is registered for COM - - This is necessary to ensure that the mscoree.dll can be found when the SetSearchDirectories function has been called in an application e.g. by Inno installer post v5.5.9 - - - - Function that is called by RegAsm when the assembly is registered for COM - - -
    -
    diff --git a/MeadeAutostar497/obj/Debug/ASCOM.MeadeAutostar497.Properties.Resources.resources b/MeadeAutostar497/obj/Debug/ASCOM.MeadeAutostar497.Properties.Resources.resources deleted file mode 100644 index a83256eb806952890a5de991f314230cb9ab0382..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128640 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 diff --git a/MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.CopyComplete b/MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.CopyComplete deleted file mode 100644 index e69de29..0000000 diff --git a/MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.FileListAbsolute.txt b/MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.FileListAbsolute.txt deleted file mode 100644 index 7a0d159..0000000 --- a/MeadeAutostar497/obj/Debug/MeadeAutostar497.csproj.FileListAbsolute.txt +++ /dev/null @@ -1,29 +0,0 @@ -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.MeadeAutostar497.Telescope.dll.config -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.MeadeAutostar497.Telescope.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.MeadeAutostar497.Telescope.pdb -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.MeadeAutostar497.Telescope.tlb -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Astrometry.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Attributes.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Controls.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.DeviceInterfaces.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Exceptions.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.SettingsProvider.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Utilities.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Utilities.Video.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Internal.Extensions.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Astrometry.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Attributes.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Controls.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.DeviceInterfaces.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Exceptions.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.SettingsProvider.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Utilities.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\bin\Debug\ASCOM.Internal.Extensions.xml -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\ASCOM.MeadeAutostar497.Properties.Resources.resources -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\ASCOM.MeadeAutostar497.SetupDialogForm.resources -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\MeadeAutostar497.csproj.GenerateResource.cache -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\MeadeAutostar497.csproj.CoreCompileInputs.cache -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\MeadeAutostar497.csproj.CopyComplete -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\ASCOM.MeadeAutostar497.Telescope.dll -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\ASCOM.MeadeAutostar497.Telescope.pdb -D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\obj\Debug\MeadeAutostar497.csprojAssemblyReference.cache From a742867377fbdb66e4f3be35e702dc322dd8193b Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 27 Apr 2019 00:41:06 +0100 Subject: [PATCH 002/109] Adding git ignore file --- .gitignore | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6553964 --- /dev/null +++ b/.gitignore @@ -0,0 +1,221 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# nCrunch items +*.ncrunchsolution +*.DotSettings +*.ncrunchproject From da6b7ec55f1e733023c49266c2b568cee883084b Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 29 Apr 2019 00:06:56 +0100 Subject: [PATCH 003/109] Started working on getting the basic communications with the scope working. Working on routines to get and set the date and time in the handbox. --- .../BootstrapAscomProfileStore.ps1 | 36 +++++ .../MeadeAutostar497.UnitTests.csproj | 125 +++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++ .../TelescopeControllerUnitTests.cs | 151 ++++++++++++++++++ MeadeAutostar497.UnitTests/packages.config | 9 ++ MeadeAutostar497.sln | 24 +++ MeadeAutostar497/AscomClasses/Telescope.cs | 20 ++- .../Controller/ITelescopeController.cs | 5 +- .../Controller/TelescopeController.cs | 131 +++++++++++++-- MeadeAutostar497/MeadeAutostar497.csproj | 17 +- MeadeAutostar497/Properties/AssemblyInfo.cs | 10 +- .../Properties/Resources.Designer.cs | 61 +++---- .../Properties/Settings.Designer.cs | 24 ++- MeadeAutostar497/StringExtensions.cs | 16 ++ MeadeAutostar497/app.config | 2 +- TestConsole/Program.cs | 55 +++++++ TestConsole/Properties/AssemblyInfo.cs | 36 +++++ TestConsole/TestConsole.csproj | 64 ++++++++ TestConsole/app.config | 3 + 19 files changed, 746 insertions(+), 79 deletions(-) create mode 100644 MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 create mode 100644 MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj create mode 100644 MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs create mode 100644 MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs create mode 100644 MeadeAutostar497.UnitTests/packages.config create mode 100644 MeadeAutostar497/StringExtensions.cs create mode 100644 TestConsole/Program.cs create mode 100644 TestConsole/Properties/AssemblyInfo.cs create mode 100644 TestConsole/TestConsole.csproj create mode 100644 TestConsole/app.config diff --git a/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 b/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 new file mode 100644 index 0000000..213c64d --- /dev/null +++ b/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 @@ -0,0 +1,36 @@ +<# +This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work +without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, +it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on +ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. + +NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. +#> + +$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node +if ($wow) + { + $root = "HKLM:\SOFTWARE\Wow6432Node" + } +else + { + $root = "HKLM:\SOFTWARE" + } +$ascomRoot = $root + "\ASCOM" + +if (Test-Path $ascomRoot) + { + <# Don't upset an already-existing ASCOM registry #> + exit + } + +<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> +New-Item -Path $root -Name ASCOM –Force +$ascomAcl = Get-Acl $ascomRoot +$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") +$ascomAcl.SetAccessRule($aclRule) +$ascomAcl | Set-Acl -Path $ascomRoot + +<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> +New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force +New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj new file mode 100644 index 0000000..e49ccdc --- /dev/null +++ b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj @@ -0,0 +1,125 @@ + + + + + + Debug + AnyCPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F} + Library + Properties + MeadeAutostar497.UnitTests + MeadeAutostar497.UnitTests + v4.6.2 + 512 + true + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll + + + ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll + + + ..\packages\Moq.4.10.1\lib\net45\Moq.dll + + + ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll + + + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + + + + {64308775-bd4a-469c-bcab-3ed830b811af} + MeadeAutostar497 + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs b/MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ef108f2 --- /dev/null +++ b/MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MeadeAutostar497.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MeadeAutostar497.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9638da27-77c7-4b30-a730-6e7159a4a09f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs new file mode 100644 index 0000000..247c1b8 --- /dev/null +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using ASCOM; +using ASCOM.MeadeAutostar497.Controller; +using ASCOM.Utilities; +using ASCOM.Utilities.Interfaces; +using Moq; +using NUnit.Framework; + +namespace MeadeAutostar497.UnitTests +{ + [TestFixture] + public class TelescopeControllerUnitTests + { + private Mock serialMock; + + private readonly List _availableComPorts = new List { "COM1", "COM2", "COM3" }; + private TelescopeController _telescopeController; + + private string transmittedString; + private string stringToRecieve; + + [SetUp] + public void Setup() + { + transmittedString = string.Empty; + stringToRecieve = string.Empty; + + serialMock = new Mock(); + serialMock.SetupAllProperties(); + + serialMock.Setup(x => x.AvailableComPorts).Returns( () => _availableComPorts.ToArray()); + serialMock.Setup(X => X.Transmit(It.IsAny())).Callback(str => { transmittedString = str; }); + serialMock.Setup(X => X.Receive()).Returns(() => stringToRecieve); + + _telescopeController = TelescopeController.Instance; + _telescopeController.SerialPort = serialMock.Object; + } + + [TearDown] + public void TearDown() + { + _telescopeController.Connected = false; + _telescopeController.Port = "COM1"; + } + + [Test] + public void ImplementsExpectedInterfaces() + { + Assert.That(_telescopeController, Is.Not.Null); + Assert.That(_telescopeController, Is.AssignableTo()); + } + + [Test] + public void NotConnectedByDefault() + { + Assert.That(_telescopeController.Connected, Is.False); + } + + [Test] + public void ConnectedCanBeSetTrue() + { + stringToRecieve = "test#"; + + _telescopeController.Connected = true; + Assert.That(_telescopeController.Connected, Is.True); + } + + [Test] + public void EnsureThatTheSerialCommunicationsAreSetCorrectly() + { + Assert.That(serialMock.Object.Connected, Is.False); + + stringToRecieve = "test#"; + + _telescopeController.Connected = true; + Assert.That(_telescopeController.Connected, Is.True); + + Assert.That(serialMock.Object.DTREnable, Is.False); + Assert.That(serialMock.Object.RTSEnable, Is.False); + Assert.That(serialMock.Object.Speed, Is.EqualTo(SerialSpeed.ps9600)); + Assert.That(serialMock.Object.DataBits, Is.EqualTo(8)); + Assert.That(serialMock.Object.StopBits, Is.EqualTo(SerialStopBits.One)); + Assert.That(serialMock.Object.Parity, Is.EqualTo(SerialParity.None)); + Assert.That(serialMock.Object.PortName, Is.EqualTo(_telescopeController.Port)); + Assert.That(serialMock.Object.Connected, Is.True); + } + + [Test] + public void WhenOpensComPortToNonAutostarThrowException() + { + Assert.That(serialMock.Object.Connected, Is.False); + var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to communicate with telescope.")); + + Assert.That(_telescopeController.Connected, Is.False); + } + + [Test] + public void CannotChangeSerialPortObjectWhenConnected() + { + stringToRecieve = "test#"; + + _telescopeController.Connected = true; + + Mock newSerialMock = new Mock(); + + var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); + + Assert.That(exception, Is.Not.Null); + Assert.That(exception.Message, Is.EqualTo("Please disconnect before changing the serial engine.")); + } + + [Test] + public void PortIsSetToCom1ByDefault() + { + Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); + } + + [Test] + public void SettingPortToValidPortAllowed() + { + _telescopeController.Port = "COM2"; + + Assert.That(_telescopeController.Port, Is.EqualTo("COM2")); + } + + [Test] + public void SettingPortToValidPortWhenConnectedFails() + { + stringToRecieve = "test#"; + + _telescopeController.Connected = true; + var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); + + Assert.That(exception.Message, Is.EqualTo("Please disconnect from the scope before changing port.")); + + Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); //port hasn't changed + } + + [Test] + public void SettingPortToInavalidPortFails() + { + var exception = Assert.Throws(() => _telescopeController.Port = "COM5"); + + Assert.That(exception.Message, Is.EqualTo("Unable to select port COM5 as it does not exist.")); + + Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); //port hasn't changed + } + } +} diff --git a/MeadeAutostar497.UnitTests/packages.config b/MeadeAutostar497.UnitTests/packages.config new file mode 100644 index 0000000..e7172db --- /dev/null +++ b/MeadeAutostar497.UnitTests/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/MeadeAutostar497.sln b/MeadeAutostar497.sln index d98a188..69570e9 100644 --- a/MeadeAutostar497.sln +++ b/MeadeAutostar497.sln @@ -5,16 +5,40 @@ VisualStudioVersion = 15.0.28307.136 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeadeAutostar497", "MeadeAutostar497\MeadeAutostar497.csproj", "{64308775-BD4A-469C-BCAB-3ED830B811AF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeadeAutostar497.UnitTests", "MeadeAutostar497.UnitTests\MeadeAutostar497.UnitTests.csproj", "{9638DA27-77C7-4B30-A730-6E7159A4A09F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsole", "TestConsole\TestConsole.csproj", "{D5207217-61C7-4E94-8097-91DBACE57D2A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|x86.ActiveCfg = Debug|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|x86.Build.0 = Debug|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|Any CPU.Build.0 = Release|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|x86.ActiveCfg = Release|Any CPU + {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|x86.Build.0 = Release|Any CPU + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.ActiveCfg = Release|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index e7e60c2..264f601 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -73,7 +73,7 @@ namespace ASCOM.MeadeAutostar497 /// /// Driver description that displays in the ASCOM Chooser. /// - private static string driverDescription = "ASCOM Telescope Driver for Meade Autostar 497 based telescopes."; + private static string driverDescription = "Meade Autostar 497 .net"; internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence internal static string comPortDefault = "COM1"; @@ -221,6 +221,7 @@ namespace ASCOM.MeadeAutostar497 if (value) { LogMessage("Connected Set", "Connecting to port {0}", comPort); + _telescopeController.Port = comPort; _telescopeController.Connected = true; } else @@ -810,8 +811,10 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("Slewing Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Slewing", false); + tl.LogMessage("Slewing Get", "Started"); + var result = _telescopeController.Slewing; + tl.LogMessage("Slewing Get", $"Result = {result}"); + return result; } } @@ -908,14 +911,17 @@ namespace ASCOM.MeadeAutostar497 { get { - DateTime utcDate = DateTime.UtcNow; - tl.LogMessage("TrackingRates", "Get - " + Format("MM/dd/yy HH:mm:ss", utcDate)); + tl.LogMessage("UTCDate", "Get started"); + + var utcDate = _telescopeController.utcDate; + tl.LogMessage("UTCDate", "Get - " + Format("MM/dd/yy HH:mm:ss", utcDate)); return utcDate; } set { - tl.LogMessage("UTCDate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("UTCDate", true); + tl.LogMessage("UTCDate", "Set - " + Format("MM/dd/yy HH:mm:ss", value)); + _telescopeController.utcDate = value; + } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 2cbea84..6663772 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -1,4 +1,5 @@ -using ASCOM.Utilities.Interfaces; +using System; +using ASCOM.Utilities.Interfaces; namespace ASCOM.MeadeAutostar497.Controller { @@ -9,5 +10,7 @@ namespace ASCOM.MeadeAutostar497.Controller bool Connected { get; set; } string CommandString(string command, bool raw); + bool Slewing { get; } + DateTime utcDate { get; set; } } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 891111d..fe6dc4c 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,4 +1,8 @@ using System; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading; using ASCOM.Utilities; using ASCOM.Utilities.Interfaces; @@ -10,6 +14,8 @@ namespace ASCOM.MeadeAutostar497.Controller public static TelescopeController Instance => lazy.Value; + private Mutex serialMutex = new Mutex(); + private ISerial _serialPort; public ISerial SerialPort { @@ -22,7 +28,7 @@ namespace ASCOM.MeadeAutostar497.Controller if (_serialPort != null) { if (_serialPort.Connected) - throw new InvalidOperationException("Please disconnect before changing the port."); + throw new InvalidOperationException("Please disconnect before changing the serial engine."); } _serialPort = value; @@ -40,10 +46,18 @@ namespace ASCOM.MeadeAutostar497.Controller if (Connected) throw new InvalidOperationException("Please disconnect from the scope before changing port."); + if (!ValidPort(value)) + throw new InvalidOperationException($"Unable to select port {value} as it does not exist."); + _port = value; } } + private bool ValidPort(string value) + { + return SerialPort.AvailableComPorts.Contains(value); + } + public bool Connected { get => SerialPort.Connected; @@ -55,16 +69,24 @@ namespace ASCOM.MeadeAutostar497.Controller if (value) { //Connecting - SerialPort.DTREnable = false; - SerialPort.RTSEnable = false; - SerialPort.Speed = SerialSpeed.ps9600; - SerialPort.DataBits = 8; - SerialPort.StopBits = SerialStopBits.One; - SerialPort.Parity = SerialParity.None; - SerialPort.PortName = Port; - SerialPort.Connected = true; + try + { + SerialPort.DTREnable = false; + SerialPort.RTSEnable = false; + SerialPort.Speed = SerialSpeed.ps9600; + SerialPort.DataBits = 8; + SerialPort.StopBits = SerialStopBits.One; + SerialPort.Parity = SerialParity.None; + SerialPort.PortName = Port; + SerialPort.Connected = true; - //todo perform test to ensure that connection has been made correctly. + TestConnectionActive(); + } + catch (Exception) + { + SerialPort.Connected = false; + throw; + } } else { @@ -74,13 +96,100 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private void TestConnectionActive() + { + var firmwareVersionNumber = CommandString("GVN"); + if (string.IsNullOrEmpty(firmwareVersionNumber)) + { + throw new InvalidOperationException("Failed to communicate with telescope."); + } + } + + public string CommandString(string command) + { + return CommandString($"#:{command}#", false); + } + public string CommandString(string command, bool raw) { // it's a good idea to put all the low level communication with the device here, // then all communication calls this function // you need something to ensure that only one command is in progress at a time + return SerialCommand(command, true); + } - throw new ASCOM.MethodNotImplementedException("CommandString"); + public bool Slewing + { + get + { + if (!Connected) return false; + + var result = CommandString("D"); + return result != string.Empty; + } + } + + public DateTime utcDate + { + get + { + string telescopeDate = CommandString("GC"); + string telescopeTime = CommandString("GL"); + + int month = telescopeDate.Substring(0, 2).ToInteger(); + int day = telescopeDate.Substring(3, 2).ToInteger(); + int year = telescopeDate.Substring(6, 2).ToInteger(); + + if (year < 2000) //This is a hack that will work until the end of the century + { + year = year + 2000; + } + + int hour = telescopeTime.Substring(0, 2).ToInteger(); + int minute = telescopeTime.Substring(3, 2).ToInteger(); + int second = telescopeTime.Substring(6, 2).ToInteger(); + + var newDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + + return newDate; + } + set + { + //var result = SerialCommand(":SLHH:MM:SS#", true); + var timeResult = SerialCommand($"#:SL{value:hh:mm:ss}#", true); + if (timeResult != "1") + { + throw new InvalidOperationException("Failed to set local time"); + } + + var dateResult = SerialCommand($"#:SC{value:MM/dd/yy}#", true); + if (dateResult.Substring(0,1) != "1") + { + throw new InvalidOperationException("Failed to set local time"); + } + } + + } + + private string SerialCommand(string command, bool expectsResult ) + { + serialMutex.WaitOne(); + try + { + SerialPort.Transmit(command); + if (expectsResult) + { + string result = SerialPort.ReceiveTerminated("#"); + + return result; + } + return string.Empty; + } + finally + { + SerialPort.ClearBuffers(); + serialMutex.ReleaseMutex(); + } } } } diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 2be7529..940afa9 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -15,7 +15,7 @@ 3.5 - v4.0 + v4.6.2 ASCOM.ico true ASCOMDriverTemplate.snk @@ -34,7 +34,8 @@ false false true - Client + + true @@ -46,6 +47,7 @@ 4 true AnyCPU + false pdbonly @@ -56,6 +58,7 @@ 4 AnyCPU false + false @@ -66,6 +69,7 @@ + @@ -74,13 +78,20 @@ + + + + + + + True diff --git a/MeadeAutostar497/Properties/AssemblyInfo.cs b/MeadeAutostar497/Properties/AssemblyInfo.cs index 848df7f..2a06abf 100644 --- a/MeadeAutostar497/Properties/AssemblyInfo.cs +++ b/MeadeAutostar497/Properties/AssemblyInfo.cs @@ -8,11 +8,11 @@ using System.Runtime.InteropServices; // // TODO - Add your authorship information here [assembly: AssemblyTitle("ASCOM.MeadeAutostar497.Telescope")] -[assembly: AssemblyDescription("ASCOM Telescope driver for MeadeAutostar497")] +[assembly: AssemblyDescription("ASCOM MeadeAutostar497 .net")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("The ASCOM Initiative")] +[assembly: AssemblyCompany("Cjdawson.com")] [assembly: AssemblyProduct("ASCOM Telescope driver for MeadeAutostar497")] -[assembly: AssemblyCopyright("Copyright © 2019 The ASCOM Initiative")] +[assembly: AssemblyCopyright("Copyright © 2019 cjdawson.com")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("6.4.0.0")] -[assembly: AssemblyFileVersion("6.4.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/MeadeAutostar497/Properties/Resources.Designer.cs b/MeadeAutostar497/Properties/Resources.Designer.cs index c18564b..9d71803 100644 --- a/MeadeAutostar497/Properties/Resources.Designer.cs +++ b/MeadeAutostar497/Properties/Resources.Designer.cs @@ -1,18 +1,17 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18052 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace ASCOM.MeadeAutostar497.Properties -{ +namespace ASCOM.MeadeAutostar497.Properties { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -20,74 +19,62 @@ namespace ASCOM.MeadeAutostar497.Properties // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - + internal class Resources { + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { + internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if (object.ReferenceEquals(resourceMan, null)) - { + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.MeadeAutostar497.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { + internal static global::System.Globalization.CultureInfo Culture { + get { return resourceCulture; } - set - { + set { resourceCulture = value; } } - + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// - internal static System.Drawing.Bitmap ASCOM - { - get - { + internal static System.Drawing.Bitmap ASCOM { + get { object obj = ResourceManager.GetObject("ASCOM", resourceCulture); return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). /// - internal static System.Drawing.Icon DefaultIcon - { - get - { + internal static System.Drawing.Icon DefaultIcon { + get { object obj = ResourceManager.GetObject("DefaultIcon", resourceCulture); return ((System.Drawing.Icon)(obj)); } diff --git a/MeadeAutostar497/Properties/Settings.Designer.cs b/MeadeAutostar497/Properties/Settings.Designer.cs index 4e629ed..a2bb372 100644 --- a/MeadeAutostar497/Properties/Settings.Designer.cs +++ b/MeadeAutostar497/Properties/Settings.Designer.cs @@ -1,28 +1,24 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18052 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ -namespace ASCOM.MeadeAutostar497.Properties -{ - - +namespace ASCOM.MeadeAutostar497.Properties { + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { + + public static Settings Default { + get { return defaultInstance; } } diff --git a/MeadeAutostar497/StringExtensions.cs b/MeadeAutostar497/StringExtensions.cs new file mode 100644 index 0000000..e6a2cd1 --- /dev/null +++ b/MeadeAutostar497/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ASCOM.MeadeAutostar497 +{ + public static class StringExtensions + { + public static int ToInteger(this string str) + { + return int.Parse(str); + } + } +} diff --git a/MeadeAutostar497/app.config b/MeadeAutostar497/app.config index e4eb090..dd30df1 100644 --- a/MeadeAutostar497/app.config +++ b/MeadeAutostar497/app.config @@ -5,4 +5,4 @@
    - + diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs new file mode 100644 index 0000000..b2ef23b --- /dev/null +++ b/TestConsole/Program.cs @@ -0,0 +1,55 @@ +// This implements a console application that can be used to test an ASCOM driver +// + +// This is used to define code in the template that is specific to one class implementation +// unused code can be deleted and this definition removed. + +#define Telescope +// remove this to bypass the code that uses the chooser to select the driver +#define UseChooser + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ASCOM +{ + class Program + { + static void Main(string[] args) + { + // Uncomment the code that's required +#if UseChooser + // choose the device + string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.MeadeAutostar497.Telescope"); + if (string.IsNullOrEmpty(id)) + return; + // create this device + ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope(id); +#else + // this can be replaced by this code, it avoids the chooser and creates the driver class directly. + ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.MeadeAutostar497.Telescope"); +#endif + // now run some tests, adding code to your driver so that the tests will pass. + // these first tests are common to all drivers. + Console.WriteLine("name " + device.Name); + Console.WriteLine("description " + device.Description); + Console.WriteLine("DriverInfo " + device.DriverInfo); + Console.WriteLine("driverVersion " + device.DriverVersion); + + // TODO add more code to test the driver. + device.Connected = true; + + //Console.WriteLine(device.Slewing); + + device.UTCDate = DateTime.UtcNow; + + Console.WriteLine(device.UTCDate); + + device.Connected = false; + Console.WriteLine("Press Enter to finish"); + Console.ReadLine(); + } + } +} diff --git a/TestConsole/Properties/AssemblyInfo.cs b/TestConsole/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..86599a1 --- /dev/null +++ b/TestConsole/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("q Test Application")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ASCOM Initiative")] +[assembly: AssemblyProduct("q")] +[assembly: AssemblyCopyright("Copyright © ASCOM Initiative 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c7008f94-e3b9-4481-b720-3b56557860c6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("6.4.0.0")] +[assembly: AssemblyFileVersion("6.4.0.0")] diff --git a/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj new file mode 100644 index 0000000..9631e67 --- /dev/null +++ b/TestConsole/TestConsole.csproj @@ -0,0 +1,64 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {D5207217-61C7-4E94-8097-91DBACE57D2A} + Exe + Properties + TestConsole + TestConsole + v4.6 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TestConsole/app.config b/TestConsole/app.config new file mode 100644 index 0000000..8935d57 --- /dev/null +++ b/TestConsole/app.config @@ -0,0 +1,3 @@ + + + From dc2a24ad25f7374ef2be3d24ca912a05260be6bd Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 29 Apr 2019 23:29:57 +0100 Subject: [PATCH 004/109] Switched the serial port over to using the .net frameworks serial port. Extracted the serial port into it's own class and created a simpler command processing mechanism. --- .../TelescopeControllerUnitTests.cs | 56 +++---- MeadeAutostar497/AscomClasses/Telescope.cs | 9 +- .../Controller/ITelescopeController.cs | 5 +- .../Controller/SerialProcessor.cs | 138 ++++++++++++++++++ .../Controller/TelescopeController.cs | 85 ++++------- MeadeAutostar497/MeadeAutostar497.csproj | 1 + 6 files changed, 204 insertions(+), 90 deletions(-) create mode 100644 MeadeAutostar497/Controller/SerialProcessor.cs diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 247c1b8..3404796 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; +using System.IO.Ports; using ASCOM; using ASCOM.MeadeAutostar497.Controller; using ASCOM.Utilities; -using ASCOM.Utilities.Interfaces; using Moq; using NUnit.Framework; @@ -11,26 +11,25 @@ namespace MeadeAutostar497.UnitTests [TestFixture] public class TelescopeControllerUnitTests { - private Mock serialMock; + private Mock serialMock; private readonly List _availableComPorts = new List { "COM1", "COM2", "COM3" }; private TelescopeController _telescopeController; - private string transmittedString; - private string stringToRecieve; + private string _stringToRecieve = string.Empty; + private bool _isConnected = false; [SetUp] public void Setup() { - transmittedString = string.Empty; - stringToRecieve = string.Empty; + _stringToRecieve = string.Empty; + _isConnected = false; - serialMock = new Mock(); + serialMock = new Mock(); serialMock.SetupAllProperties(); - - serialMock.Setup(x => x.AvailableComPorts).Returns( () => _availableComPorts.ToArray()); - serialMock.Setup(X => X.Transmit(It.IsAny())).Callback(str => { transmittedString = str; }); - serialMock.Setup(X => X.Receive()).Returns(() => stringToRecieve); + serialMock.Setup(x => x.GetPortNames()).Returns( () => _availableComPorts.ToArray()); + serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())).Returns(() => _stringToRecieve); + serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); _telescopeController = TelescopeController.Instance; _telescopeController.SerialPort = serialMock.Object; @@ -39,7 +38,6 @@ namespace MeadeAutostar497.UnitTests [TearDown] public void TearDown() { - _telescopeController.Connected = false; _telescopeController.Port = "COM1"; } @@ -59,7 +57,8 @@ namespace MeadeAutostar497.UnitTests [Test] public void ConnectedCanBeSetTrue() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; Assert.That(_telescopeController.Connected, Is.True); @@ -68,27 +67,30 @@ namespace MeadeAutostar497.UnitTests [Test] public void EnsureThatTheSerialCommunicationsAreSetCorrectly() { - Assert.That(serialMock.Object.Connected, Is.False); - - stringToRecieve = "test#"; + Assert.That(serialMock.Object.IsOpen, Is.False); + _stringToRecieve = "test#"; _telescopeController.Connected = true; + _isConnected = true; Assert.That(_telescopeController.Connected, Is.True); - Assert.That(serialMock.Object.DTREnable, Is.False); - Assert.That(serialMock.Object.RTSEnable, Is.False); - Assert.That(serialMock.Object.Speed, Is.EqualTo(SerialSpeed.ps9600)); + serialMock.Verify(x => x.Open(), Times.Once); + + Assert.That(serialMock.Object.DtrEnable, Is.False); + Assert.That(serialMock.Object.RtsEnable, Is.False); + Assert.That(serialMock.Object.BaudRate, Is.EqualTo(9600)); Assert.That(serialMock.Object.DataBits, Is.EqualTo(8)); - Assert.That(serialMock.Object.StopBits, Is.EqualTo(SerialStopBits.One)); - Assert.That(serialMock.Object.Parity, Is.EqualTo(SerialParity.None)); + Assert.That(serialMock.Object.StopBits, Is.EqualTo(StopBits.One)); + Assert.That(serialMock.Object.Parity, Is.EqualTo(Parity.None)); Assert.That(serialMock.Object.PortName, Is.EqualTo(_telescopeController.Port)); - Assert.That(serialMock.Object.Connected, Is.True); + Assert.That(serialMock.Object.IsOpen, Is.True); + } [Test] public void WhenOpensComPortToNonAutostarThrowException() { - Assert.That(serialMock.Object.Connected, Is.False); + Assert.That(serialMock.Object.IsOpen, Is.False); var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); Assert.That(exception.Message, Is.EqualTo("Failed to communicate with telescope.")); @@ -99,11 +101,12 @@ namespace MeadeAutostar497.UnitTests [Test] public void CannotChangeSerialPortObjectWhenConnected() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; - Mock newSerialMock = new Mock(); + Mock newSerialMock = new Mock(); var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); @@ -128,7 +131,8 @@ namespace MeadeAutostar497.UnitTests [Test] public void SettingPortToValidPortWhenConnectedFails() { - stringToRecieve = "test#"; + _stringToRecieve = "test#"; + _isConnected = true; _telescopeController.Connected = true; var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 264f601..a56d4d6 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -169,9 +169,9 @@ namespace ASCOM.MeadeAutostar497 { CheckConnected("CommandBlind"); // Call CommandString and return as soon as it finishes - this.CommandString(command, raw); + //this.CommandString(command, raw); // or - //throw new ASCOM.MethodNotImplementedException("CommandBlind"); + throw new ASCOM.MethodNotImplementedException("CommandBlind"); // DO NOT have both these sections! One or the other } @@ -187,8 +187,11 @@ namespace ASCOM.MeadeAutostar497 public string CommandString(string command, bool raw) { + // it's a good idea to put all the low level communication with the device here, + // then all communication calls this function + // you need something to ensure that only one command is in progress at a time CheckConnected("CommandString"); - return _telescopeController.CommandString(command, raw); + throw new ASCOM.MethodNotImplementedException("CommandString"); } public void Dispose() diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 6663772..f0bf070 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -1,15 +1,14 @@ using System; -using ASCOM.Utilities.Interfaces; +using System.IO.Ports; namespace ASCOM.MeadeAutostar497.Controller { public interface ITelescopeController { - ISerial SerialPort { get; set; } + ISerialProcessor SerialPort { get; set; } string Port { get; set; } bool Connected { get; set; } - string CommandString(string command, bool raw); bool Slewing { get; } DateTime utcDate { get; set; } } diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs new file mode 100644 index 0000000..b49619f --- /dev/null +++ b/MeadeAutostar497/Controller/SerialProcessor.cs @@ -0,0 +1,138 @@ +using System; +using System.IO.Ports; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace ASCOM.MeadeAutostar497.Controller +{ + [ComVisible(false)] + public interface ISerialProcessor + { + bool IsOpen { get; } + bool DtrEnable { get; set; } + bool RtsEnable { get; set; } + int BaudRate { get; set; } + int DataBits { get; set; } + StopBits StopBits { get; set; } + Parity Parity { get; set; } + string PortName { get; set; } + string[] GetPortNames(); + void Open(); + void Close(); + + string CommandTerminated(string command, string terminator); + char CommandChar(string command); + string ReadTerminated(string terminator); + } + + [ComVisible(false)] + public class SerialProcessor : ISerialProcessor + { + private SerialPort _serialPort = new SerialPort(); + private Mutex serialMutex = new Mutex(); + + public bool IsOpen => _serialPort.IsOpen; + + public bool DtrEnable + { + get => _serialPort.DtrEnable; + set => _serialPort.DtrEnable = value; + } + + public bool RtsEnable + { + get => _serialPort.RtsEnable; + set => _serialPort.RtsEnable = value; + } + + public int BaudRate + { + get => _serialPort.BaudRate; + set => _serialPort.BaudRate = value; + } + + public int DataBits + { + get => _serialPort.DataBits; + set => _serialPort.DataBits = value; + } + + public StopBits StopBits + { + get => _serialPort.StopBits; + set => _serialPort.StopBits = value; + } + + public Parity Parity + { + get => _serialPort.Parity; + set => _serialPort.Parity = value; + } + + public string PortName + { + get => _serialPort.PortName; + set => _serialPort.PortName = value; + } + + public string[] GetPortNames() + { + return SerialPort.GetPortNames(); + } + + public void Open() + { + _serialPort.Open(); + } + + public void Close() + { + _serialPort.Close(); + } + + public string CommandTerminated(string command, string terminator) + { + serialMutex.WaitOne(); + try + { + _serialPort.Write(command); + string result = _serialPort.ReadTo("#"); + return result; + } + finally + { + serialMutex.ReleaseMutex(); + } + } + + public char CommandChar(string command) + { + serialMutex.WaitOne(); + try + { + _serialPort.Write(command); + var result = _serialPort.ReadChar(); + return Convert.ToChar(result); + } + finally + { + serialMutex.ReleaseMutex(); + } + } + + public string ReadTerminated(string terminator) + { + serialMutex.WaitOne(); + try + { + string result = _serialPort.ReadTo("#"); + return result; + } + finally + { + serialMutex.ReleaseMutex(); + } + } + } +} diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index fe6dc4c..2367d75 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,6 +1,7 @@ using System; using System.Configuration; using System.Data; +using System.IO.Ports; using System.Linq; using System.Threading; using ASCOM.Utilities; @@ -14,12 +15,10 @@ namespace ASCOM.MeadeAutostar497.Controller public static TelescopeController Instance => lazy.Value; - private Mutex serialMutex = new Mutex(); - - private ISerial _serialPort; - public ISerial SerialPort + private ISerialProcessor _serialPort; + public ISerialProcessor SerialPort { - get => _serialPort ?? (_serialPort = new Serial()); + get => _serialPort ?? (_serialPort = new SerialProcessor()); set { if (_serialPort == value) @@ -27,7 +26,7 @@ namespace ASCOM.MeadeAutostar497.Controller if (_serialPort != null) { - if (_serialPort.Connected) + if (_serialPort.IsOpen) throw new InvalidOperationException("Please disconnect before changing the serial engine."); } @@ -55,12 +54,12 @@ namespace ASCOM.MeadeAutostar497.Controller private bool ValidPort(string value) { - return SerialPort.AvailableComPorts.Contains(value); + return SerialPort.GetPortNames().Contains(value); } public bool Connected { - get => SerialPort.Connected; + get => SerialPort.IsOpen; set { if (value == Connected) @@ -71,60 +70,48 @@ namespace ASCOM.MeadeAutostar497.Controller //Connecting try { - SerialPort.DTREnable = false; - SerialPort.RTSEnable = false; - SerialPort.Speed = SerialSpeed.ps9600; + SerialPort.DtrEnable = false; + SerialPort.RtsEnable = false; + SerialPort.BaudRate = 9600; SerialPort.DataBits = 8; - SerialPort.StopBits = SerialStopBits.One; - SerialPort.Parity = SerialParity.None; + SerialPort.StopBits = StopBits.One; + SerialPort.Parity = Parity.None; SerialPort.PortName = Port; - SerialPort.Connected = true; + SerialPort.Open(); TestConnectionActive(); } catch (Exception) { - SerialPort.Connected = false; + if (SerialPort.IsOpen) + SerialPort.Close(); throw; } } else { //Disconnecting - SerialPort.Connected = false; + SerialPort.Close(); } } } private void TestConnectionActive() { - var firmwareVersionNumber = CommandString("GVN"); + var firmwareVersionNumber = SerialPort.CommandTerminated(":GVN#", "#"); if (string.IsNullOrEmpty(firmwareVersionNumber)) { throw new InvalidOperationException("Failed to communicate with telescope."); } } - public string CommandString(string command) - { - return CommandString($"#:{command}#", false); - } - - public string CommandString(string command, bool raw) - { - // it's a good idea to put all the low level communication with the device here, - // then all communication calls this function - // you need something to ensure that only one command is in progress at a time - return SerialCommand(command, true); - } - public bool Slewing { get { if (!Connected) return false; - var result = CommandString("D"); + var result = SerialPort.CommandTerminated("#:D#", "#"); return result != string.Empty; } } @@ -133,8 +120,8 @@ namespace ASCOM.MeadeAutostar497.Controller { get { - string telescopeDate = CommandString("GC"); - string telescopeTime = CommandString("GL"); + string telescopeDate = SerialPort.CommandTerminated("#:GC#", "#"); + string telescopeTime = SerialPort.CommandTerminated("#:GL#", "#"); int month = telescopeDate.Substring(0, 2).ToInteger(); int day = telescopeDate.Substring(3, 2).ToInteger(); @@ -156,40 +143,22 @@ namespace ASCOM.MeadeAutostar497.Controller set { //var result = SerialCommand(":SLHH:MM:SS#", true); - var timeResult = SerialCommand($"#:SL{value:hh:mm:ss}#", true); - if (timeResult != "1") + var timeResult = SerialPort.CommandChar($"#:SL{value:hh:mm:ss}#"); + if (timeResult != '1') { throw new InvalidOperationException("Failed to set local time"); } - var dateResult = SerialCommand($"#:SC{value:MM/dd/yy}#", true); - if (dateResult.Substring(0,1) != "1") + var dateResult = SerialPort.CommandChar($"#:SC{value:MM/dd/yy}#"); + if (dateResult != '1') { throw new InvalidOperationException("Failed to set local time"); } + + SerialPort.ReadTerminated("#"); + SerialPort.ReadTerminated("#"); } } - - private string SerialCommand(string command, bool expectsResult ) - { - serialMutex.WaitOne(); - try - { - SerialPort.Transmit(command); - if (expectsResult) - { - string result = SerialPort.ReceiveTerminated("#"); - - return result; - } - return string.Empty; - } - finally - { - SerialPort.ClearBuffers(); - serialMutex.ReleaseMutex(); - } - } } } diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 940afa9..2640107 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -90,6 +90,7 @@ + From e339831f0c504fa0b2ab533174d9abdd11d49bac Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 29 Apr 2019 23:56:51 +0100 Subject: [PATCH 005/109] Implemented AbortSlew and did some code tidy up. --- .../TelescopeControllerUnitTests.cs | 14 +++++++- MeadeAutostar497/AscomClasses/Telescope.cs | 14 +++----- .../Controller/ISerialProcessor.cs | 26 ++++++++++++++ .../Controller/ITelescopeController.cs | 3 +- .../Controller/SerialProcessor.cs | 34 +++++++------------ .../Controller/TelescopeController.cs | 17 +++++----- MeadeAutostar497/MeadeAutostar497.csproj | 1 + 7 files changed, 68 insertions(+), 41 deletions(-) create mode 100644 MeadeAutostar497/Controller/ISerialProcessor.cs diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 3404796..9362784 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -143,7 +143,7 @@ namespace MeadeAutostar497.UnitTests } [Test] - public void SettingPortToInavalidPortFails() + public void SettingPortToInvalidPortFails() { var exception = Assert.Throws(() => _telescopeController.Port = "COM5"); @@ -151,5 +151,17 @@ namespace MeadeAutostar497.UnitTests Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); //port hasn't changed } + + [Test] + public void AbortSlewWorks() + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.AbortSlew(); + + serialMock.Verify(x => x.Command("#:Q#"), Times.Once); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index a56d4d6..bc4171d 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -27,11 +27,7 @@ #define Telescope using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; using System.Runtime.InteropServices; - using ASCOM; using ASCOM.Astrometry; using ASCOM.Astrometry.AstroUtils; @@ -293,8 +289,8 @@ namespace ASCOM.MeadeAutostar497 #region ITelescope Implementation public void AbortSlew() { - tl.LogMessage("AbortSlew", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("AbortSlew"); + tl.LogMessage("AbortSlew", "Aborting slew"); + _telescopeController.AbortSlew(); } public AlignmentModes AlignmentMode @@ -380,9 +376,9 @@ namespace ASCOM.MeadeAutostar497 tl.LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); switch (Axis) { - case TelescopeAxes.axisPrimary: return false; - case TelescopeAxes.axisSecondary: return false; - case TelescopeAxes.axisTertiary: return false; + case TelescopeAxes.axisPrimary: return true; //RA or AZ + case TelescopeAxes.axisSecondary: return true; //Dev or Alt + case TelescopeAxes.axisTertiary: return false; //rotator / derotator default: throw new InvalidValueException("CanMoveAxis", Axis.ToString(), "0 to 2"); } } diff --git a/MeadeAutostar497/Controller/ISerialProcessor.cs b/MeadeAutostar497/Controller/ISerialProcessor.cs new file mode 100644 index 0000000..5f2e2c0 --- /dev/null +++ b/MeadeAutostar497/Controller/ISerialProcessor.cs @@ -0,0 +1,26 @@ +using System.IO.Ports; +using System.Runtime.InteropServices; + +namespace ASCOM.MeadeAutostar497.Controller +{ + [ComVisible(false)] + public interface ISerialProcessor + { + bool IsOpen { get; } + bool DtrEnable { get; set; } + bool RtsEnable { get; set; } + int BaudRate { get; set; } + int DataBits { get; set; } + StopBits StopBits { get; set; } + Parity Parity { get; set; } + string PortName { get; set; } + string[] GetPortNames(); + void Open(); + void Close(); + + string CommandTerminated(string command, string terminator); + char CommandChar(string command); + string ReadTerminated(string terminator); + void Command(string command); + } +} \ No newline at end of file diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index f0bf070..d903675 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -1,15 +1,14 @@ using System; -using System.IO.Ports; namespace ASCOM.MeadeAutostar497.Controller { public interface ITelescopeController { - ISerialProcessor SerialPort { get; set; } string Port { get; set; } bool Connected { get; set; } bool Slewing { get; } DateTime utcDate { get; set; } + void AbortSlew(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs index b49619f..b9fe333 100644 --- a/MeadeAutostar497/Controller/SerialProcessor.cs +++ b/MeadeAutostar497/Controller/SerialProcessor.cs @@ -1,31 +1,10 @@ using System; using System.IO.Ports; using System.Runtime.InteropServices; -using System.Text; using System.Threading; namespace ASCOM.MeadeAutostar497.Controller { - [ComVisible(false)] - public interface ISerialProcessor - { - bool IsOpen { get; } - bool DtrEnable { get; set; } - bool RtsEnable { get; set; } - int BaudRate { get; set; } - int DataBits { get; set; } - StopBits StopBits { get; set; } - Parity Parity { get; set; } - string PortName { get; set; } - string[] GetPortNames(); - void Open(); - void Close(); - - string CommandTerminated(string command, string terminator); - char CommandChar(string command); - string ReadTerminated(string terminator); - } - [ComVisible(false)] public class SerialProcessor : ISerialProcessor { @@ -134,5 +113,18 @@ namespace ASCOM.MeadeAutostar497.Controller serialMutex.ReleaseMutex(); } } + + public void Command(string command) + { + serialMutex.WaitOne(); + try + { + _serialPort.Write(command); + } + finally + { + serialMutex.ReleaseMutex(); + } + } } } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 2367d75..a2a3f64 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,11 +1,6 @@ using System; -using System.Configuration; -using System.Data; using System.IO.Ports; using System.Linq; -using System.Threading; -using ASCOM.Utilities; -using ASCOM.Utilities.Interfaces; namespace ASCOM.MeadeAutostar497.Controller { @@ -98,7 +93,7 @@ namespace ASCOM.MeadeAutostar497.Controller private void TestConnectionActive() { - var firmwareVersionNumber = SerialPort.CommandTerminated(":GVN#", "#"); + var firmwareVersionNumber = SerialPort.CommandTerminated("#:GVN#", "#"); if (string.IsNullOrEmpty(firmwareVersionNumber)) { throw new InvalidOperationException("Failed to communicate with telescope."); @@ -155,10 +150,16 @@ namespace ASCOM.MeadeAutostar497.Controller throw new InvalidOperationException("Failed to set local time"); } - SerialPort.ReadTerminated("#"); - SerialPort.ReadTerminated("#"); + //throwing away these two strings which represent + SerialPort.ReadTerminated("#"); //Updating Planetary Data# + SerialPort.ReadTerminated("#"); // # } } + + public void AbortSlew() + { + SerialPort.Command("#:Q#"); + } } } diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 2640107..1fa4160 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -89,6 +89,7 @@ + From 90eb1c604b7d1a309535033560a34842d33dfcdd Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 30 Apr 2019 18:52:32 +0100 Subject: [PATCH 006/109] Forced all code to 64-bit only, will make this 32/64 bit before release. Fixed issue in the SerialProcessor when setting the time, makes sure that there's no chance of thread stealing when pulling out the junk messages Added ConformanceResult.txt to show the progress of the driver development --- ConformanceResult.txt | 166 ++++++++++++++++++ .../MeadeAutostar497.UnitTests.csproj | 1 + .../Controller/ISerialProcessor.cs | 2 + .../Controller/SerialProcessor.cs | 26 ++- .../Controller/TelescopeController.cs | 32 ++-- MeadeAutostar497/MeadeAutostar497.csproj | 2 +- TestConsole/TestConsole.csproj | 2 +- 7 files changed, 209 insertions(+), 22 deletions(-) create mode 100644 ConformanceResult.txt diff --git a/ConformanceResult.txt b/ConformanceResult.txt new file mode 100644 index 0000000..aaab4ff --- /dev/null +++ b/ConformanceResult.txt @@ -0,0 +1,166 @@ +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040401 +Error number for "Invalid Value 2" is: 80040405 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +18:44:58.528 Driver Access Checks OK +18:44:59.174 AccessChecks OK Successfully created driver using late binding +18:44:59.400 AccessChecks OK Successfully connected using late binding +18:44:59.405 AccessChecks INFO The driver is a .NET object +18:44:59.409 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +18:44:59.413 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +18:45:00.117 AccessChecks INFO Device does not expose interface ITelescopeV2 +18:45:00.926 AccessChecks INFO Device exposes interface ITelescopeV3 +18:45:02.245 AccessChecks OK Successfully created driver using driver access toolkit +18:45:02.415 AccessChecks OK Successfully connected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object +18:45:03.742 ConformanceCheck OK Driver instance created successfully +18:45:03.954 ConformanceCheck OK Connected OK + +Common Driver Methods +18:45:03.995 InterfaceVersion OK 3 +18:45:04.023 Connected OK True +18:45:04.052 Description OK Meade Autostar 497 .net +18:45:04.081 DriverInfo OK Information about the driver itself. Version: 0.0 +18:45:04.110 DriverVersion OK 0.0 +18:45:04.139 Name OK Meade Autostar 497 .net +18:45:04.168 CommandString INFO Conform cannot test the CommandString method +18:45:04.174 CommandBlind INFO Conform cannot test the CommandBlind method +18:45:04.180 CommandBool INFO Conform cannot test the CommandBool method +18:45:04.185 Action INFO Conform cannot test the Action method +18:45:04.192 SupportedActions OK Driver returned an empty action list + +Can Properties +18:45:04.260 CanFindHome OK False +18:45:04.266 CanPark OK False +18:45:04.273 CanPulseGuide OK False +18:45:04.280 CanSetDeclinationRate OK False +18:45:04.287 CanSetGuideRates OK False +18:45:04.294 CanSetPark OK False +18:45:04.301 CanSetPierSide OK False +18:45:04.315 CanSetRightAscensionRate OK False +18:45:04.322 CanSetTracking OK False +18:45:04.330 CanSlew OK False +18:45:04.337 CanSlewltAz OK False +18:45:04.344 CanSlewAltAzAsync OK False +18:45:04.352 CanSlewAsync OK False +18:45:04.359 CanSync OK False +18:45:04.367 CanSyncAltAz OK False +18:45:04.375 CanUnPark OK False + +Pre-run Checks +18:45:04.421 Mount Safety INFO Scope is not parked, continuing testing +18:45:04.474 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +18:45:04.482 TimeCheck INFO PC UTCDate: 30-Apr-2019 17:45:04.482 +18:45:04.574 TimeCheck INFO Mount UTCDate: 30-Apr-2019 05:45:04.000 + +Properties +18:45:04.646 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. +18:45:04.683 Altitude OK Optional member threw a PropertyNotImplementedException exception. +18:45:04.715 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +18:45:04.747 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +18:45:04.779 AtHome OK False +18:45:04.813 AtPark OK False +18:45:04.845 Azimuth OK Optional member threw a PropertyNotImplementedException exception. +18:45:04.877 Declination OK 00:00:00.00 +18:45:04.909 DeclinationRate Read OK 0.00 +18:45:04.943 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +18:45:04.982 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.015 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.047 EquatorialSystem OK equLocalTopocentric +18:45:05.080 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.116 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.127 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:45:05.159 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.171 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:45:05.205 IsPulseGuiding OK CanPulseGuide is False and a PropertyNotImplementedException exception was generated as expected +18:45:05.237 RightAscension OK 00:00:00.00 +18:45:05.270 RightAscensionRate Read OK 0.00 +18:45:05.305 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +18:45:05.339 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.374 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.386 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.398 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.432 SiteLatitude Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.467 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.480 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.493 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.529 SiteLongitude Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.564 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.577 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.589 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.635 Slewing OK False +18:45:05.669 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.706 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.719 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.754 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.787 SiderealTime ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +18:45:05.827 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.862 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:45:05.877 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:45:05.915 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:45:05.928 Tracking Read OK True +18:45:05.963 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +18:45:06.005 TrackingRates Found drive rate: driveSidereal +18:45:06.017 TrackingRates OK Drive rates read OK +18:45:06.031 TrackingRates OK Disposed tracking rates OK +18:45:06.066 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +18:45:06.079 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +18:45:06.157 UTCDate Read OK 30-Apr-2019 05:45:05.000 +18:45:06.305 UTCDate Write OK New UTCDate written successfully: 30/04/2019 06:45:05 + +Methods +18:45:06.538 CanMoveAxis:Primary OK CanMoveAxis:Primary True +18:45:06.574 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +18:45:06.611 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +18:45:06.647 Park OK CanPark is False and a MethodNotImplementedException exception was generated as expected +18:45:06.662 UnPark OK CanUnPark is False and a MethodNotImplementedException exception was generated as expected +18:45:06.706 AbortSlew OK AbortSlew OK when not slewing +18:45:06.775 AxisRate:Primary OK Empty axis rate returned +18:45:06.788 AxisRate:Primary OK Disposed axis rates OK +18:45:06.801 AxisRate:Secondary OK Empty axis rate returned +18:45:06.814 AxisRate:Secondary OK Disposed axis rates OK +18:45:06.828 AxisRate:Tertiary OK Empty axis rate returned +18:45:06.840 AxisRate:Tertiary OK Disposed axis rates OK +18:45:06.855 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +18:45:06.905 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +18:45:06.919 MoveAxis Primary OK AxisRates object successfully disposed +18:45:06.978 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +18:45:06.991 MoveAxis Secondary OK AxisRates object successfully disposed +18:45:07.050 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +18:45:07.091 PulseGuide OK CanPulseGuide is False and a MethodNotImplementedException exception was generated as expected +18:45:07.146 SlewToCoordinates ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +18:45:07.191 SlewToCoordinatesAsync ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +18:45:07.235 SyncToCoordinates OK CanSync is False and a MethodNotImplementedException exception was generated as expected +18:45:07.272 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.287 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.309 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.348 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.362 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.376 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:45:07.421 SlewToTarget ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +18:45:07.466 SlewToTargetAsync ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +18:45:07.503 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +18:45:07.520 SlewToAltAz OK CanSlewAltAz is False and a MethodNotImplementedException exception was generated as expected +18:45:07.564 SlewToAltAzAsync OK CanSlewAltAzAsync is False and a MethodNotImplementedException exception was generated as expected +18:45:07.603 SyncToTarget OK CanSync is False and a MethodNotImplementedException exception was generated as expected +18:45:07.641 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected + +SideOfPier Model Tests +18:45:07.711 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read + +Post-run Checks +18:45:07.800 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. + +Conformance test complete + +Your driver had 0 errors, 2 warnings and 6 issues \ No newline at end of file diff --git a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj index e49ccdc..a7a4fae 100644 --- a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj +++ b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj @@ -26,6 +26,7 @@ prompt 4 false + x64 pdbonly diff --git a/MeadeAutostar497/Controller/ISerialProcessor.cs b/MeadeAutostar497/Controller/ISerialProcessor.cs index 5f2e2c0..5578bf3 100644 --- a/MeadeAutostar497/Controller/ISerialProcessor.cs +++ b/MeadeAutostar497/Controller/ISerialProcessor.cs @@ -22,5 +22,7 @@ namespace ASCOM.MeadeAutostar497.Controller char CommandChar(string command); string ReadTerminated(string terminator); void Command(string command); + void Lock(); + void Unlock(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs index b9fe333..2e14264 100644 --- a/MeadeAutostar497/Controller/SerialProcessor.cs +++ b/MeadeAutostar497/Controller/SerialProcessor.cs @@ -72,7 +72,7 @@ namespace ASCOM.MeadeAutostar497.Controller public string CommandTerminated(string command, string terminator) { - serialMutex.WaitOne(); + Lock(); try { _serialPort.Write(command); @@ -81,13 +81,13 @@ namespace ASCOM.MeadeAutostar497.Controller } finally { - serialMutex.ReleaseMutex(); + Unlock(); } } public char CommandChar(string command) { - serialMutex.WaitOne(); + Lock(); try { _serialPort.Write(command); @@ -96,13 +96,13 @@ namespace ASCOM.MeadeAutostar497.Controller } finally { - serialMutex.ReleaseMutex(); + Unlock(); } } public string ReadTerminated(string terminator) { - serialMutex.WaitOne(); + Lock(); try { string result = _serialPort.ReadTo("#"); @@ -110,21 +110,31 @@ namespace ASCOM.MeadeAutostar497.Controller } finally { - serialMutex.ReleaseMutex(); + Unlock(); } } public void Command(string command) { - serialMutex.WaitOne(); + Lock(); try { _serialPort.Write(command); } finally { - serialMutex.ReleaseMutex(); + Unlock(); } } + + public void Lock() + { + serialMutex.WaitOne(); + } + + public void Unlock() + { + serialMutex.ReleaseMutex(); + } } } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index a2a3f64..4979d07 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -93,7 +93,7 @@ namespace ASCOM.MeadeAutostar497.Controller private void TestConnectionActive() { - var firmwareVersionNumber = SerialPort.CommandTerminated("#:GVN#", "#"); + var firmwareVersionNumber = SerialPort.CommandTerminated(":GVN#", "#"); if (string.IsNullOrEmpty(firmwareVersionNumber)) { throw new InvalidOperationException("Failed to communicate with telescope."); @@ -106,7 +106,7 @@ namespace ASCOM.MeadeAutostar497.Controller { if (!Connected) return false; - var result = SerialPort.CommandTerminated("#:D#", "#"); + var result = SerialPort.CommandTerminated(":D#", "#"); return result != string.Empty; } } @@ -115,8 +115,8 @@ namespace ASCOM.MeadeAutostar497.Controller { get { - string telescopeDate = SerialPort.CommandTerminated("#:GC#", "#"); - string telescopeTime = SerialPort.CommandTerminated("#:GL#", "#"); + string telescopeDate = SerialPort.CommandTerminated(":GC#", "#"); + string telescopeTime = SerialPort.CommandTerminated(":GL#", "#"); int month = telescopeDate.Substring(0, 2).ToInteger(); int day = telescopeDate.Substring(3, 2).ToInteger(); @@ -138,21 +138,29 @@ namespace ASCOM.MeadeAutostar497.Controller set { //var result = SerialCommand(":SLHH:MM:SS#", true); - var timeResult = SerialPort.CommandChar($"#:SL{value:hh:mm:ss}#"); + var timeResult = SerialPort.CommandChar($":SL{value:hh:mm:ss}#"); if (timeResult != '1') { throw new InvalidOperationException("Failed to set local time"); } - var dateResult = SerialPort.CommandChar($"#:SC{value:MM/dd/yy}#"); - if (dateResult != '1') + SerialPort.Lock(); + try { - throw new InvalidOperationException("Failed to set local time"); - } + var dateResult = SerialPort.CommandChar($":SC{value:MM/dd/yy}#"); + if (dateResult != '1') + { + throw new InvalidOperationException("Failed to set local time"); + } - //throwing away these two strings which represent - SerialPort.ReadTerminated("#"); //Updating Planetary Data# - SerialPort.ReadTerminated("#"); // # + //throwing away these two strings which represent + SerialPort.ReadTerminated("#"); //Updating Planetary Data# + SerialPort.ReadTerminated("#"); // # + } + finally + { + SerialPort.Unlock(); + } } } diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 1fa4160..6de6351 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -46,7 +46,7 @@ prompt 4 true - AnyCPU + x64 false diff --git a/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj index 9631e67..4392996 100644 --- a/TestConsole/TestConsole.csproj +++ b/TestConsole/TestConsole.csproj @@ -16,7 +16,7 @@ 512 - x86 + x64 true full false From ef982a3aba400affa84ccf84d81ebf86e850d943 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 1 May 2019 00:22:15 +0100 Subject: [PATCH 007/109] Added code for the site latitude and started work on the longitude. --- ConformanceResult.txt | 305 ++++++++++-------- MeadeAutostar497/AscomClasses/Telescope.cs | 46 +-- .../Controller/ITelescopeController.cs | 2 + .../Controller/TelescopeController.cs | 54 ++++ TargetToBeat.txt | 249 ++++++++++++++ TestConsole/Program.cs | 11 +- 6 files changed, 509 insertions(+), 158 deletions(-) create mode 100644 TargetToBeat.txt diff --git a/ConformanceResult.txt b/ConformanceResult.txt index aaab4ff..3506e3b 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -1,3 +1,4 @@ + ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -11,156 +12,192 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -18:44:58.528 Driver Access Checks OK -18:44:59.174 AccessChecks OK Successfully created driver using late binding -18:44:59.400 AccessChecks OK Successfully connected using late binding -18:44:59.405 AccessChecks INFO The driver is a .NET object -18:44:59.409 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -18:44:59.413 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -18:45:00.117 AccessChecks INFO Device does not expose interface ITelescopeV2 -18:45:00.926 AccessChecks INFO Device exposes interface ITelescopeV3 -18:45:02.245 AccessChecks OK Successfully created driver using driver access toolkit -18:45:02.415 AccessChecks OK Successfully connected using driver access toolkit +00:17:11.400 Driver Access Checks OK +00:17:12.050 AccessChecks OK Successfully created driver using late binding +00:17:12.279 AccessChecks OK Successfully connected using late binding +00:17:12.283 AccessChecks INFO The driver is a .NET object +00:17:12.287 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +00:17:12.291 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +00:17:12.990 AccessChecks INFO Device does not expose interface ITelescopeV2 +00:17:13.805 AccessChecks INFO Device exposes interface ITelescopeV3 +00:17:15.124 AccessChecks OK Successfully created driver using driver access toolkit +00:17:15.332 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -18:45:03.742 ConformanceCheck OK Driver instance created successfully -18:45:03.954 ConformanceCheck OK Connected OK +00:17:16.657 ConformanceCheck OK Driver instance created successfully +00:17:16.877 ConformanceCheck OK Connected OK Common Driver Methods -18:45:03.995 InterfaceVersion OK 3 -18:45:04.023 Connected OK True -18:45:04.052 Description OK Meade Autostar 497 .net -18:45:04.081 DriverInfo OK Information about the driver itself. Version: 0.0 -18:45:04.110 DriverVersion OK 0.0 -18:45:04.139 Name OK Meade Autostar 497 .net -18:45:04.168 CommandString INFO Conform cannot test the CommandString method -18:45:04.174 CommandBlind INFO Conform cannot test the CommandBlind method -18:45:04.180 CommandBool INFO Conform cannot test the CommandBool method -18:45:04.185 Action INFO Conform cannot test the Action method -18:45:04.192 SupportedActions OK Driver returned an empty action list +00:17:16.919 InterfaceVersion OK 3 +00:17:16.946 Connected OK True +00:17:16.974 Description OK Meade Autostar 497 .net +00:17:17.003 DriverInfo OK Information about the driver itself. Version: 0.0 +00:17:17.032 DriverVersion OK 0.0 +00:17:17.061 Name OK Meade Autostar 497 .net +00:17:17.091 CommandString INFO Conform cannot test the CommandString method +00:17:17.097 CommandBlind INFO Conform cannot test the CommandBlind method +00:17:17.104 CommandBool INFO Conform cannot test the CommandBool method +00:17:17.110 Action INFO Conform cannot test the Action method +00:17:17.118 SupportedActions OK Driver returned an empty action list Can Properties -18:45:04.260 CanFindHome OK False -18:45:04.266 CanPark OK False -18:45:04.273 CanPulseGuide OK False -18:45:04.280 CanSetDeclinationRate OK False -18:45:04.287 CanSetGuideRates OK False -18:45:04.294 CanSetPark OK False -18:45:04.301 CanSetPierSide OK False -18:45:04.315 CanSetRightAscensionRate OK False -18:45:04.322 CanSetTracking OK False -18:45:04.330 CanSlew OK False -18:45:04.337 CanSlewltAz OK False -18:45:04.344 CanSlewAltAzAsync OK False -18:45:04.352 CanSlewAsync OK False -18:45:04.359 CanSync OK False -18:45:04.367 CanSyncAltAz OK False -18:45:04.375 CanUnPark OK False +00:17:17.192 CanFindHome OK False +00:17:17.199 CanPark OK True +00:17:17.206 CanPulseGuide OK True +00:17:17.213 CanSetDeclinationRate OK False +00:17:17.220 CanSetGuideRates OK False +00:17:17.227 CanSetPark OK False +00:17:17.235 CanSetPierSide OK False +00:17:17.248 CanSetRightAscensionRate OK False +00:17:17.256 CanSetTracking OK False +00:17:17.263 CanSlew OK True +00:17:17.271 CanSlewltAz OK True +00:17:17.278 CanSlewAltAzAsync OK True +00:17:17.286 CanSlewAsync OK True +00:17:17.295 CanSync OK True +00:17:17.303 CanSyncAltAz OK False +00:17:17.311 CanUnPark OK False Pre-run Checks -18:45:04.421 Mount Safety INFO Scope is not parked, continuing testing -18:45:04.474 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -18:45:04.482 TimeCheck INFO PC UTCDate: 30-Apr-2019 17:45:04.482 -18:45:04.574 TimeCheck INFO Mount UTCDate: 30-Apr-2019 05:45:04.000 +00:17:17.360 Mount Safety INFO Scope is not parked, continuing testing +00:17:17.413 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +00:17:17.421 TimeCheck INFO PC UTCDate: 30-Apr-2019 23:17:17.421 +00:17:17.509 TimeCheck INFO Mount UTCDate: 01-May-2019 12:16:15.000 Properties -18:45:04.646 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. -18:45:04.683 Altitude OK Optional member threw a PropertyNotImplementedException exception. -18:45:04.715 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -18:45:04.747 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -18:45:04.779 AtHome OK False -18:45:04.813 AtPark OK False -18:45:04.845 Azimuth OK Optional member threw a PropertyNotImplementedException exception. -18:45:04.877 Declination OK 00:00:00.00 -18:45:04.909 DeclinationRate Read OK 0.00 -18:45:04.943 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -18:45:04.982 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.015 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.047 EquatorialSystem OK equLocalTopocentric -18:45:05.080 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.116 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.127 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:45:05.159 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.171 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:45:05.205 IsPulseGuiding OK CanPulseGuide is False and a PropertyNotImplementedException exception was generated as expected -18:45:05.237 RightAscension OK 00:00:00.00 -18:45:05.270 RightAscensionRate Read OK 0.00 -18:45:05.305 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -18:45:05.339 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.374 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.386 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.398 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.432 SiteLatitude Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.467 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.480 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.493 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.529 SiteLongitude Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.564 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.577 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.589 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.635 Slewing OK False -18:45:05.669 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.706 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.719 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.754 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.787 SiderealTime ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -18:45:05.827 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.862 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:45:05.877 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:45:05.915 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:45:05.928 Tracking Read OK True -18:45:05.963 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -18:45:06.005 TrackingRates Found drive rate: driveSidereal -18:45:06.017 TrackingRates OK Drive rates read OK -18:45:06.031 TrackingRates OK Disposed tracking rates OK -18:45:06.066 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -18:45:06.079 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -18:45:06.157 UTCDate Read OK 30-Apr-2019 05:45:05.000 -18:45:06.305 UTCDate Write OK New UTCDate written successfully: 30/04/2019 06:45:05 +00:17:17.586 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.622 Altitude OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.654 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.687 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.718 AtHome OK False +00:17:17.753 AtPark OK False +00:17:17.785 Azimuth OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.817 Declination OK 00:00:00.00 +00:17:17.849 DeclinationRate Read OK 0.00 +00:17:17.882 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +00:17:17.914 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.948 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:17.980 EquatorialSystem OK equLocalTopocentric +00:17:18.014 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.047 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.058 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +00:17:18.091 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.103 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +00:17:18.138 IsPulseGuiding ISSUE CanPulseGuide is True and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:18.171 RightAscension OK 00:00:00.00 +00:17:18.205 RightAscensionRate Read OK 0.00 +00:17:18.239 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +00:17:18.274 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.309 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.320 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.334 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.391 SiteLatitude Read OK 00:00:00.00 +00:17:18.430 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +00:17:18.441 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +00:17:18.491 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +00:17:18.547 SiteLongitude Read OK 01:46:00.00 +00:17:18.584 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.596 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.609 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.653 Slewing OK False +00:17:18.688 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.723 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.736 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.773 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.825 SiderealTime OK 13:58:47.89 +00:17:18.837 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 13:58:47.89, ASCOM: 13:58:48.98 +00:17:18.874 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.910 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +00:17:18.923 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +00:17:18.957 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +00:17:18.970 Tracking Read OK True +00:17:19.005 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +00:17:19.051 TrackingRates Found drive rate: driveSidereal +00:17:19.064 TrackingRates OK Drive rates read OK +00:17:19.077 TrackingRates OK Disposed tracking rates OK +00:17:19.111 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +00:17:19.124 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +00:17:19.204 UTCDate Read OK 01-May-2019 12:16:17.000 +00:17:19.407 UTCDate Write OK New UTCDate written successfully: 01/05/2019 13:16:17 Methods -18:45:06.538 CanMoveAxis:Primary OK CanMoveAxis:Primary True -18:45:06.574 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -18:45:06.611 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -18:45:06.647 Park OK CanPark is False and a MethodNotImplementedException exception was generated as expected -18:45:06.662 UnPark OK CanUnPark is False and a MethodNotImplementedException exception was generated as expected -18:45:06.706 AbortSlew OK AbortSlew OK when not slewing -18:45:06.775 AxisRate:Primary OK Empty axis rate returned -18:45:06.788 AxisRate:Primary OK Disposed axis rates OK -18:45:06.801 AxisRate:Secondary OK Empty axis rate returned -18:45:06.814 AxisRate:Secondary OK Disposed axis rates OK -18:45:06.828 AxisRate:Tertiary OK Empty axis rate returned -18:45:06.840 AxisRate:Tertiary OK Disposed axis rates OK -18:45:06.855 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -18:45:06.905 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -18:45:06.919 MoveAxis Primary OK AxisRates object successfully disposed -18:45:06.978 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -18:45:06.991 MoveAxis Secondary OK AxisRates object successfully disposed -18:45:07.050 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -18:45:07.091 PulseGuide OK CanPulseGuide is False and a MethodNotImplementedException exception was generated as expected -18:45:07.146 SlewToCoordinates ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -18:45:07.191 SlewToCoordinatesAsync ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -18:45:07.235 SyncToCoordinates OK CanSync is False and a MethodNotImplementedException exception was generated as expected -18:45:07.272 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.287 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.309 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.348 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.362 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.376 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:45:07.421 SlewToTarget ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -18:45:07.466 SlewToTargetAsync ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -18:45:07.503 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -18:45:07.520 SlewToAltAz OK CanSlewAltAz is False and a MethodNotImplementedException exception was generated as expected -18:45:07.564 SlewToAltAzAsync OK CanSlewAltAzAsync is False and a MethodNotImplementedException exception was generated as expected -18:45:07.603 SyncToTarget OK CanSync is False and a MethodNotImplementedException exception was generated as expected -18:45:07.641 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +00:17:19.642 CanMoveAxis:Primary OK CanMoveAxis:Primary True +00:17:19.678 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +00:17:19.715 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +00:17:19.752 Park/Unpark INFO Tests skipped +00:17:19.776 AbortSlew OK AbortSlew OK when not slewing +00:17:19.843 AxisRate:Primary OK Empty axis rate returned +00:17:19.856 AxisRate:Primary OK Disposed axis rates OK +00:17:19.869 AxisRate:Secondary OK Empty axis rate returned +00:17:19.882 AxisRate:Secondary OK Disposed axis rates OK +00:17:19.895 AxisRate:Tertiary OK Empty axis rate returned +00:17:19.907 AxisRate:Tertiary OK Disposed axis rates OK +00:17:19.923 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +00:17:19.972 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +00:17:19.987 MoveAxis Primary OK AxisRates object successfully disposed +00:17:20.044 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +00:17:20.058 MoveAxis Secondary OK AxisRates object successfully disposed +00:17:20.117 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +00:17:20.155 PulseGuide ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +00:17:20.233 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:20.285 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.331 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.391 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.436 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.532 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:20.571 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.615 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.674 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.720 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.823 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:20.863 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.910 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:20.971 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:21.015 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:21.074 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.091 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.134 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.172 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.186 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.201 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:17:21.327 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.343 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.360 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.401 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.450 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.510 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.554 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.646 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.662 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.680 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.720 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.768 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.828 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.873 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.933 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +00:17:21.952 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:21.995 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.014 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.077 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.096 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.159 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.203 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.221 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.285 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.305 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:17:22.409 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.450 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.498 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.559 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.603 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:17:22.665 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -18:45:07.711 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +00:17:22.735 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -18:45:07.800 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +00:17:22.828 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 0 errors, 2 warnings and 6 issues \ No newline at end of file +Your driver had 0 errors, 2 warnings and 47 issues diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index bc4171d..1574c5d 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -387,8 +387,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanPark", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanPark", "Get - " + true.ToString()); + return true; } } @@ -396,8 +396,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanPulseGuide", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanPulseGuide", "Get - " + true.ToString()); + return true; } } @@ -459,8 +459,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSlew", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSlew", "Get - " + true.ToString()); + return true; } } @@ -468,8 +468,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSlewAltAz", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSlewAltAz", "Get - " + true.ToString()); + return true; } } @@ -477,8 +477,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSlewAltAzAsync", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSlewAltAzAsync", "Get - " + true.ToString()); + return true; } } @@ -486,8 +486,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSlewAsync", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSlewAsync", "Get - " + true.ToString()); + return true; } } @@ -495,8 +495,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSync", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSync", "Get - " + true.ToString()); + return true; } } @@ -732,13 +732,14 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("SiteLatitude Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteLatitude", false); + var siteLatitude = _telescopeController.SiteLatitude; + tl.LogMessage("SiteLatitude Get", $"{utilities.DegreesToDMS(siteLatitude)}"); + return siteLatitude; } set { - tl.LogMessage("SiteLatitude Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteLatitude", true); + tl.LogMessage("SiteLatitude Set", $"{utilities.DegreesToDMS(value)}"); + _telescopeController.SiteLatitude = value; } } @@ -746,13 +747,14 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("SiteLongitude Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteLongitude", false); + var siteLongitude = _telescopeController.SiteLongitude; + tl.LogMessage("SiteLongitude Get", $"{utilities.DegreesToDMS(siteLongitude)}"); + return siteLongitude; } set { - tl.LogMessage("SiteLongitude Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteLongitude", true); + tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(value)}"); + _telescopeController.SiteLongitude = value; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index d903675..32bde77 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -9,6 +9,8 @@ namespace ASCOM.MeadeAutostar497.Controller bool Slewing { get; } DateTime utcDate { get; set; } + double SiteLatitude { get; set; } + double SiteLongitude { get; set; } void AbortSlew(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 4979d07..33da8e6 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,6 +1,7 @@ using System; using System.IO.Ports; using System.Linq; +using ASCOM.Utilities; namespace ASCOM.MeadeAutostar497.Controller { @@ -165,6 +166,59 @@ namespace ASCOM.MeadeAutostar497.Controller } + public double SiteLatitude + { + get + { + var latitude = SerialPort.CommandTerminated( ":Gt#", "#"); + + double lat = int.Parse(latitude.Substring(1, 2)); + lat = lat + double.Parse(latitude.Substring(4, 2)) / 60; + if (latitude.Length == 9) + lat = lat + double.Parse(latitude.Substring(7, 2)) / 60 / 60; + + if (latitude[0] == '-') + lat = -lat; + + return lat; + } + set + { + if (value > 90) + throw new ASCOM.InvalidValueException("Latitude cannot be greater than 90 degrees."); + + if (value < -90) + throw new ASCOM.InvalidValueException("Latitude cannot be less than -90 degrees."); + + int dd = Convert.ToInt32(Math.Floor(value)); + int mm = Convert.ToInt32(60 * (value - dd)); + + var result = SerialPort.CommandChar($":Sts{dd:00}*{mm:00}#"); + if (result != '1') + throw new InvalidOperationException("Failed to set site latitude."); + } + } + + public double SiteLongitude + { + get + { + var longitude = SerialPort.CommandTerminated(":Gg#", "#"); + + double l = int.Parse(longitude.Substring(0, 3)); + l = l + double.Parse(longitude.Substring(4, 2)) / 60; + if (longitude.Length == 9) + l = l + double.Parse(longitude.Substring(7, 2)) / 60 / 60; + + return l; + } + set + { + throw new ASCOM.PropertyNotImplementedException("not done yet."); + } + + } + public void AbortSlew() { SerialPort.Command("#:Q#"); diff --git a/TargetToBeat.txt b/TargetToBeat.txt new file mode 100644 index 0000000..8255bd9 --- /dev/null +++ b/TargetToBeat.txt @@ -0,0 +1,249 @@ + +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: MeadeEx.Telescope + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040401 +Error number for "Invalid Value 2" is: 80040405 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +21:04:42.255 Driver Access Checks OK +21:04:42.997 AccessChecks OK Successfully created driver using late binding +21:04:50.059 AccessChecks OK Successfully connected using late binding +21:04:50.063 AccessChecks INFO The driver is a COM object +21:04:57.769 AccessChecks INFO Device exposes interface ITelescopeV2 +21:04:58.546 AccessChecks INFO Device does not expose interface ITelescopeV3 +21:04:59.881 AccessChecks OK Successfully created driver using driver access toolkit +21:05:06.873 AccessChecks OK Successfully connected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object +21:05:08.261 ConformanceCheck OK Driver instance created successfully +21:05:15.293 ConformanceCheck OK Connected OK + +Common Driver Methods +21:05:15.333 InterfaceVersion OK 2 +21:05:15.362 Connected OK True +21:05:15.448 Description OK Meade Autostar 497: ETX Autostar|A|43Ea|Jun 02 2006@10:09:40 +21:05:15.480 DriverInfo OK ASCOM Meade Telescope/Focuser driver for classic and Autostar I 5.0.4 + ASCOM Iniative + http://ascom-standards.org/ + Last Modified 10/06/2013 19:06:54 +21:05:15.509 DriverVersion OK 5.0 +21:05:15.539 Name OK Autostar 497 +21:05:15.568 CommandString INFO Conform cannot test the CommandString method +21:05:15.572 CommandBlind INFO Conform cannot test the CommandBlind method +21:05:15.582 CommandBool INFO Conform cannot test the CommandBool method +21:05:15.588 Action INFO Conform cannot test the Action method +21:05:15.595 SupportedActions OK Driver returned an empty action list + +Can Properties +21:05:15.663 CanFindHome OK False +21:05:15.671 CanPark OK True +21:05:15.679 CanPulseGuide OK True +21:05:15.687 CanSetDeclinationRate OK False +21:05:15.695 CanSetGuideRates OK False +21:05:15.703 CanSetPark OK False +21:05:15.711 CanSetPierSide OK False +21:05:15.719 CanSetRightAscensionRate OK False +21:05:15.727 CanSetTracking OK False +21:05:15.735 CanSlew OK True +21:05:15.743 CanSlewltAz OK True +21:05:15.752 CanSlewAltAzAsync OK True +21:05:15.761 CanSlewAsync OK True +21:05:15.769 CanSync OK True +21:05:15.777 CanSyncAltAz OK False +21:05:15.785 CanUnPark OK False + +Pre-run Checks +21:05:15.834 Mount Safety INFO Scope is not parked, continuing testing +21:05:15.887 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +21:05:15.894 TimeCheck INFO PC UTCDate: 30-Apr-2019 20:05:15.894 +21:05:16.013 TimeCheck INFO Mount UTCDate: 30-Apr-2019 20:04:15.000 + +Properties +21:05:16.063 AlignmentMode OK algPolar +21:05:16.117 Altitude OK 90.00 +21:05:16.149 ApertureArea ERROR Unexpected DriverAccessCOMException, : Property ApertureAreaThe supplied value is out of range for this property. +21:05:16.182 ApertureDiameter ERROR Unexpected DriverAccessCOMException, : Property ApertureDiameterThe supplied value is out of range for this property. +21:05:16.214 AtHome OK False +21:05:16.245 AtPark OK False +21:05:16.310 Azimuth OK 0.57 +21:05:16.369 Declination OK 89:59:59.00 +21:05:16.402 DeclinationRate Read OK 0.00 +21:05:16.434 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +21:05:16.469 DoesRefraction Read OK True +21:05:16.501 DoesRefraction Write ERROR Unexpected DriverAccessCOMException, : Property DoesRefractionThe supplied value is out of range for this property. +21:05:16.534 EquatorialSystem OK equLocalTopocentric +21:05:16.568 FocalLength ERROR Unexpected DriverAccessCOMException, : Property FocalLengthThe supplied value is out of range for this property. +21:05:16.602 GuideRateDeclination Read OK 0.00 +21:05:16.613 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +21:05:16.646 GuideRateRightAscension Read OK 0.00 +21:05:16.661 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +21:05:16.694 IsPulseGuiding OK False +21:05:16.748 RightAscension OK 22:28:48.00 +21:05:16.781 RightAscensionRate Read OK 0.00 +21:05:16.814 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +21:05:16.848 SiteElevation Read OK 0 +21:05:16.884 SiteElevation Write ERROR Unexpected DriverAccessCOMException, : Property SiteElevation The supplied value is out of range for this property. +21:05:16.896 SiteElevation Write ERROR Unexpected DriverAccessCOMException, : Property SiteElevation The supplied value is out of range for this property. +21:05:16.908 SiteElevation Write OK Legal value 0m written successfully +21:05:16.965 SiteLatitude Read OK 53:50:00.00 +21:05:16.999 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.012 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.025 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.096 SiteLongitude Read OK -01:46:00.00 +21:05:17.130 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.144 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.156 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.192 Slewing OK False +21:05:17.226 SlewSettleTime Read OK 0 +21:05:17.262 SlewSettleTime Write ERROR Unexpected DriverAccessCOMException, : Property SlewSettleTime The supplied value is out of range for this property. +21:05:17.277 SlewSettleTime Write OK Legal value 0 seconds written successfully +21:05:17.313 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +21:05:17.356 SiderealTime OK 10:31:06.00 +21:05:17.368 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:31:06.00, ASCOM: 10:32:07.97 +21:05:17.405 TargetDeclination Read ERROR Unexpected DriverAccessCOMException, : The target value is not set. +21:05:17.440 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +21:05:17.454 TargetRightAscension Read ERROR Unexpected DriverAccessCOMException, : The target value is not set. +21:05:17.489 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +21:05:17.502 Tracking Read OK True +21:05:17.537 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +21:05:17.575 TrackingRates ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. +21:05:17.590 TrackingRates ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. +21:05:17.603 TrackingRates OK Dispose member not present +21:05:17.638 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +21:05:17.651 TrackingRate Read OK driveSidereal +21:05:17.665 TrackingRate Write ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. +21:05:17.760 UTCDate Read OK 30-Apr-2019 20:04:16.000 +21:05:17.774 UTCDate Write OK Optional member threw a PropertyNotImplementedException exception. + +Methods +21:05:17.858 CanMoveAxis:Primary OK CanMoveAxis:Primary False +21:05:17.894 CanMoveAxis:Secondary OK CanMoveAxis:Secondary False +21:05:17.931 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +21:05:17.967 Park/Unpark INFO Tests skipped +21:05:18.981 AbortSlew OK AbortSlew OK when not slewing +21:05:19.040 AxisRate:Primary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) + --- End of inner exception stack trace --- + at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 +21:05:19.055 AxisRate:Primary OK Empty axis rate returned +21:05:19.069 AxisRate:Primary OK AxisRates.Dispose() member not present for axis axisPrimary +21:05:19.085 AxisRate:Secondary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) + --- End of inner exception stack trace --- + at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 +21:05:19.100 AxisRate:Secondary OK Empty axis rate returned +21:05:19.117 AxisRate:Secondary OK AxisRates.Dispose() member not present for axis axisSecondary +21:05:19.132 AxisRate:Tertiary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) + --- End of inner exception stack trace --- + at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) + at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 +21:05:19.149 AxisRate:Tertiary OK Empty axis rate returned +21:05:19.178 AxisRate:Tertiary OK AxisRates.Dispose() member not present for axis axisTertiary +21:05:19.195 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +21:05:19.234 MoveAxis Primary OK CanMoveAxis Primary is False and a MethodNotImplementedException exception was generated as expected +21:05:19.273 MoveAxis Secondary OK CanMoveAxis Secondary is False and a MethodNotImplementedException exception was generated as expected +21:05:19.314 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +21:05:21.349 PulseGuide OK Synchronous pulse guide found OK +21:06:13.942 SlewToCoordinates INFO Slewed within 15.0 arc seconds of expected RA: 09:31:10.00, actual RA: 09:31:09.00 +21:06:13.956 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 +21:06:13.971 SlewToCoordinates OK The TargetRightAscension property 09:31:10.00 matches the expected RA OK. +21:06:13.987 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +21:06:14.028 SlewToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:06:14.102 SlewToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:06:14.164 SlewToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:06:14.262 SlewToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:06:48.075 SlewToCoordinatesAsync INFO Slewed within 45.0 arc seconds of expected RA: 08:32:03.00, actual RA: 08:32:00.00 +21:06:48.090 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 +21:06:48.106 SlewToCoordinatesAsync OK The TargetRightAscension property 08:32:03.00 matches the expected RA OK. +21:06:48.122 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +21:06:48.164 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:06:48.239 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:06:48.302 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:06:48.436 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:07:22.044 SyncToCoordinates INFO Slewed to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 +21:07:22.061 SyncToCoordinates OK Slewed to start position OK. DEC: 26:55:00.00 +21:07:22.782 SyncToCoordinates INFO Synced to sync position within 15.0 arc seconds of expected RA: 07:28:37.00, actual RA: 07:28:36.00 +21:07:22.796 SyncToCoordinates OK Synced to sync position OK. DEC: 25:55:00.00 +21:07:22.812 SyncToCoordinates OK The TargetRightAscension property 07:28:37.00 matches the expected RA OK. +21:07:22.828 SyncToCoordinates OK The TargetDeclination property 25:55:00.00 matches the expected Declination OK. +21:07:53.961 SyncToCoordinates INFO Slewed back to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 +21:07:53.976 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:55:00.00 +21:07:54.692 SyncToCoordinates INFO Synced to reversed sync position within 30.0 arc seconds of expected RA: 07:36:37.00, actual RA: 07:36:35.00 +21:07:54.708 SyncToCoordinates OK Synced to reversed sync position OK. DEC: 27:55:00.00 +21:08:25.954 SyncToCoordinates INFO Slewed back to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 +21:08:25.969 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:55:00.00 +21:08:26.009 SyncToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, syncing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:08:26.087 SyncToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, syncing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:08:26.150 SyncToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, syncing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:08:26.229 SyncToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, syncing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:08:26.292 TargetRightAscension Write ERROR Unexpected DriverAccessCOMException, : Property TargetRightAscension The supplied value is out of range for this property. +21:08:26.311 TargetRightAscension Write ERROR Unexpected DriverAccessCOMException, : Property TargetRightAscension The supplied value is out of range for this property. +21:08:26.395 TargetRightAscension Write OK Legal value 06:34:15.00 HH:MM:SS written successfully +21:08:26.435 TargetDeclination Write ERROR Unexpected DriverAccessCOMException, : Property TargetDeclination The supplied value is out of range for this property. +21:08:26.454 TargetDeclination Write ERROR Unexpected DriverAccessCOMException, : Property TargetDeclination The supplied value is out of range for this property. +21:08:26.506 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +21:08:57.865 SlewToTarget INFO Slewed within 45.0 arc seconds of expected RA: 07:34:15.00, actual RA: 07:34:12.00 +21:08:57.880 SlewToTarget OK Slewed OK. DEC: 03:00:00.00 +21:08:57.897 SlewToTarget OK The TargetRightAscension property 07:34:15.00 matches the expected RA OK. +21:08:57.915 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +21:08:57.959 SlewToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:08:58.003 SlewToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:08:58.064 SlewToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:08:58.114 SlewToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:09:29.948 SlewToTargetAsync INFO Slewed within 45.0 arc seconds of expected RA: 06:34:47.00, actual RA: 06:34:44.00 +21:09:29.964 SlewToTargetAsync OK Slewed OK. DEC: 04:00:00.00 +21:09:29.979 SlewToTargetAsync OK The TargetRightAscension property 06:34:47.00 matches the expected RA OK. +21:09:29.996 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +21:09:30.038 SlewToTargetAsync (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:09:30.085 SlewToTargetAsync (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:09:30.150 SlewToTargetAsync (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:09:30.196 SlewToTargetAsync (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:09:30.257 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +21:09:30.278 SlewToAltAz ERROR Unexpected DriverAccessCOMException, CanSlewAltAz is True: Wrong tracking state +21:09:30.322 SlewToAltAz (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state +21:09:30.343 SlewToAltAz (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state +21:09:30.407 SlewToAltAz (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state +21:09:30.426 SlewToAltAz (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state +21:09:30.492 SlewToAltAzAsync ERROR Unexpected DriverAccessCOMException, CanSlewAltAzAsync is True: Wrong tracking state +21:09:30.534 SlewToAltAzAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state +21:09:30.552 SlewToAltAzAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state +21:09:30.617 SlewToAltAzAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state +21:09:30.637 SlewToAltAzAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state +21:10:05.974 SyncToTarget OK Slewed to start position OK. RA: 07:35:20.00 +21:10:05.993 SyncToTarget OK Slewed to start position OK. DEC: 26:55:00.00 +21:10:06.721 SyncToTarget OK Synced to sync position OK. RA: 07:31:20.00 +21:10:06.736 SyncToTarget OK Synced to sync position OK. DEC: 25:55:00.00 +21:10:37.626 SyncToTarget OK Slewed back to start position OK. RA: 07:35:20.00 +21:10:37.641 SyncToTarget OK Slewed back to start position OK. DEC: 26:55:00.00 +21:10:38.363 SyncToTarget OK Synced to reversed sync position OK. RA: 07:39:20.00 +21:10:38.381 SyncToTarget OK Synced to reversed sync position OK. DEC: 27:55:00.00 +21:11:09.639 SyncToTarget OK Slewed back to start position OK. RA: 07:35:20.00 +21:11:09.657 SyncToTarget OK Slewed back to start position OK. DEC: 26:55:00.00 +21:11:09.697 SyncToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:11:09.741 SyncToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:11:09.803 SyncToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. +21:11:09.847 SyncToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. +21:11:10.010 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected + +SideOfPier Model Tests +21:11:10.080 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read + +Post-run Checks +21:11:10.180 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. + +Conformance test complete + +Your driver had 53 errors, 0 warnings and 0 issues \ No newline at end of file diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index b2ef23b..560918a 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -43,9 +43,16 @@ namespace ASCOM //Console.WriteLine(device.Slewing); - device.UTCDate = DateTime.UtcNow; + //device.UTCDate = DateTime.UtcNow; - Console.WriteLine(device.UTCDate); + //Console.WriteLine(device.UTCDate); + + double l = device.SiteLatitude; + device.SiteLatitude = l; + + //double l = device.SiteLongitude; + //device.SiteLongitude = l; + //Console.WriteLine(device.SiteLongitude); device.Connected = false; Console.WriteLine("Press Enter to finish"); From eb3c7710d7ae583ba263daa58f5ed60d3ae81f74 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 1 May 2019 13:20:03 +0100 Subject: [PATCH 008/109] Added unit tests for reading and writing the utcDate. Fixed a couple of defects in the code that was setting the utcDate. --- .../TelescopeControllerUnitTests.cs | 102 +++++++++++++++++- MeadeAutostar497/AscomClasses/Telescope.cs | 1 + .../Controller/TelescopeController.cs | 29 +++-- 3 files changed, 119 insertions(+), 13 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 9362784..a1d20b4 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -1,10 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO.Ports; -using ASCOM; using ASCOM.MeadeAutostar497.Controller; -using ASCOM.Utilities; using Moq; using NUnit.Framework; +using InvalidOperationException = ASCOM.InvalidOperationException; namespace MeadeAutostar497.UnitTests { @@ -38,7 +38,7 @@ namespace MeadeAutostar497.UnitTests [TearDown] public void TearDown() { - _telescopeController.Port = "COM1"; + _telescopeController.Port = "COM1"; } [Test] @@ -163,5 +163,99 @@ namespace MeadeAutostar497.UnitTests serialMock.Verify(x => x.Command("#:Q#"), Times.Once); } + + [Test] + public void SlewingReturnTrueAsExpected() + { + _isConnected = true; + + _telescopeController.Connected = true; + + serialMock.Setup(x => x.CommandTerminated(":D#", "#")).Returns("|"); + + var slewing = _telescopeController.Slewing; + + Assert.That(slewing, Is.True); + } + + [Test] + public void SlewingReturnFalseAsExpected() + { + _isConnected = true; + + _telescopeController.Connected = true; + + serialMock.Setup(x => x.CommandTerminated(":D#", "#")).Returns(string.Empty); + + var slewing = _telescopeController.Slewing; + + Assert.That(slewing, Is.False); + } + + [Test] + public void utcDate_Get_ReturnsExpectedValue() + { + DateTime expectedDate = new DateTime(2019, 04, 30, 12, 32, 24, DateTimeKind.Utc); + + var dateString = "04/30/19"; + var timeString = "12:32:24"; + + _isConnected = true; + + _telescopeController.Connected = true; + + serialMock.Setup(x => x.CommandTerminated(":GC#", "#")).Returns(dateString); + serialMock.Setup(x => x.CommandTerminated(":GL#", "#")).Returns(timeString); + + var result = _telescopeController.utcDate; + + Assert.That(result, Is.EqualTo(expectedDate)); + } + + [Test] + public void utcDate_Set_SetsTelescopeDateAndTime() + { + DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); + serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); + serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); + + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.utcDate = testDateTime; + } + + [Test] + public void utcDate_Set_ThrowsExceptionWhenTimeInvalid() + { + DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); + //serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); + serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); + + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws( () => {_telescopeController.utcDate = testDateTime; }); + + Assert.That( exception.Message, Is.EqualTo("Failed to set local time")); + } + + [Test] + public void utcDate_Set_ThrowsExceptionWhenDateInvalid() + { + DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); + serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); + //serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); + + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.utcDate = testDateTime; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to set local date")); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 1574c5d..d3d2113 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -869,6 +869,7 @@ namespace ASCOM.MeadeAutostar497 { get { + //todo implementing this, it exists. bool tracking = true; tl.LogMessage("Tracking", "Get - " + tracking.ToString()); return tracking; diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 33da8e6..1f620e9 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,7 +1,6 @@ using System; using System.IO.Ports; using System.Linq; -using ASCOM.Utilities; namespace ASCOM.MeadeAutostar497.Controller { @@ -123,7 +122,7 @@ namespace ASCOM.MeadeAutostar497.Controller int day = telescopeDate.Substring(3, 2).ToInteger(); int year = telescopeDate.Substring(6, 2).ToInteger(); - if (year < 2000) //This is a hack that will work until the end of the century + if (year < 2000) //todo fix this hack that will create a Y2K100 bug { year = year + 2000; } @@ -132,14 +131,15 @@ namespace ASCOM.MeadeAutostar497.Controller int minute = telescopeTime.Substring(3, 2).ToInteger(); int second = telescopeTime.Substring(6, 2).ToInteger(); + //Todo is this telescope local time, or real utc? var newDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); return newDate; } set { - //var result = SerialCommand(":SLHH:MM:SS#", true); - var timeResult = SerialPort.CommandChar($":SL{value:hh:mm:ss}#"); + //Todo is this telescope local time, or real utc? + var timeResult = SerialPort.CommandChar($":SL{value:HH:mm:ss}#"); if (timeResult != '1') { throw new InvalidOperationException("Failed to set local time"); @@ -151,7 +151,7 @@ namespace ASCOM.MeadeAutostar497.Controller var dateResult = SerialPort.CommandChar($":SC{value:MM/dd/yy}#"); if (dateResult != '1') { - throw new InvalidOperationException("Failed to set local time"); + throw new InvalidOperationException("Failed to set local date"); } //throwing away these two strings which represent @@ -190,10 +190,10 @@ namespace ASCOM.MeadeAutostar497.Controller if (value < -90) throw new ASCOM.InvalidValueException("Latitude cannot be less than -90 degrees."); - int dd = Convert.ToInt32(Math.Floor(value)); - int mm = Convert.ToInt32(60 * (value - dd)); + int d = Convert.ToInt32(Math.Floor(value)); + int m = Convert.ToInt32(60 * (value - d)); - var result = SerialPort.CommandChar($":Sts{dd:00}*{mm:00}#"); + var result = SerialPort.CommandChar($":Sts{d:00}*{m:00}#"); if (result != '1') throw new InvalidOperationException("Failed to set site latitude."); } @@ -214,7 +214,18 @@ namespace ASCOM.MeadeAutostar497.Controller } set { - throw new ASCOM.PropertyNotImplementedException("not done yet."); + if (value >= 360) + throw new ASCOM.InvalidValueException("Longitude cannot be greater than or equal to 360 degrees."); + + if (value < 0) + throw new ASCOM.InvalidValueException("Longitude cannot be lower than 0 degrees."); + + int d = Convert.ToInt32(Math.Floor(value)); + int m = Convert.ToInt32(60 * (value - d)); + + var result = SerialPort.CommandChar($":Sg{d:000}*{m:00}#"); + if (result != '1') + throw new InvalidOperationException("Failed to set site Longitude."); } } From a59b602b54ee27e7a3c2d33d03a274280028a1e0 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 1 May 2019 19:37:58 +0100 Subject: [PATCH 009/109] Corrected Longitude value range --- ConformanceResult.txt | 341 +++++++++--------- .../Controller/TelescopeController.cs | 11 +- 2 files changed, 179 insertions(+), 173 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index 3506e3b..ef58bd0 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -1,3 +1,6 @@ +Start-up ASCOM Device Conformance Checker - 64bit mode +Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 + ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -12,191 +15,191 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -00:17:11.400 Driver Access Checks OK -00:17:12.050 AccessChecks OK Successfully created driver using late binding -00:17:12.279 AccessChecks OK Successfully connected using late binding -00:17:12.283 AccessChecks INFO The driver is a .NET object -00:17:12.287 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -00:17:12.291 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -00:17:12.990 AccessChecks INFO Device does not expose interface ITelescopeV2 -00:17:13.805 AccessChecks INFO Device exposes interface ITelescopeV3 -00:17:15.124 AccessChecks OK Successfully created driver using driver access toolkit -00:17:15.332 AccessChecks OK Successfully connected using driver access toolkit +17:38:04.254 Driver Access Checks OK +17:38:04.900 AccessChecks OK Successfully created driver using late binding +17:38:05.127 AccessChecks OK Successfully connected using late binding +17:38:05.132 AccessChecks INFO The driver is a .NET object +17:38:05.137 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +17:38:05.142 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +17:38:05.839 AccessChecks INFO Device does not expose interface ITelescopeV2 +17:38:06.643 AccessChecks INFO Device exposes interface ITelescopeV3 +17:38:07.961 AccessChecks OK Successfully created driver using driver access toolkit +17:38:08.125 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -00:17:16.657 ConformanceCheck OK Driver instance created successfully -00:17:16.877 ConformanceCheck OK Connected OK +17:38:09.448 ConformanceCheck OK Driver instance created successfully +17:38:09.659 ConformanceCheck OK Connected OK Common Driver Methods -00:17:16.919 InterfaceVersion OK 3 -00:17:16.946 Connected OK True -00:17:16.974 Description OK Meade Autostar 497 .net -00:17:17.003 DriverInfo OK Information about the driver itself. Version: 0.0 -00:17:17.032 DriverVersion OK 0.0 -00:17:17.061 Name OK Meade Autostar 497 .net -00:17:17.091 CommandString INFO Conform cannot test the CommandString method -00:17:17.097 CommandBlind INFO Conform cannot test the CommandBlind method -00:17:17.104 CommandBool INFO Conform cannot test the CommandBool method -00:17:17.110 Action INFO Conform cannot test the Action method -00:17:17.118 SupportedActions OK Driver returned an empty action list +17:38:09.700 InterfaceVersion OK 3 +17:38:09.728 Connected OK True +17:38:09.757 Description OK Meade Autostar 497 .net +17:38:09.787 DriverInfo OK Information about the driver itself. Version: 0.0 +17:38:09.816 DriverVersion OK 0.0 +17:38:09.846 Name OK Meade Autostar 497 .net +17:38:09.875 CommandString INFO Conform cannot test the CommandString method +17:38:09.881 CommandBlind INFO Conform cannot test the CommandBlind method +17:38:09.888 CommandBool INFO Conform cannot test the CommandBool method +17:38:09.894 Action INFO Conform cannot test the Action method +17:38:09.900 SupportedActions OK Driver returned an empty action list Can Properties -00:17:17.192 CanFindHome OK False -00:17:17.199 CanPark OK True -00:17:17.206 CanPulseGuide OK True -00:17:17.213 CanSetDeclinationRate OK False -00:17:17.220 CanSetGuideRates OK False -00:17:17.227 CanSetPark OK False -00:17:17.235 CanSetPierSide OK False -00:17:17.248 CanSetRightAscensionRate OK False -00:17:17.256 CanSetTracking OK False -00:17:17.263 CanSlew OK True -00:17:17.271 CanSlewltAz OK True -00:17:17.278 CanSlewAltAzAsync OK True -00:17:17.286 CanSlewAsync OK True -00:17:17.295 CanSync OK True -00:17:17.303 CanSyncAltAz OK False -00:17:17.311 CanUnPark OK False +17:38:09.968 CanFindHome OK False +17:38:09.975 CanPark OK True +17:38:09.982 CanPulseGuide OK True +17:38:09.989 CanSetDeclinationRate OK False +17:38:09.995 CanSetGuideRates OK False +17:38:10.002 CanSetPark OK False +17:38:10.009 CanSetPierSide OK False +17:38:10.022 CanSetRightAscensionRate OK False +17:38:10.030 CanSetTracking OK False +17:38:10.038 CanSlew OK True +17:38:10.045 CanSlewltAz OK True +17:38:10.052 CanSlewAltAzAsync OK True +17:38:10.060 CanSlewAsync OK True +17:38:10.067 CanSync OK True +17:38:10.075 CanSyncAltAz OK False +17:38:10.083 CanUnPark OK False Pre-run Checks -00:17:17.360 Mount Safety INFO Scope is not parked, continuing testing -00:17:17.413 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -00:17:17.421 TimeCheck INFO PC UTCDate: 30-Apr-2019 23:17:17.421 -00:17:17.509 TimeCheck INFO Mount UTCDate: 01-May-2019 12:16:15.000 +17:38:10.130 Mount Safety INFO Scope is not parked, continuing testing +17:38:10.183 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +17:38:10.192 TimeCheck INFO PC UTCDate: 01-May-2019 16:38:10.192 +17:38:10.284 TimeCheck INFO Mount UTCDate: 01-May-2019 20:02:19.000 Properties -00:17:17.586 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.622 Altitude OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.654 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.687 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.718 AtHome OK False -00:17:17.753 AtPark OK False -00:17:17.785 Azimuth OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.817 Declination OK 00:00:00.00 -00:17:17.849 DeclinationRate Read OK 0.00 -00:17:17.882 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -00:17:17.914 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.948 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:17.980 EquatorialSystem OK equLocalTopocentric -00:17:18.014 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.047 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.058 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -00:17:18.091 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.103 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -00:17:18.138 IsPulseGuiding ISSUE CanPulseGuide is True and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:18.171 RightAscension OK 00:00:00.00 -00:17:18.205 RightAscensionRate Read OK 0.00 -00:17:18.239 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -00:17:18.274 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.309 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.320 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.334 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.391 SiteLatitude Read OK 00:00:00.00 -00:17:18.430 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -00:17:18.441 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -00:17:18.491 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -00:17:18.547 SiteLongitude Read OK 01:46:00.00 -00:17:18.584 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.596 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.609 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.653 Slewing OK False -00:17:18.688 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.723 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.736 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.773 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.825 SiderealTime OK 13:58:47.89 -00:17:18.837 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 13:58:47.89, ASCOM: 13:58:48.98 -00:17:18.874 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.910 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -00:17:18.923 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -00:17:18.957 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -00:17:18.970 Tracking Read OK True -00:17:19.005 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -00:17:19.051 TrackingRates Found drive rate: driveSidereal -00:17:19.064 TrackingRates OK Drive rates read OK -00:17:19.077 TrackingRates OK Disposed tracking rates OK -00:17:19.111 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -00:17:19.124 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -00:17:19.204 UTCDate Read OK 01-May-2019 12:16:17.000 -00:17:19.407 UTCDate Write OK New UTCDate written successfully: 01/05/2019 13:16:17 +17:38:10.356 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.392 Altitude OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.423 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.456 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.487 AtHome OK False +17:38:10.523 AtPark OK False +17:38:10.558 Azimuth OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.593 Declination OK 00:00:00.00 +17:38:10.626 DeclinationRate Read OK 0.00 +17:38:10.660 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +17:38:10.694 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.726 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.759 EquatorialSystem OK equLocalTopocentric +17:38:10.792 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.824 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.836 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +17:38:10.871 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:10.885 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +17:38:10.922 IsPulseGuiding ISSUE CanPulseGuide is True and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:10.956 RightAscension OK 00:00:00.00 +17:38:10.990 RightAscensionRate Read OK 0.00 +17:38:11.024 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +17:38:11.058 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.093 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.105 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.117 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.173 SiteLatitude Read OK 00:00:00.00 +17:38:11.214 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +17:38:11.231 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +17:38:11.264 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +17:38:11.324 SiteLongitude Read OK 01:46:00.00 +17:38:11.363 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +17:38:11.378 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +17:38:11.417 SiteLongitude Write OK Legal value 01:46:00.00 degrees written successfully +17:38:11.458 Slewing OK False +17:38:11.493 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.529 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.541 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.578 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.642 SiderealTime OK 07:22:31.69 +17:38:11.655 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 07:22:31.69, ASCOM: 07:22:32.79 +17:38:11.694 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.731 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +17:38:11.744 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +17:38:11.779 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +17:38:11.791 Tracking Read OK True +17:38:11.829 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +17:38:11.870 TrackingRates Found drive rate: driveSidereal +17:38:11.882 TrackingRates OK Drive rates read OK +17:38:11.894 TrackingRates OK Disposed tracking rates OK +17:38:11.933 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +17:38:11.947 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +17:38:12.025 UTCDate Read OK 01-May-2019 20:02:21.000 +17:38:12.196 UTCDate Write OK New UTCDate written successfully: 01/05/2019 21:02:21 Methods -00:17:19.642 CanMoveAxis:Primary OK CanMoveAxis:Primary True -00:17:19.678 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -00:17:19.715 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -00:17:19.752 Park/Unpark INFO Tests skipped -00:17:19.776 AbortSlew OK AbortSlew OK when not slewing -00:17:19.843 AxisRate:Primary OK Empty axis rate returned -00:17:19.856 AxisRate:Primary OK Disposed axis rates OK -00:17:19.869 AxisRate:Secondary OK Empty axis rate returned -00:17:19.882 AxisRate:Secondary OK Disposed axis rates OK -00:17:19.895 AxisRate:Tertiary OK Empty axis rate returned -00:17:19.907 AxisRate:Tertiary OK Disposed axis rates OK -00:17:19.923 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -00:17:19.972 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -00:17:19.987 MoveAxis Primary OK AxisRates object successfully disposed -00:17:20.044 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -00:17:20.058 MoveAxis Secondary OK AxisRates object successfully disposed -00:17:20.117 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -00:17:20.155 PulseGuide ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -00:17:20.233 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:20.285 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.331 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.391 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.436 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.532 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:20.571 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.615 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.674 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.720 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.823 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:20.863 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.910 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:20.971 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:21.015 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:21.074 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.091 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.134 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.172 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.186 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.201 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:17:21.327 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.343 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.360 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.401 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.450 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.510 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.554 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.646 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.662 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.680 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.720 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.768 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.828 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.873 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.933 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -00:17:21.952 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:21.995 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.014 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.077 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.096 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.159 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.203 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.221 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.285 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.305 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:17:22.409 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.450 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.498 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.559 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.603 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:17:22.665 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +17:38:12.430 CanMoveAxis:Primary OK CanMoveAxis:Primary True +17:38:12.470 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +17:38:12.506 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +17:38:12.542 Park/Unpark INFO Tests skipped +17:38:12.564 AbortSlew OK AbortSlew OK when not slewing +17:38:12.631 AxisRate:Primary OK Empty axis rate returned +17:38:12.648 AxisRate:Primary OK Disposed axis rates OK +17:38:12.665 AxisRate:Secondary OK Empty axis rate returned +17:38:12.679 AxisRate:Secondary OK Disposed axis rates OK +17:38:12.693 AxisRate:Tertiary OK Empty axis rate returned +17:38:12.710 AxisRate:Tertiary OK Disposed axis rates OK +17:38:12.729 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +17:38:12.781 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +17:38:12.795 MoveAxis Primary OK AxisRates object successfully disposed +17:38:12.853 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +17:38:12.866 MoveAxis Secondary OK AxisRates object successfully disposed +17:38:12.924 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +17:38:12.961 PulseGuide ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException +17:38:13.038 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:13.093 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.139 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.203 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.247 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.338 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:13.377 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.419 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.479 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.520 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.623 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:13.665 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.715 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.776 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.820 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:13.879 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:13.896 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:13.938 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:13.977 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:13.993 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:14.010 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +17:38:14.080 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.095 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.112 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.152 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.195 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.255 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.299 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.391 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.408 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.428 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.469 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.526 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.588 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.634 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.696 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +17:38:14.717 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.762 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:14.781 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:14.844 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:14.862 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:14.926 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:14.967 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:14.988 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:15.050 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:15.070 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +17:38:15.183 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:15.227 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:15.270 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:15.331 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:15.376 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +17:38:15.438 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -00:17:22.735 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +17:38:15.513 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -00:17:22.828 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +17:38:15.611 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 1f620e9..7df3662 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -210,15 +210,18 @@ namespace ASCOM.MeadeAutostar497.Controller if (longitude.Length == 9) l = l + double.Parse(longitude.Substring(7, 2)) / 60 / 60; + if (l > 180) + l = l - 360; + return l; } set { - if (value >= 360) - throw new ASCOM.InvalidValueException("Longitude cannot be greater than or equal to 360 degrees."); + if (value > 180) + throw new ASCOM.InvalidValueException("Longitude cannot be greater than 180 degrees."); - if (value < 0) - throw new ASCOM.InvalidValueException("Longitude cannot be lower than 0 degrees."); + if (value < -180) + throw new ASCOM.InvalidValueException("Longitude cannot be lower than -180 degrees."); int d = Convert.ToInt32(Math.Floor(value)); int m = Convert.ToInt32(60 * (value - d)); From 0d04ecd5873a52a14ca32a01933db862c0d6bf7f Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 1 May 2019 22:43:59 +0100 Subject: [PATCH 010/109] Added support for UTC offset. --- .../TelescopeControllerUnitTests.cs | 16 ++++++++++++---- .../Controller/TelescopeController.cs | 19 ++++++++++++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index a1d20b4..600b538 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -32,6 +32,7 @@ namespace MeadeAutostar497.UnitTests serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); _telescopeController = TelescopeController.Instance; + _telescopeController.Connected = false; _telescopeController.SerialPort = serialMock.Object; } @@ -195,7 +196,7 @@ namespace MeadeAutostar497.UnitTests [Test] public void utcDate_Get_ReturnsExpectedValue() { - DateTime expectedDate = new DateTime(2019, 04, 30, 12, 32, 24, DateTimeKind.Utc); + DateTime expectedDate = new DateTime(2019, 04, 30, 11, 32, 24, DateTimeKind.Local); var dateString = "04/30/19"; var timeString = "12:32:24"; @@ -204,6 +205,7 @@ namespace MeadeAutostar497.UnitTests _telescopeController.Connected = true; + serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); serialMock.Setup(x => x.CommandTerminated(":GC#", "#")).Returns(dateString); serialMock.Setup(x => x.CommandTerminated(":GL#", "#")).Returns(timeString); @@ -216,7 +218,9 @@ namespace MeadeAutostar497.UnitTests public void utcDate_Set_SetsTelescopeDateAndTime() { DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); - serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); + + serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); + serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour+1:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); _isConnected = true; @@ -230,6 +234,8 @@ namespace MeadeAutostar497.UnitTests public void utcDate_Set_ThrowsExceptionWhenTimeInvalid() { DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); + + serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); //serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); @@ -245,8 +251,10 @@ namespace MeadeAutostar497.UnitTests [Test] public void utcDate_Set_ThrowsExceptionWhenDateInvalid() { - DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); - serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); + DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Local); + + serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); + serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour+1:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); //serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); _isConnected = true; diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 7df3662..b35089c 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -131,15 +131,20 @@ namespace ASCOM.MeadeAutostar497.Controller int minute = telescopeTime.Substring(3, 2).ToInteger(); int second = telescopeTime.Substring(6, 2).ToInteger(); + var utcCorrection = GetUtcCorrection(); + //Todo is this telescope local time, or real utc? - var newDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + var newDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + utcCorrection; return newDate; } set { + var utcCorrection = GetUtcCorrection(); + var localDateTime = value - utcCorrection; + //Todo is this telescope local time, or real utc? - var timeResult = SerialPort.CommandChar($":SL{value:HH:mm:ss}#"); + var timeResult = SerialPort.CommandChar($":SL{localDateTime:HH:mm:ss}#"); if (timeResult != '1') { throw new InvalidOperationException("Failed to set local time"); @@ -148,7 +153,7 @@ namespace ASCOM.MeadeAutostar497.Controller SerialPort.Lock(); try { - var dateResult = SerialPort.CommandChar($":SC{value:MM/dd/yy}#"); + var dateResult = SerialPort.CommandChar($":SC{localDateTime:MM/dd/yy}#"); if (dateResult != '1') { throw new InvalidOperationException("Failed to set local date"); @@ -166,6 +171,14 @@ namespace ASCOM.MeadeAutostar497.Controller } + private TimeSpan GetUtcCorrection() + { + string utcOffSet = SerialPort.CommandTerminated(":GG#", "#"); + double utcOffsetHours = double.Parse(utcOffSet); + TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); + return utcCorrection; + } + public double SiteLatitude { get From 9e4c7862f9f6211ec50182d0851914b7bff7c723 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 00:31:54 +0100 Subject: [PATCH 011/109] Pulse guiding support added --- ConformanceResult.txt | 340 +++++++++--------- MeadeAutostar497/AscomClasses/Telescope.cs | 9 +- .../Controller/ITelescopeController.cs | 2 + .../Controller/TelescopeController.cs | 41 +++ TestConsole/Program.cs | 5 +- 5 files changed, 220 insertions(+), 177 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index ef58bd0..b3e4d88 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -15,192 +15,192 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -17:38:04.254 Driver Access Checks OK -17:38:04.900 AccessChecks OK Successfully created driver using late binding -17:38:05.127 AccessChecks OK Successfully connected using late binding -17:38:05.132 AccessChecks INFO The driver is a .NET object -17:38:05.137 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -17:38:05.142 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -17:38:05.839 AccessChecks INFO Device does not expose interface ITelescopeV2 -17:38:06.643 AccessChecks INFO Device exposes interface ITelescopeV3 -17:38:07.961 AccessChecks OK Successfully created driver using driver access toolkit -17:38:08.125 AccessChecks OK Successfully connected using driver access toolkit +00:25:26.447 Driver Access Checks OK +00:25:27.090 AccessChecks OK Successfully created driver using late binding +00:25:27.323 AccessChecks OK Successfully connected using late binding +00:25:27.327 AccessChecks INFO The driver is a .NET object +00:25:27.332 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +00:25:27.336 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +00:25:28.025 AccessChecks INFO Device does not expose interface ITelescopeV2 +00:25:28.830 AccessChecks INFO Device exposes interface ITelescopeV3 +00:25:30.141 AccessChecks OK Successfully created driver using driver access toolkit +00:25:30.312 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -17:38:09.448 ConformanceCheck OK Driver instance created successfully -17:38:09.659 ConformanceCheck OK Connected OK +00:25:31.632 ConformanceCheck OK Driver instance created successfully +00:25:31.848 ConformanceCheck OK Connected OK Common Driver Methods -17:38:09.700 InterfaceVersion OK 3 -17:38:09.728 Connected OK True -17:38:09.757 Description OK Meade Autostar 497 .net -17:38:09.787 DriverInfo OK Information about the driver itself. Version: 0.0 -17:38:09.816 DriverVersion OK 0.0 -17:38:09.846 Name OK Meade Autostar 497 .net -17:38:09.875 CommandString INFO Conform cannot test the CommandString method -17:38:09.881 CommandBlind INFO Conform cannot test the CommandBlind method -17:38:09.888 CommandBool INFO Conform cannot test the CommandBool method -17:38:09.894 Action INFO Conform cannot test the Action method -17:38:09.900 SupportedActions OK Driver returned an empty action list +00:25:31.890 InterfaceVersion OK 3 +00:25:31.917 Connected OK True +00:25:31.945 Description OK Meade Autostar 497 .net +00:25:31.974 DriverInfo OK Information about the driver itself. Version: 0.0 +00:25:32.004 DriverVersion OK 0.0 +00:25:32.032 Name OK Meade Autostar 497 .net +00:25:32.060 CommandString INFO Conform cannot test the CommandString method +00:25:32.066 CommandBlind INFO Conform cannot test the CommandBlind method +00:25:32.072 CommandBool INFO Conform cannot test the CommandBool method +00:25:32.078 Action INFO Conform cannot test the Action method +00:25:32.085 SupportedActions OK Driver returned an empty action list Can Properties -17:38:09.968 CanFindHome OK False -17:38:09.975 CanPark OK True -17:38:09.982 CanPulseGuide OK True -17:38:09.989 CanSetDeclinationRate OK False -17:38:09.995 CanSetGuideRates OK False -17:38:10.002 CanSetPark OK False -17:38:10.009 CanSetPierSide OK False -17:38:10.022 CanSetRightAscensionRate OK False -17:38:10.030 CanSetTracking OK False -17:38:10.038 CanSlew OK True -17:38:10.045 CanSlewltAz OK True -17:38:10.052 CanSlewAltAzAsync OK True -17:38:10.060 CanSlewAsync OK True -17:38:10.067 CanSync OK True -17:38:10.075 CanSyncAltAz OK False -17:38:10.083 CanUnPark OK False +00:25:32.153 CanFindHome OK False +00:25:32.161 CanPark OK True +00:25:32.169 CanPulseGuide OK True +00:25:32.177 CanSetDeclinationRate OK False +00:25:32.185 CanSetGuideRates OK False +00:25:32.193 CanSetPark OK False +00:25:32.204 CanSetPierSide OK False +00:25:32.218 CanSetRightAscensionRate OK False +00:25:32.227 CanSetTracking OK False +00:25:32.237 CanSlew OK True +00:25:32.247 CanSlewltAz OK True +00:25:32.256 CanSlewAltAzAsync OK True +00:25:32.266 CanSlewAsync OK True +00:25:32.275 CanSync OK True +00:25:32.284 CanSyncAltAz OK False +00:25:32.293 CanUnPark OK False Pre-run Checks -17:38:10.130 Mount Safety INFO Scope is not parked, continuing testing -17:38:10.183 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -17:38:10.192 TimeCheck INFO PC UTCDate: 01-May-2019 16:38:10.192 -17:38:10.284 TimeCheck INFO Mount UTCDate: 01-May-2019 20:02:19.000 +00:25:32.342 Mount Safety INFO Scope is not parked, continuing testing +00:25:32.393 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +00:25:32.401 TimeCheck INFO PC UTCDate: 01-May-2019 23:25:32.401 +00:25:32.579 TimeCheck INFO Mount UTCDate: 01-May-2019 19:00:43.000 Properties -17:38:10.356 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.392 Altitude OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.423 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.456 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.487 AtHome OK False -17:38:10.523 AtPark OK False -17:38:10.558 Azimuth OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.593 Declination OK 00:00:00.00 -17:38:10.626 DeclinationRate Read OK 0.00 -17:38:10.660 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -17:38:10.694 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.726 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.759 EquatorialSystem OK equLocalTopocentric -17:38:10.792 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.824 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.836 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -17:38:10.871 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:10.885 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -17:38:10.922 IsPulseGuiding ISSUE CanPulseGuide is True and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:10.956 RightAscension OK 00:00:00.00 -17:38:10.990 RightAscensionRate Read OK 0.00 -17:38:11.024 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -17:38:11.058 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.093 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.105 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.117 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.173 SiteLatitude Read OK 00:00:00.00 -17:38:11.214 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -17:38:11.231 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -17:38:11.264 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -17:38:11.324 SiteLongitude Read OK 01:46:00.00 -17:38:11.363 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -17:38:11.378 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -17:38:11.417 SiteLongitude Write OK Legal value 01:46:00.00 degrees written successfully -17:38:11.458 Slewing OK False -17:38:11.493 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.529 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.541 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.578 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.642 SiderealTime OK 07:22:31.69 -17:38:11.655 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 07:22:31.69, ASCOM: 07:22:32.79 -17:38:11.694 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.731 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -17:38:11.744 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -17:38:11.779 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -17:38:11.791 Tracking Read OK True -17:38:11.829 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -17:38:11.870 TrackingRates Found drive rate: driveSidereal -17:38:11.882 TrackingRates OK Drive rates read OK -17:38:11.894 TrackingRates OK Disposed tracking rates OK -17:38:11.933 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -17:38:11.947 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -17:38:12.025 UTCDate Read OK 01-May-2019 20:02:21.000 -17:38:12.196 UTCDate Write OK New UTCDate written successfully: 01/05/2019 21:02:21 +00:25:32.654 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. +00:25:32.688 Altitude OK Optional member threw a PropertyNotImplementedException exception. +00:25:32.720 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +00:25:32.752 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +00:25:32.784 AtHome OK False +00:25:32.831 AtPark OK False +00:25:32.862 Azimuth OK Optional member threw a PropertyNotImplementedException exception. +00:25:32.895 Declination OK 00:00:00.00 +00:25:32.926 DeclinationRate Read OK 0.00 +00:25:32.958 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +00:25:32.990 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.022 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.055 EquatorialSystem OK equLocalTopocentric +00:25:33.087 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.120 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.132 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +00:25:33.165 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.176 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +00:25:33.209 IsPulseGuiding OK False +00:25:33.242 RightAscension OK 00:00:00.00 +00:25:33.277 RightAscensionRate Read OK 0.00 +00:25:33.311 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +00:25:33.345 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.380 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.391 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.403 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.461 SiteLatitude Read OK 00:00:00.00 +00:25:33.499 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +00:25:33.511 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +00:25:33.545 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +00:25:33.600 SiteLongitude Read OK -03:48:00.00 +00:25:33.635 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +00:25:33.647 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +00:25:33.737 SiteLongitude Write OK Legal value -03:48:00.00 degrees written successfully +00:25:33.778 Slewing OK False +00:25:33.812 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.847 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.859 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.894 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:33.944 SiderealTime OK 13:47:08.92 +00:25:33.966 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 13:47:08.92, ASCOM: 13:48:46.01 +00:25:34.000 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:34.035 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +00:25:34.052 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +00:25:34.089 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +00:25:34.101 Tracking Read OK True +00:25:34.135 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +00:25:34.180 TrackingRates Found drive rate: driveSidereal +00:25:34.192 TrackingRates OK Drive rates read OK +00:25:34.205 TrackingRates OK Disposed tracking rates OK +00:25:34.241 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +00:25:34.257 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +00:25:34.347 UTCDate Read OK 01-May-2019 19:00:45.000 +00:25:34.586 UTCDate Write OK New UTCDate written successfully: 01/05/2019 20:00:45 Methods -17:38:12.430 CanMoveAxis:Primary OK CanMoveAxis:Primary True -17:38:12.470 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -17:38:12.506 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -17:38:12.542 Park/Unpark INFO Tests skipped -17:38:12.564 AbortSlew OK AbortSlew OK when not slewing -17:38:12.631 AxisRate:Primary OK Empty axis rate returned -17:38:12.648 AxisRate:Primary OK Disposed axis rates OK -17:38:12.665 AxisRate:Secondary OK Empty axis rate returned -17:38:12.679 AxisRate:Secondary OK Disposed axis rates OK -17:38:12.693 AxisRate:Tertiary OK Empty axis rate returned -17:38:12.710 AxisRate:Tertiary OK Disposed axis rates OK -17:38:12.729 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -17:38:12.781 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -17:38:12.795 MoveAxis Primary OK AxisRates object successfully disposed -17:38:12.853 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -17:38:12.866 MoveAxis Secondary OK AxisRates object successfully disposed -17:38:12.924 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -17:38:12.961 PulseGuide ISSUE Received a PropertyNotImplementedException instead of a MethodNotImplementedException -17:38:13.038 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:13.093 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.139 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.203 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.247 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.338 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:13.377 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.419 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.479 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.520 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.623 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:13.665 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.715 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.776 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.820 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:13.879 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:13.896 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:13.938 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:13.977 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:13.993 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:14.010 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -17:38:14.080 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.095 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.112 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.152 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.195 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.255 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.299 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.391 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.408 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.428 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.469 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.526 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.588 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.634 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.696 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -17:38:14.717 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.762 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:14.781 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:14.844 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:14.862 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:14.926 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:14.967 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:14.988 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:15.050 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:15.070 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -17:38:15.183 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:15.227 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:15.270 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:15.331 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:15.376 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -17:38:15.438 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +00:25:34.827 CanMoveAxis:Primary OK CanMoveAxis:Primary True +00:25:34.863 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +00:25:34.899 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +00:25:34.934 Park/Unpark INFO Tests skipped +00:25:34.956 AbortSlew OK AbortSlew OK when not slewing +00:25:35.021 AxisRate:Primary OK Empty axis rate returned +00:25:35.033 AxisRate:Primary OK Disposed axis rates OK +00:25:35.045 AxisRate:Secondary OK Empty axis rate returned +00:25:35.059 AxisRate:Secondary OK Disposed axis rates OK +00:25:35.072 AxisRate:Tertiary OK Empty axis rate returned +00:25:35.084 AxisRate:Tertiary OK Disposed axis rates OK +00:25:35.099 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +00:25:35.150 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +00:25:35.163 MoveAxis Primary OK AxisRates object successfully disposed +00:25:35.221 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +00:25:35.234 MoveAxis Secondary OK AxisRates object successfully disposed +00:25:35.293 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +00:25:37.331 PulseGuide OK Synchronous pulse guide found OK +00:25:37.428 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:37.477 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.521 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.581 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.626 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.713 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:37.751 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.795 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.855 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.898 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:37.999 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.037 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:38.079 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:38.139 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:38.185 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:38.243 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.259 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.300 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.341 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.357 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.373 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +00:25:38.497 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.513 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.531 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.569 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.611 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.670 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.716 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.809 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.823 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.843 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.883 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.930 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:38.990 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.031 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +00:25:39.110 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.151 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.172 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.234 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.254 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.316 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.357 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.375 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.439 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.456 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +00:25:39.545 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.585 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.630 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.690 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.734 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +00:25:39.796 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -17:38:15.513 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +00:25:39.866 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -17:38:15.611 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +00:25:39.960 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 0 errors, 2 warnings and 47 issues +Your driver had 0 errors, 2 warnings and 45 issues diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index d3d2113..f15e767 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -620,8 +620,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("IsPulseGuiding Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); + tl.LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); + //throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); + return false; } } @@ -639,8 +640,8 @@ namespace ASCOM.MeadeAutostar497 public void PulseGuide(GuideDirections Direction, int Duration) { - tl.LogMessage("PulseGuide", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("PulseGuide"); + tl.LogMessage("PulseGuide", $"pulse guide direction {Direction} duration {Duration}"); + _telescopeController.PulseGuide(Direction, Duration); } public double RightAscension diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 32bde77..a4f26d2 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -1,4 +1,5 @@ using System; +using ASCOM.DeviceInterface; namespace ASCOM.MeadeAutostar497.Controller { @@ -12,5 +13,6 @@ namespace ASCOM.MeadeAutostar497.Controller double SiteLatitude { get; set; } double SiteLongitude { get; set; } void AbortSlew(); + void PulseGuide(GuideDirections direction, int duration); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index b35089c..0568b42 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -1,6 +1,8 @@ using System; using System.IO.Ports; using System.Linq; +using System.Threading; +using ASCOM.DeviceInterface; namespace ASCOM.MeadeAutostar497.Controller { @@ -250,5 +252,44 @@ namespace ASCOM.MeadeAutostar497.Controller { SerialPort.Command("#:Q#"); } + + public void PulseGuide(GuideDirections direction, int duration) + { + string d = string.Empty; + switch (direction) + { + case GuideDirections.guideEast: + d = "e"; + break; + case GuideDirections.guideNorth: + d = "n"; + break; + case GuideDirections.guideSouth: + d = "s"; + break; + case GuideDirections.guideWest: + d = "w"; + break; + } + + if (UserNewerPulseGuiding) + { + _serialPort.Command($":Mg{d}{duration:0000}#"); + Thread.Sleep(duration); + } + else + { + _serialPort.Command(":RG#"); //Make sure we are at guide rate + _serialPort.Command($":M{d}#"); + Thread.Sleep(duration); + _serialPort.Command($":Q{d}#"); + + //classic only !!!, this is needed since once in a while one is not enough + Thread.Sleep(200); + _serialPort.Command($":Q{d}#"); + } + } + + public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting } } diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index 560918a..a6cbae5 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -43,9 +43,8 @@ namespace ASCOM //Console.WriteLine(device.Slewing); - //device.UTCDate = DateTime.UtcNow; - - //Console.WriteLine(device.UTCDate); + Console.WriteLine(device.UTCDate); + device.UTCDate = DateTime.UtcNow; double l = device.SiteLatitude; device.SiteLatitude = l; From c2ecb1891c19aa6497ed0b029bb9b6993e8e1d7d Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 12:50:22 +0100 Subject: [PATCH 012/109] Added SiteLatitude unit tests --- .../TelescopeControllerUnitTests.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 600b538..3f48324 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO.Ports; +using ASCOM; using ASCOM.MeadeAutostar497.Controller; using Moq; using NUnit.Framework; @@ -265,5 +266,69 @@ namespace MeadeAutostar497.UnitTests Assert.That(exception.Message, Is.EqualTo("Failed to set local date")); } + + [TestCase("+12:34", 12.566666666666666)] + [TestCase("+12:34.56", 12.582222222222223)] + [TestCase("-67:34.56", -67.582222222222214)] + public void SiteLatitude_Get_ReturnsExpectedDouble( string latitude, double expectedResult) + { + serialMock.Setup(x => x.CommandTerminated(":Gt#", "#")).Returns(latitude); + + _isConnected = true; + + _telescopeController.Connected = true; + + var result = _telescopeController.SiteLatitude; + + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [Test] + public void SiteLatitude_Set_ThrowsExeptionWhenValueTooSmall() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws( () => { _telescopeController.SiteLatitude = -91;}); + + Assert.That(exception.Message, Is.EqualTo("Latitude cannot be less than -90 degrees.")); + } + + [Test] + public void SiteLatitude_Set_ThrowsExeptionWhenValueTooLarge() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 91; }); + + Assert.That(exception.Message, Is.EqualTo("Latitude cannot be greater than 90 degrees.")); + } + + [Test] + public void SiteLatitude_Set_ThrowsExeptionWhenTelescopeReportsFail() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 10; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to set site latitude.")); + } + + [Test] + public void SiteLatitude_Set_NoErrorWhenValidValueSentSuccessfully() + { + serialMock.Setup(x => x.CommandChar(":Sts10*00#")).Returns('1'); + + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.SiteLatitude = 10; + } } } From d1b3f5718f1024df4e2a4b2d18ad1c037f4e7098 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 13:00:52 +0100 Subject: [PATCH 013/109] Added unit tests for SiteLongitude --- .../TelescopeControllerUnitTests.cs | 73 ++++++++++++++++++- .../Controller/TelescopeController.cs | 2 +- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 3f48324..c47b9ef 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -267,9 +267,9 @@ namespace MeadeAutostar497.UnitTests Assert.That(exception.Message, Is.EqualTo("Failed to set local date")); } - [TestCase("+12:34", 12.566666666666666)] - [TestCase("+12:34.56", 12.582222222222223)] - [TestCase("-67:34.56", -67.582222222222214)] + [TestCase("+12*34", 12.566666666666666)] + [TestCase("+12*34.56", 12.582222222222223)] + [TestCase("-67*34.56", -67.582222222222214)] public void SiteLatitude_Get_ReturnsExpectedDouble( string latitude, double expectedResult) { serialMock.Setup(x => x.CommandTerminated(":Gt#", "#")).Returns(latitude); @@ -330,5 +330,72 @@ namespace MeadeAutostar497.UnitTests _telescopeController.SiteLatitude = 10; } + + + [TestCase("012*34", 12.566666666666666)] + [TestCase("012:34.56", 12.582222222222223)] + [TestCase("350:34.56", -9.4177777777777578)] + public void SiteLongitude_Get_ReturnsExpectedDouble(string longitude, double expectedResult) + { + serialMock.Setup(x => x.CommandTerminated(":Gg#", "#")).Returns(longitude); + + _isConnected = true; + + _telescopeController.Connected = true; + + var result = _telescopeController.SiteLongitude; + + Assert.That(result, Is.EqualTo(expectedResult)); + } + + [Test] + public void SiteLongitude_Set_ThrowsExeptionWhenValueTooSmall() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = -181; }); + + Assert.That(exception.Message, Is.EqualTo("Longitude cannot be lower than -180 degrees.")); + } + + [Test] + public void SiteLongitude_Set_ThrowsExeptionWhenValueTooLarge() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 181; }); + + Assert.That(exception.Message, Is.EqualTo("Longitude cannot be greater than 180 degrees.")); + } + + [Test] + public void SiteLongitude_Set_ThrowsExeptionWhenTelescopeReportsFail() + { + _isConnected = true; + + _telescopeController.Connected = true; + + var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 10; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to set site longitude.")); + } + + + + [Test] + public void SiteLongitude_Set_NoErrorWhenValidValueSentSuccessfully() + { + serialMock.Setup(x => x.CommandChar(":Sg010*00#")).Returns('1'); + + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.SiteLongitude = 10; + } } } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 0568b42..76569ae 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -243,7 +243,7 @@ namespace ASCOM.MeadeAutostar497.Controller var result = SerialPort.CommandChar($":Sg{d:000}*{m:00}#"); if (result != '1') - throw new InvalidOperationException("Failed to set site Longitude."); + throw new InvalidOperationException("Failed to set site longitude."); } } From d2fae7607bafd94a98c7836c04cb2b92e57f6cc2 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 13:10:40 +0100 Subject: [PATCH 014/109] Added unit tests for the new Pulse guide implementation. --- .../TelescopeControllerUnitTests.cs | 51 ++++++++++++++++++- .../Controller/TelescopeController.cs | 2 +- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index c47b9ef..dd5ec24 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO.Ports; using ASCOM; +using ASCOM.DeviceInterface; using ASCOM.MeadeAutostar497.Controller; using Moq; using NUnit.Framework; @@ -384,8 +385,6 @@ namespace MeadeAutostar497.UnitTests Assert.That(exception.Message, Is.EqualTo("Failed to set site longitude.")); } - - [Test] public void SiteLongitude_Set_NoErrorWhenValidValueSentSuccessfully() { @@ -397,5 +396,53 @@ namespace MeadeAutostar497.UnitTests _telescopeController.SiteLongitude = 10; } + + [Test] + public void PulseGuideEast() + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.PulseGuide(GuideDirections.guideEast,100); + + serialMock.Verify( x => x.Command(":Mge0100#"), Times.Once); + } + + [Test] + public void PulseGuideWest() + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.PulseGuide(GuideDirections.guideWest, 1200); + + serialMock.Verify(x => x.Command(":Mgw1200#"), Times.Once); + } + + [Test] + public void PulseGuideNorth() + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.PulseGuide(GuideDirections.guideNorth, 256); + + serialMock.Verify(x => x.Command(":Mgn0256#"), Times.Once); + } + + [Test] + public void PulseGuideSouth() + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.PulseGuide(GuideDirections.guideSouth, 1024); + + serialMock.Verify(x => x.Command(":Mgs1024#"), Times.Once); + } } } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 76569ae..8fd7d7c 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -275,7 +275,7 @@ namespace ASCOM.MeadeAutostar497.Controller if (UserNewerPulseGuiding) { _serialPort.Command($":Mg{d}{duration:0000}#"); - Thread.Sleep(duration); + Thread.Sleep(duration); //todo figure out if this is really needed } else { From 7225c2d70f7975346fd63921f4590cb6df6737e4 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 14:05:23 +0100 Subject: [PATCH 015/109] Added support for AlignmentMode --- .../TelescopeControllerUnitTests.cs | 30 +++++++++++++ MeadeAutostar497/AscomClasses/Telescope.cs | 2 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 45 +++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index dd5ec24..27ccfa4 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -444,5 +444,35 @@ namespace MeadeAutostar497.UnitTests serialMock.Verify(x => x.Command(":Mgs1024#"), Times.Once); } + + [TestCase("AT0", AlignmentModes.algAltAz)] + [TestCase("PT0", AlignmentModes.algPolar)] + [TestCase("GT0", AlignmentModes.algGermanPolar)] + public void AlignmentMode_Get_ReturnsExpectedValue(string commandResponse, AlignmentModes mode) + { + serialMock.Setup(x => x.CommandTerminated(":GW#", "#")).Returns(commandResponse); + + _isConnected = true; + + _telescopeController.Connected = true; + + var result = _telescopeController.AlignmentMode; + + Assert.That(result, Is.EqualTo(mode)); + } + + [TestCase(AlignmentModes.algAltAz, ":AA#")] + [TestCase(AlignmentModes.algPolar, ":AP#")] + [TestCase(AlignmentModes.algGermanPolar, ":AP#")] + public void AligmentMode_Set_WorksAsExpected(AlignmentModes mode, string command) + { + _isConnected = true; + + _telescopeController.Connected = true; + + _telescopeController.AlignmentMode = mode; + + serialMock.Verify( x => x.Command(command), Times.Once); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index f15e767..8b4de2e 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -298,7 +298,7 @@ namespace ASCOM.MeadeAutostar497 get { tl.LogMessage("AlignmentMode Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("AlignmentMode", false); + return _telescopeController.AlignmentMode; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index a4f26d2..893c470 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -12,6 +12,7 @@ namespace ASCOM.MeadeAutostar497.Controller DateTime utcDate { get; set; } double SiteLatitude { get; set; } double SiteLongitude { get; set; } + AlignmentModes AlignmentMode { get; set; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 8fd7d7c..44a67d8 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -6,6 +6,7 @@ using ASCOM.DeviceInterface; namespace ASCOM.MeadeAutostar497.Controller { + //todo stop this being a singleton, and instead use a server to make only a single instance. public sealed class TelescopeController : ITelescopeController { private static readonly Lazy lazy = new Lazy(); @@ -248,6 +249,50 @@ namespace ASCOM.MeadeAutostar497.Controller } + public AlignmentModes AlignmentMode + { + get + { + var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + + switch (alignmentString[0]) + { + case 'A': return AlignmentModes.algAltAz; + case 'P': return AlignmentModes.algPolar; + case 'G': return AlignmentModes.algGermanPolar; + default: + throw new ASCOM.InvalidValueException($"unknown alignment returned from telescope: {alignmentString[0]}"); + } + //:GW# Get Scope Alignment Status + //Returns: # + // where: + //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial + //tracking: T - tracking, N - not tracking + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + } + set + { + switch (value) + { + case AlignmentModes.algAltAz: SerialPort.Command(":AA#"); + break; + case AlignmentModes.algPolar: + case AlignmentModes.algGermanPolar: + SerialPort.Command(":AP#"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + + //:AL# Sets telescope to Land alignment mode + //Returns: nothing + //:AP# Sets telescope to Polar alignment mode + //Returns: nothing + //:AA# Sets telescope the AltAz alignment mode + //Returns: nothing + } + } + public void AbortSlew() { SerialPort.Command("#:Q#"); From 76c88420caebab3fdf731855ad9166606fe326b9 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 15:14:36 +0100 Subject: [PATCH 016/109] Added support for AtPark and Park --- .../TelescopeControllerUnitTests.cs | 48 +++++++++++++++++++ MeadeAutostar497/AscomClasses/Telescope.cs | 9 ++-- .../Controller/ITelescopeController.cs | 2 + .../Controller/TelescopeController.cs | 13 +++++ 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 27ccfa4..15df4bd 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Configuration; using System.IO.Ports; using ASCOM; using ASCOM.DeviceInterface; @@ -33,6 +34,8 @@ namespace MeadeAutostar497.UnitTests serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())).Returns(() => _stringToRecieve); serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); + //Todo inject the serialMock instead of using a singleton to increase code stability. + _telescopeController = TelescopeController.Instance; _telescopeController.Connected = false; _telescopeController.SerialPort = serialMock.Object; @@ -474,5 +477,50 @@ namespace MeadeAutostar497.UnitTests serialMock.Verify( x => x.Command(command), Times.Once); } + + [Test] + public void AtParkIsFalseByDefault() + { + _isConnected = true; + + _telescopeController.Connected = true; + + Assert.That( _telescopeController.AtPark, Is.False ); + } + + [Test] + public void AtParkIsTrueAfterParkingScope() + { + _isConnected = true; + + _telescopeController.Connected = true; + _telescopeController.Park(); + + Assert.That(_telescopeController.AtPark, Is.True); + } + + [Test] + public void Park_CallingParkSendsTheParkCommand() + { + _isConnected = true; + + _telescopeController.Connected = true; + _telescopeController.Park(); + + serialMock.Verify( x => x.Command(":hP#"), Times.Once); + } + + [Test] + public void Park_ParkingSecondTimeDoesNothing() + { + _isConnected = true; + + _telescopeController.Connected = true; + _telescopeController.Park(); + + _telescopeController.Park(); + + serialMock.Verify(x => x.Command(":hP#"), Times.Once); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 8b4de2e..e6d0cfb 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -342,8 +342,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("AtPark", "Get - " + false.ToString()); - return false; + var atPatk = _telescopeController.AtPark; + tl.LogMessage("AtPark", "Get - " + atPatk.ToString()); + return atPatk; } } @@ -634,8 +635,8 @@ namespace ASCOM.MeadeAutostar497 public void Park() { - tl.LogMessage("Park", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("Park"); + tl.LogMessage("Park", "Parking telescope"); + _telescopeController.Park(); } public void PulseGuide(GuideDirections Direction, int Duration) diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 893c470..06f1d5a 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -13,7 +13,9 @@ namespace ASCOM.MeadeAutostar497.Controller double SiteLatitude { get; set; } double SiteLongitude { get; set; } AlignmentModes AlignmentMode { get; set; } + bool AtPark { get; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); + void Park(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 44a67d8..051c5d9 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -293,6 +293,10 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private bool _parked = false; + + public bool AtPark => _parked; + public void AbortSlew() { SerialPort.Command("#:Q#"); @@ -335,6 +339,15 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public void Park() + { + if (_parked) + return; + + _parked = true; + _serialPort.Command(":hP#"); + } + public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting } } From c0c0bedbbaf9266c6cae0790891c75da1919449f Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 16:03:24 +0100 Subject: [PATCH 017/109] Added support for parking the scope Added support for reading the scope Azimuth --- .../TelescopeControllerUnitTests.cs | 38 +++++++++---- MeadeAutostar497/AscomClasses/Telescope.cs | 5 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 57 +++++++++++++------ 4 files changed, 71 insertions(+), 30 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index 15df4bd..c5e8fe7 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -7,7 +7,6 @@ using ASCOM.DeviceInterface; using ASCOM.MeadeAutostar497.Controller; using Moq; using NUnit.Framework; -using InvalidOperationException = ASCOM.InvalidOperationException; namespace MeadeAutostar497.UnitTests { @@ -30,20 +29,21 @@ namespace MeadeAutostar497.UnitTests serialMock = new Mock(); serialMock.SetupAllProperties(); - serialMock.Setup(x => x.GetPortNames()).Returns( () => _availableComPorts.ToArray()); - serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())).Returns(() => _stringToRecieve); + serialMock.Setup(x => x.GetPortNames()).Returns(() => _availableComPorts.ToArray()); + serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())) + .Returns(() => _stringToRecieve); serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); //Todo inject the serialMock instead of using a singleton to increase code stability. - _telescopeController = TelescopeController.Instance; - _telescopeController.Connected = false; _telescopeController.SerialPort = serialMock.Object; } [TearDown] public void TearDown() { + _isConnected = false; + _telescopeController.Connected = false; _telescopeController.Port = "COM1"; } @@ -97,7 +97,7 @@ namespace MeadeAutostar497.UnitTests public void WhenOpensComPortToNonAutostarThrowException() { Assert.That(serialMock.Object.IsOpen, Is.False); - var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); + var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); Assert.That(exception.Message, Is.EqualTo("Failed to communicate with telescope.")); @@ -114,7 +114,7 @@ namespace MeadeAutostar497.UnitTests Mock newSerialMock = new Mock(); - var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); + var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); Assert.That(exception, Is.Not.Null); Assert.That(exception.Message, Is.EqualTo("Please disconnect before changing the serial engine.")); @@ -141,7 +141,7 @@ namespace MeadeAutostar497.UnitTests _isConnected = true; _telescopeController.Connected = true; - var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); + var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); Assert.That(exception.Message, Is.EqualTo("Please disconnect from the scope before changing port.")); @@ -151,7 +151,7 @@ namespace MeadeAutostar497.UnitTests [Test] public void SettingPortToInvalidPortFails() { - var exception = Assert.Throws(() => _telescopeController.Port = "COM5"); + var exception = Assert.Throws(() => _telescopeController.Port = "COM5"); Assert.That(exception.Message, Is.EqualTo("Unable to select port COM5 as it does not exist.")); @@ -318,7 +318,7 @@ namespace MeadeAutostar497.UnitTests _telescopeController.Connected = true; - var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 10; }); + var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 10; }); Assert.That(exception.Message, Is.EqualTo("Failed to set site latitude.")); } @@ -383,7 +383,7 @@ namespace MeadeAutostar497.UnitTests _telescopeController.Connected = true; - var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 10; }); + var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 10; }); Assert.That(exception.Message, Is.EqualTo("Failed to set site longitude.")); } @@ -482,7 +482,6 @@ namespace MeadeAutostar497.UnitTests public void AtParkIsFalseByDefault() { _isConnected = true; - _telescopeController.Connected = true; Assert.That( _telescopeController.AtPark, Is.False ); @@ -522,5 +521,20 @@ namespace MeadeAutostar497.UnitTests serialMock.Verify(x => x.Command(":hP#"), Times.Once); } + + [TestCase("356*13",356.21666666666664)] + [TestCase("356*13'21", 356.22249999999997)] + public void Azimuth_CanGetValue( string response, double expectedResult ) + { + serialMock.Setup(x => x.CommandTerminated(":GZ#", "#")).Returns(response); + + _isConnected = true; + + _telescopeController.Connected = true; + + var az = _telescopeController.Azimuth; + + Assert.That( az, Is.EqualTo(expectedResult)); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index e6d0cfb..dbff572 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -358,8 +358,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("Azimuth Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Azimuth", false); + var az = _telescopeController.Azimuth; + tl.LogMessage("Azimuth Get", $"{az}"); + return az; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 06f1d5a..a8f7de8 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -14,6 +14,7 @@ namespace ASCOM.MeadeAutostar497.Controller double SiteLongitude { get; set; } AlignmentModes AlignmentMode { get; set; } bool AtPark { get; } + double Azimuth { get; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 051c5d9..d85f038 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -13,6 +13,7 @@ namespace ASCOM.MeadeAutostar497.Controller public static TelescopeController Instance => lazy.Value; + //todo remove this as it can cause problems in production private ISerialProcessor _serialPort; public ISerialProcessor SerialPort { @@ -68,6 +69,7 @@ namespace ASCOM.MeadeAutostar497.Controller //Connecting try { + _parked = false; SerialPort.DtrEnable = false; SerialPort.RtsEnable = false; SerialPort.BaudRate = 9600; @@ -90,6 +92,7 @@ namespace ASCOM.MeadeAutostar497.Controller { //Disconnecting SerialPort.Close(); + _parked = false; } } } @@ -215,16 +218,22 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private double DMSToDouble(string DMS) + { + double l = int.Parse(DMS.Substring(0, 3)); + l = l + double.Parse(DMS.Substring(4, 2)) / 60; + if (DMS.Length == 9) + l = l + double.Parse(DMS.Substring(7, 2)) / 60 / 60; + + return l; + } + public double SiteLongitude { get { var longitude = SerialPort.CommandTerminated(":Gg#", "#"); - - double l = int.Parse(longitude.Substring(0, 3)); - l = l + double.Parse(longitude.Substring(4, 2)) / 60; - if (longitude.Length == 9) - l = l + double.Parse(longitude.Substring(7, 2)) / 60 / 60; + double l = DMSToDouble(longitude); if (l > 180) l = l - 360; @@ -254,6 +263,12 @@ namespace ASCOM.MeadeAutostar497.Controller get { var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + //:GW# Get Scope Alignment Status + //Returns: # + // where: + //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial + //tracking: T - tracking, N - not tracking + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. switch (alignmentString[0]) { @@ -263,22 +278,21 @@ namespace ASCOM.MeadeAutostar497.Controller default: throw new ASCOM.InvalidValueException($"unknown alignment returned from telescope: {alignmentString[0]}"); } - //:GW# Get Scope Alignment Status - //Returns: # - // where: - //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial - //tracking: T - tracking, N - not tracking - //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. } set { switch (value) { - case AlignmentModes.algAltAz: SerialPort.Command(":AA#"); + case AlignmentModes.algAltAz: + SerialPort.Command(":AA#"); + //:AA# Sets telescope the AltAz alignment mode + //Returns: nothing break; case AlignmentModes.algPolar: case AlignmentModes.algGermanPolar: SerialPort.Command(":AP#"); + //:AP# Sets telescope to Polar alignment mode + //Returns: nothing break; default: throw new ArgumentOutOfRangeException(nameof(value), value, null); @@ -286,10 +300,6 @@ namespace ASCOM.MeadeAutostar497.Controller //:AL# Sets telescope to Land alignment mode //Returns: nothing - //:AP# Sets telescope to Polar alignment mode - //Returns: nothing - //:AA# Sets telescope the AltAz alignment mode - //Returns: nothing } } @@ -297,6 +307,21 @@ namespace ASCOM.MeadeAutostar497.Controller public bool AtPark => _parked; + public double Azimuth + { + get + { + var result = SerialPort.CommandTerminated(":GZ#", "#"); + //:GZ# Get telescope azimuth + //Returns: DDD*MM#T or DDD*MM’SS# + //The current telescope Azimuth depending on the selected precision. + + double az = DMSToDouble(result); + + return az; + } + } + public void AbortSlew() { SerialPort.Command("#:Q#"); From ae4ba48ce29e61550a33af587e4fe5694cb18232 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 16:12:53 +0100 Subject: [PATCH 018/109] Added support for reading Declination --- .../TelescopeControllerUnitTests.cs | 15 +++++++++++++++ MeadeAutostar497/AscomClasses/Telescope.cs | 2 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 17 ++++++++++++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index c5e8fe7..a52d946 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -536,5 +536,20 @@ namespace MeadeAutostar497.UnitTests Assert.That( az, Is.EqualTo(expectedResult)); } + + [TestCase("+75*13", 75.2166666666666654)] + [TestCase("+65*13'21", 65.222499999999997)] + public void Declination_CanGetValue(string response, double expectedResult) + { + serialMock.Setup(x => x.CommandTerminated(":GD#", "#")).Returns(response); + + _isConnected = true; + + _telescopeController.Connected = true; + + var result = _telescopeController.Declination; + + Assert.That(result, Is.EqualTo(expectedResult)); + } } } diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index dbff572..9a7c05e 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -524,7 +524,7 @@ namespace ASCOM.MeadeAutostar497 { get { - double declination = 0.0; + double declination = _telescopeController.Declination; tl.LogMessage("Declination", "Get - " + utilities.DegreesToDMS(declination, ":", ":")); return declination; } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index a8f7de8..6f1f3fa 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -15,6 +15,7 @@ namespace ASCOM.MeadeAutostar497.Controller AlignmentModes AlignmentMode { get; set; } bool AtPark { get; } double Azimuth { get; } + double Declination { get; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index d85f038..04d8dff 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -320,7 +320,22 @@ namespace ASCOM.MeadeAutostar497.Controller return az; } - } + } + + public double Declination + { + get + { + var result = SerialPort.CommandTerminated(":GD#", "#"); + //:GD# Get Telescope Declination. + //Returns: sDD* MM# or sDD*MM’SS# + //Depending upon the current precision setting for the telescope. + + double az = DMSToDouble(result); + + return az; + } + } public void AbortSlew() { From 7df8da2f5959e1e378f3d8b1207df9bd4e2f9e43 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 18:45:18 +0100 Subject: [PATCH 019/109] Added 5 second timeout for the serial port. Fixed problem with the GW command not working on the Autostar 497. --- ConformanceResult.txt | 342 +++++++++--------- .../Controller/SerialProcessor.cs | 2 + .../Controller/TelescopeController.cs | 8 +- TestConsole/Program.cs | 7 +- 4 files changed, 180 insertions(+), 179 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index b3e4d88..b2c86ca 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -1,6 +1,3 @@ -Start-up ASCOM Device Conformance Checker - 64bit mode -Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 - ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -15,191 +12,188 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -00:25:26.447 Driver Access Checks OK -00:25:27.090 AccessChecks OK Successfully created driver using late binding -00:25:27.323 AccessChecks OK Successfully connected using late binding -00:25:27.327 AccessChecks INFO The driver is a .NET object -00:25:27.332 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -00:25:27.336 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -00:25:28.025 AccessChecks INFO Device does not expose interface ITelescopeV2 -00:25:28.830 AccessChecks INFO Device exposes interface ITelescopeV3 -00:25:30.141 AccessChecks OK Successfully created driver using driver access toolkit -00:25:30.312 AccessChecks OK Successfully connected using driver access toolkit +18:42:13.212 Driver Access Checks OK +18:42:13.853 AccessChecks OK Successfully created driver using late binding +18:42:14.078 AccessChecks OK Successfully connected using late binding +18:42:14.098 AccessChecks INFO The driver is a .NET object +18:42:14.101 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +18:42:14.106 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +18:42:14.796 AccessChecks INFO Device does not expose interface ITelescopeV2 +18:42:15.597 AccessChecks INFO Device exposes interface ITelescopeV3 +18:42:16.909 AccessChecks OK Successfully created driver using driver access toolkit +18:42:17.080 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -00:25:31.632 ConformanceCheck OK Driver instance created successfully -00:25:31.848 ConformanceCheck OK Connected OK +18:42:18.395 ConformanceCheck OK Driver instance created successfully +18:42:18.611 ConformanceCheck OK Connected OK Common Driver Methods -00:25:31.890 InterfaceVersion OK 3 -00:25:31.917 Connected OK True -00:25:31.945 Description OK Meade Autostar 497 .net -00:25:31.974 DriverInfo OK Information about the driver itself. Version: 0.0 -00:25:32.004 DriverVersion OK 0.0 -00:25:32.032 Name OK Meade Autostar 497 .net -00:25:32.060 CommandString INFO Conform cannot test the CommandString method -00:25:32.066 CommandBlind INFO Conform cannot test the CommandBlind method -00:25:32.072 CommandBool INFO Conform cannot test the CommandBool method -00:25:32.078 Action INFO Conform cannot test the Action method -00:25:32.085 SupportedActions OK Driver returned an empty action list +18:42:18.652 InterfaceVersion OK 3 +18:42:18.680 Connected OK True +18:42:18.708 Description OK Meade Autostar 497 .net +18:42:18.736 DriverInfo OK Information about the driver itself. Version: 0.0 +18:42:18.765 DriverVersion OK 0.0 +18:42:18.794 Name OK Meade Autostar 497 .net +18:42:18.823 CommandString INFO Conform cannot test the CommandString method +18:42:18.829 CommandBlind INFO Conform cannot test the CommandBlind method +18:42:18.835 CommandBool INFO Conform cannot test the CommandBool method +18:42:18.842 Action INFO Conform cannot test the Action method +18:42:18.849 SupportedActions OK Driver returned an empty action list Can Properties -00:25:32.153 CanFindHome OK False -00:25:32.161 CanPark OK True -00:25:32.169 CanPulseGuide OK True -00:25:32.177 CanSetDeclinationRate OK False -00:25:32.185 CanSetGuideRates OK False -00:25:32.193 CanSetPark OK False -00:25:32.204 CanSetPierSide OK False -00:25:32.218 CanSetRightAscensionRate OK False -00:25:32.227 CanSetTracking OK False -00:25:32.237 CanSlew OK True -00:25:32.247 CanSlewltAz OK True -00:25:32.256 CanSlewAltAzAsync OK True -00:25:32.266 CanSlewAsync OK True -00:25:32.275 CanSync OK True -00:25:32.284 CanSyncAltAz OK False -00:25:32.293 CanUnPark OK False +18:42:18.914 CanFindHome OK False +18:42:18.921 CanPark OK True +18:42:18.928 CanPulseGuide OK True +18:42:18.935 CanSetDeclinationRate OK False +18:42:18.942 CanSetGuideRates OK False +18:42:18.950 CanSetPark OK False +18:42:18.959 CanSetPierSide OK False +18:42:18.971 CanSetRightAscensionRate OK False +18:42:18.978 CanSetTracking OK False +18:42:18.985 CanSlew OK True +18:42:18.992 CanSlewltAz OK True +18:42:19.000 CanSlewAltAzAsync OK True +18:42:19.010 CanSlewAsync OK True +18:42:19.019 CanSync OK True +18:42:19.027 CanSyncAltAz OK False +18:42:19.036 CanUnPark OK False Pre-run Checks -00:25:32.342 Mount Safety INFO Scope is not parked, continuing testing -00:25:32.393 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -00:25:32.401 TimeCheck INFO PC UTCDate: 01-May-2019 23:25:32.401 -00:25:32.579 TimeCheck INFO Mount UTCDate: 01-May-2019 19:00:43.000 +18:42:19.083 Mount Safety INFO Scope is not parked, continuing testing +18:42:19.139 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +18:42:19.147 TimeCheck INFO PC UTCDate: 02-May-2019 17:42:19.147 +18:42:19.274 TimeCheck INFO Mount UTCDate: 02-May-2019 17:42:17.000 Properties -00:25:32.654 AlignmentMode OK Optional member threw a PropertyNotImplementedException exception. -00:25:32.688 Altitude OK Optional member threw a PropertyNotImplementedException exception. -00:25:32.720 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -00:25:32.752 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -00:25:32.784 AtHome OK False -00:25:32.831 AtPark OK False -00:25:32.862 Azimuth OK Optional member threw a PropertyNotImplementedException exception. -00:25:32.895 Declination OK 00:00:00.00 -00:25:32.926 DeclinationRate Read OK 0.00 -00:25:32.958 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -00:25:32.990 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.022 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.055 EquatorialSystem OK equLocalTopocentric -00:25:33.087 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.120 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.132 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -00:25:33.165 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.176 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -00:25:33.209 IsPulseGuiding OK False -00:25:33.242 RightAscension OK 00:00:00.00 -00:25:33.277 RightAscensionRate Read OK 0.00 -00:25:33.311 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -00:25:33.345 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.380 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.391 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.403 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.461 SiteLatitude Read OK 00:00:00.00 -00:25:33.499 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -00:25:33.511 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -00:25:33.545 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -00:25:33.600 SiteLongitude Read OK -03:48:00.00 -00:25:33.635 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -00:25:33.647 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -00:25:33.737 SiteLongitude Write OK Legal value -03:48:00.00 degrees written successfully -00:25:33.778 Slewing OK False -00:25:33.812 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.847 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.859 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.894 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:33.944 SiderealTime OK 13:47:08.92 -00:25:33.966 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 13:47:08.92, ASCOM: 13:48:46.01 -00:25:34.000 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:34.035 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -00:25:34.052 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -00:25:34.089 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -00:25:34.101 Tracking Read OK True -00:25:34.135 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -00:25:34.180 TrackingRates Found drive rate: driveSidereal -00:25:34.192 TrackingRates OK Drive rates read OK -00:25:34.205 TrackingRates OK Disposed tracking rates OK -00:25:34.241 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -00:25:34.257 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -00:25:34.347 UTCDate Read OK 01-May-2019 19:00:45.000 -00:25:34.586 UTCDate Write OK New UTCDate written successfully: 01/05/2019 20:00:45 +18:42:19.348 AlignmentMode OK algPolar +18:42:19.385 Altitude OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.418 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.450 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.482 AtHome OK False +18:42:19.513 AtPark OK False +18:42:19.573 Azimuth OK 323.76 +18:42:19.644 Declination OK 25:33:02.00 +18:42:19.676 DeclinationRate Read OK 0.00 +18:42:19.709 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +18:42:19.741 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.773 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.805 EquatorialSystem OK equLocalTopocentric +18:42:19.837 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.870 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.880 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:42:19.914 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:19.924 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:42:19.958 IsPulseGuiding OK False +18:42:19.990 RightAscension OK 00:00:00.00 +18:42:20.022 RightAscensionRate Read OK 0.00 +18:42:20.055 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +18:42:20.088 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.122 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.132 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.145 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.205 SiteLatitude Read OK 00:00:00.00 +18:42:20.242 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +18:42:20.254 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +18:42:20.290 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +18:42:20.347 SiteLongitude Read OK -06:12:00.00 +18:42:20.382 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +18:42:20.393 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +18:42:20.486 SiteLongitude Write OK Legal value -06:12:00.00 degrees written successfully +18:42:20.526 Slewing OK False +18:42:20.560 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.599 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.611 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.650 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.699 SiderealTime OK 07:52:31.84 +18:42:20.710 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 07:52:31.84, ASCOM: 07:58:56.94 +18:42:20.749 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.794 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:42:20.811 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:42:20.849 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:42:20.861 Tracking Read OK True +18:42:20.899 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +18:42:20.940 TrackingRates Found drive rate: driveSidereal +18:42:20.951 TrackingRates OK Drive rates read OK +18:42:20.965 TrackingRates OK Disposed tracking rates OK +18:42:21.001 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +18:42:21.013 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +18:42:21.105 UTCDate Read OK 02-May-2019 17:42:18.000 +18:42:21.272 UTCDate Write OK New UTCDate written successfully: 02/05/2019 18:42:18 Methods -00:25:34.827 CanMoveAxis:Primary OK CanMoveAxis:Primary True -00:25:34.863 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -00:25:34.899 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -00:25:34.934 Park/Unpark INFO Tests skipped -00:25:34.956 AbortSlew OK AbortSlew OK when not slewing -00:25:35.021 AxisRate:Primary OK Empty axis rate returned -00:25:35.033 AxisRate:Primary OK Disposed axis rates OK -00:25:35.045 AxisRate:Secondary OK Empty axis rate returned -00:25:35.059 AxisRate:Secondary OK Disposed axis rates OK -00:25:35.072 AxisRate:Tertiary OK Empty axis rate returned -00:25:35.084 AxisRate:Tertiary OK Disposed axis rates OK -00:25:35.099 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -00:25:35.150 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -00:25:35.163 MoveAxis Primary OK AxisRates object successfully disposed -00:25:35.221 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -00:25:35.234 MoveAxis Secondary OK AxisRates object successfully disposed -00:25:35.293 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -00:25:37.331 PulseGuide OK Synchronous pulse guide found OK -00:25:37.428 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:37.477 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.521 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.581 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.626 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.713 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:37.751 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.795 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.855 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.898 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:37.999 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.037 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:38.079 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:38.139 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:38.185 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:38.243 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.259 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.300 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.341 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.357 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.373 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -00:25:38.497 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.513 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.531 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.569 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.611 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.670 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.716 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.809 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.823 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.843 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.883 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.930 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:38.990 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.031 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -00:25:39.110 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.151 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.172 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.234 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.254 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.316 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.357 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.375 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.439 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.456 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -00:25:39.545 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.585 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.630 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.690 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.734 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -00:25:39.796 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected - -SideOfPier Model Tests -00:25:39.866 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +18:42:21.516 CanMoveAxis:Primary OK CanMoveAxis:Primary True +18:42:21.551 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +18:42:21.587 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +18:42:21.623 Park/Unpark INFO Tests skipped +18:42:21.645 AbortSlew OK AbortSlew OK when not slewing +18:42:21.714 AxisRate:Primary OK Empty axis rate returned +18:42:21.726 AxisRate:Primary OK Disposed axis rates OK +18:42:21.739 AxisRate:Secondary OK Empty axis rate returned +18:42:21.754 AxisRate:Secondary OK Disposed axis rates OK +18:42:21.769 AxisRate:Tertiary OK Empty axis rate returned +18:42:21.782 AxisRate:Tertiary OK Disposed axis rates OK +18:42:21.797 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +18:42:21.845 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +18:42:21.860 MoveAxis Primary OK AxisRates object successfully disposed +18:42:21.922 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +18:42:21.934 MoveAxis Secondary OK AxisRates object successfully disposed +18:42:21.992 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +18:42:24.032 PulseGuide OK Synchronous pulse guide found OK +18:42:24.128 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:24.178 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.224 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.283 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.326 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.412 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:24.451 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.494 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.554 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.614 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.738 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:24.777 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.824 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.885 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.929 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:24.988 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.003 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.043 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.079 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.094 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.109 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. +18:42:25.174 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.188 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.204 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.243 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.287 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.347 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.392 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.479 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.494 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.513 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.552 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.596 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.655 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.699 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.760 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +18:42:25.778 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:25.820 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:25.837 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:25.899 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:25.920 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:25.984 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.025 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:26.042 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:26.104 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:26.123 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +18:42:26.239 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.278 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.321 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.382 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.427 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. +18:42:26.538 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected Post-run Checks -00:25:39.960 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +18:42:26.651 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs index 2e14264..1c77556 100644 --- a/MeadeAutostar497/Controller/SerialProcessor.cs +++ b/MeadeAutostar497/Controller/SerialProcessor.cs @@ -62,6 +62,8 @@ namespace ASCOM.MeadeAutostar497.Controller public void Open() { + _serialPort.ReadTimeout = 5000; + _serialPort.WriteTimeout = 5000; _serialPort.Open(); } diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 04d8dff..e5d1d13 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -262,7 +262,9 @@ namespace ASCOM.MeadeAutostar497.Controller { get { - var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + char ack = (char)6; + //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + var alignmentString = SerialPort.CommandChar(ack.ToString()); //:GW# Get Scope Alignment Status //Returns: # // where: @@ -270,13 +272,13 @@ namespace ASCOM.MeadeAutostar497.Controller //tracking: T - tracking, N - not tracking //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. - switch (alignmentString[0]) + switch (alignmentString) { case 'A': return AlignmentModes.algAltAz; case 'P': return AlignmentModes.algPolar; case 'G': return AlignmentModes.algGermanPolar; default: - throw new ASCOM.InvalidValueException($"unknown alignment returned from telescope: {alignmentString[0]}"); + throw new ASCOM.InvalidValueException($"unknown alignment returned from telescope: {alignmentString}"); } } set diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index a6cbae5..992d4ef 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -43,8 +43,11 @@ namespace ASCOM //Console.WriteLine(device.Slewing); - Console.WriteLine(device.UTCDate); - device.UTCDate = DateTime.UtcNow; + //device.UTCDate = DateTime.UtcNow; + //Console.WriteLine(device.UTCDate.ToLocalTime()); + + + Console.WriteLine(device.AlignmentMode); double l = device.SiteLatitude; device.SiteLatitude = l; From e8793231d1eaed86c13c8377053c82b4cae9565d Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 2 May 2019 18:54:52 +0100 Subject: [PATCH 020/109] Fixed broken unit test --- .../TelescopeControllerUnitTests.cs | 11 ++++++----- MeadeAutostar497/Controller/TelescopeController.cs | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs index a52d946..97f4fcf 100644 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs @@ -448,12 +448,13 @@ namespace MeadeAutostar497.UnitTests serialMock.Verify(x => x.Command(":Mgs1024#"), Times.Once); } - [TestCase("AT0", AlignmentModes.algAltAz)] - [TestCase("PT0", AlignmentModes.algPolar)] - [TestCase("GT0", AlignmentModes.algGermanPolar)] - public void AlignmentMode_Get_ReturnsExpectedValue(string commandResponse, AlignmentModes mode) + [TestCase('A', AlignmentModes.algAltAz)] + [TestCase('P', AlignmentModes.algPolar)] + public void AlignmentMode_Get_ReturnsExpectedValue(char commandResponse, AlignmentModes mode) { - serialMock.Setup(x => x.CommandTerminated(":GW#", "#")).Returns(commandResponse); + const char ack = (char)6; + + serialMock.Setup(x => x.CommandChar(ack.ToString())).Returns(commandResponse); _isConnected = true; diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index e5d1d13..da3234b 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -262,7 +262,7 @@ namespace ASCOM.MeadeAutostar497.Controller { get { - char ack = (char)6; + const char ack = (char)6; //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); var alignmentString = SerialPort.CommandChar(ack.ToString()); //:GW# Get Scope Alignment Status From 2d69a4fba82d9fc7e13eba366c24cd5efa9bf0ff Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 17:17:22 +0100 Subject: [PATCH 021/109] Added support for altitude --- MeadeAutostar497/AscomClasses/Telescope.cs | 5 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 50 +++++++++++++------ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 9a7c05e..4dba4a4 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -306,8 +306,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("Altitude", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Altitude", false); + var alt = _telescopeController.Altitude; + tl.LogMessage("Altitude", $"{alt}"); + return alt; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 6f1f3fa..7815e6f 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -16,6 +16,7 @@ namespace ASCOM.MeadeAutostar497.Controller bool AtPark { get; } double Azimuth { get; } double Declination { get; } + double Altitude { get; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index da3234b..a5f7139 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -190,16 +190,8 @@ namespace ASCOM.MeadeAutostar497.Controller get { var latitude = SerialPort.CommandTerminated( ":Gt#", "#"); - - double lat = int.Parse(latitude.Substring(1, 2)); - lat = lat + double.Parse(latitude.Substring(4, 2)) / 60; - if (latitude.Length == 9) - lat = lat + double.Parse(latitude.Substring(7, 2)) / 60 / 60; - if (latitude[0] == '-') - lat = -lat; - - return lat; + return DMSToDouble(latitude); } set { @@ -220,12 +212,31 @@ namespace ASCOM.MeadeAutostar497.Controller private double DMSToDouble(string DMS) { - double l = int.Parse(DMS.Substring(0, 3)); - l = l + double.Parse(DMS.Substring(4, 2)) / 60; - if (DMS.Length == 9) - l = l + double.Parse(DMS.Substring(7, 2)) / 60 / 60; + if (IsNumeric(DMS[0])) + { + double l = int.Parse(DMS.Substring(0, 3)); + l = l + double.Parse(DMS.Substring(4, 2)) / 60; + if (DMS.Length == 9) + l = l + double.Parse(DMS.Substring(7, 2)) / 60 / 60; - return l; + return l; + } + + double lat = int.Parse(DMS.Substring(1, 2)); + lat = lat + double.Parse(DMS.Substring(4, 2)) / 60; + if (DMS.Length == 9) + lat = lat + double.Parse(DMS.Substring(7, 2)) / 60 / 60; + + if (DMS[0] == '-') + lat = -lat; + + return lat; + } + + private bool IsNumeric(char c) + { + char[] nums = new[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + return nums.Contains(c); } public double SiteLongitude @@ -339,6 +350,17 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public double Altitude { + get + { + var result = SerialPort.CommandTerminated(":GA#", "#"); + //:GA# Get Telescope Altitude + //Returns: sDD* MM# or sDD*MM’SS# + //The current scope altitude. The returned format depending on the current precision setting. + return DMSToDouble(result); + } + } + public void AbortSlew() { SerialPort.Command("#:Q#"); From 75d2d080a3388fcc3a10cda6f058e527e083c24e Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 17:29:34 +0100 Subject: [PATCH 022/109] Tidying up resharper warinings --- .../Controller/TelescopeController.cs | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index a5f7139..97757cf 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -9,9 +9,9 @@ namespace ASCOM.MeadeAutostar497.Controller //todo stop this being a singleton, and instead use a server to make only a single instance. public sealed class TelescopeController : ITelescopeController { - private static readonly Lazy lazy = new Lazy(); + private static readonly Lazy Lazy = new Lazy(); - public static TelescopeController Instance => lazy.Value; + public static TelescopeController Instance => Lazy.Value; //todo remove this as it can cause problems in production private ISerialProcessor _serialPort; @@ -69,7 +69,7 @@ namespace ASCOM.MeadeAutostar497.Controller //Connecting try { - _parked = false; + AtPark = false; SerialPort.DtrEnable = false; SerialPort.RtsEnable = false; SerialPort.BaudRate = 9600; @@ -92,7 +92,7 @@ namespace ASCOM.MeadeAutostar497.Controller { //Disconnecting SerialPort.Close(); - _parked = false; + AtPark = false; } } } @@ -191,15 +191,15 @@ namespace ASCOM.MeadeAutostar497.Controller { var latitude = SerialPort.CommandTerminated( ":Gt#", "#"); - return DMSToDouble(latitude); + return DmsToDouble(latitude); } set { if (value > 90) - throw new ASCOM.InvalidValueException("Latitude cannot be greater than 90 degrees."); + throw new InvalidValueException("Latitude cannot be greater than 90 degrees."); if (value < -90) - throw new ASCOM.InvalidValueException("Latitude cannot be less than -90 degrees."); + throw new InvalidValueException("Latitude cannot be less than -90 degrees."); int d = Convert.ToInt32(Math.Floor(value)); int m = Convert.ToInt32(60 * (value - d)); @@ -210,24 +210,24 @@ namespace ASCOM.MeadeAutostar497.Controller } } - private double DMSToDouble(string DMS) + private double DmsToDouble(string dms) { - if (IsNumeric(DMS[0])) + if (IsNumeric(dms[0])) { - double l = int.Parse(DMS.Substring(0, 3)); - l = l + double.Parse(DMS.Substring(4, 2)) / 60; - if (DMS.Length == 9) - l = l + double.Parse(DMS.Substring(7, 2)) / 60 / 60; + double l = int.Parse(dms.Substring(0, 3)); + l = l + double.Parse(dms.Substring(4, 2)) / 60; + if (dms.Length == 9) + l = l + double.Parse(dms.Substring(7, 2)) / 60 / 60; return l; } - double lat = int.Parse(DMS.Substring(1, 2)); - lat = lat + double.Parse(DMS.Substring(4, 2)) / 60; - if (DMS.Length == 9) - lat = lat + double.Parse(DMS.Substring(7, 2)) / 60 / 60; + double lat = int.Parse(dms.Substring(1, 2)); + lat = lat + double.Parse(dms.Substring(4, 2)) / 60; + if (dms.Length == 9) + lat = lat + double.Parse(dms.Substring(7, 2)) / 60 / 60; - if (DMS[0] == '-') + if (dms[0] == '-') lat = -lat; return lat; @@ -244,7 +244,7 @@ namespace ASCOM.MeadeAutostar497.Controller get { var longitude = SerialPort.CommandTerminated(":Gg#", "#"); - double l = DMSToDouble(longitude); + double l = DmsToDouble(longitude); if (l > 180) l = l - 360; @@ -254,10 +254,10 @@ namespace ASCOM.MeadeAutostar497.Controller set { if (value > 180) - throw new ASCOM.InvalidValueException("Longitude cannot be greater than 180 degrees."); + throw new InvalidValueException("Longitude cannot be greater than 180 degrees."); if (value < -180) - throw new ASCOM.InvalidValueException("Longitude cannot be lower than -180 degrees."); + throw new InvalidValueException("Longitude cannot be lower than -180 degrees."); int d = Convert.ToInt32(Math.Floor(value)); int m = Convert.ToInt32(60 * (value - d)); @@ -289,7 +289,7 @@ namespace ASCOM.MeadeAutostar497.Controller case 'P': return AlignmentModes.algPolar; case 'G': return AlignmentModes.algGermanPolar; default: - throw new ASCOM.InvalidValueException($"unknown alignment returned from telescope: {alignmentString}"); + throw new InvalidValueException($"unknown alignment returned from telescope: {alignmentString}"); } } set @@ -316,9 +316,7 @@ namespace ASCOM.MeadeAutostar497.Controller } } - private bool _parked = false; - - public bool AtPark => _parked; + public bool AtPark { get; private set; } public double Azimuth { @@ -329,7 +327,7 @@ namespace ASCOM.MeadeAutostar497.Controller //Returns: DDD*MM#T or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. - double az = DMSToDouble(result); + double az = DmsToDouble(result); return az; } @@ -344,7 +342,7 @@ namespace ASCOM.MeadeAutostar497.Controller //Returns: sDD* MM# or sDD*MM’SS# //Depending upon the current precision setting for the telescope. - double az = DMSToDouble(result); + double az = DmsToDouble(result); return az; } @@ -357,7 +355,7 @@ namespace ASCOM.MeadeAutostar497.Controller //:GA# Get Telescope Altitude //Returns: sDD* MM# or sDD*MM’SS# //The current scope altitude. The returned format depending on the current precision setting. - return DMSToDouble(result); + return DmsToDouble(result); } } @@ -405,10 +403,10 @@ namespace ASCOM.MeadeAutostar497.Controller public void Park() { - if (_parked) + if (AtPark) return; - _parked = true; + AtPark = true; _serialPort.Command(":hP#"); } From ee088ff35c903d26992f7142d90f1116dd384991 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 20:29:32 +0100 Subject: [PATCH 023/109] Implemented RightAscension TargetRightAscension TargetDec SlewToCoord and SlewToCoordAsync --- ConformanceResult.txt | 409 ++++++++++-------- MeadeAutostar497/AscomClasses/Telescope.cs | 30 +- .../Controller/ITelescopeController.cs | 9 +- .../Controller/TelescopeController.cs | 175 ++++++++ TestConsole/Program.cs | 10 +- 5 files changed, 445 insertions(+), 188 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index b2c86ca..dc441b0 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -1,3 +1,6 @@ +Start-up ASCOM Device Conformance Checker - 64bit mode +Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 + ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -12,189 +15,257 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -18:42:13.212 Driver Access Checks OK -18:42:13.853 AccessChecks OK Successfully created driver using late binding -18:42:14.078 AccessChecks OK Successfully connected using late binding -18:42:14.098 AccessChecks INFO The driver is a .NET object -18:42:14.101 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -18:42:14.106 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -18:42:14.796 AccessChecks INFO Device does not expose interface ITelescopeV2 -18:42:15.597 AccessChecks INFO Device exposes interface ITelescopeV3 -18:42:16.909 AccessChecks OK Successfully created driver using driver access toolkit -18:42:17.080 AccessChecks OK Successfully connected using driver access toolkit +20:25:07.406 Driver Access Checks OK +20:25:08.054 AccessChecks OK Successfully created driver using late binding +20:25:08.281 AccessChecks OK Successfully connected using late binding +20:25:08.285 AccessChecks INFO The driver is a .NET object +20:25:08.289 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +20:25:08.294 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +20:25:08.987 AccessChecks INFO Device does not expose interface ITelescopeV2 +20:25:09.814 AccessChecks INFO Device exposes interface ITelescopeV3 +20:25:11.132 AccessChecks OK Successfully created driver using driver access toolkit +20:25:11.305 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -18:42:18.395 ConformanceCheck OK Driver instance created successfully -18:42:18.611 ConformanceCheck OK Connected OK +20:25:12.627 ConformanceCheck OK Driver instance created successfully +20:25:12.842 ConformanceCheck OK Connected OK Common Driver Methods -18:42:18.652 InterfaceVersion OK 3 -18:42:18.680 Connected OK True -18:42:18.708 Description OK Meade Autostar 497 .net -18:42:18.736 DriverInfo OK Information about the driver itself. Version: 0.0 -18:42:18.765 DriverVersion OK 0.0 -18:42:18.794 Name OK Meade Autostar 497 .net -18:42:18.823 CommandString INFO Conform cannot test the CommandString method -18:42:18.829 CommandBlind INFO Conform cannot test the CommandBlind method -18:42:18.835 CommandBool INFO Conform cannot test the CommandBool method -18:42:18.842 Action INFO Conform cannot test the Action method -18:42:18.849 SupportedActions OK Driver returned an empty action list +20:25:12.886 InterfaceVersion OK 3 +20:25:12.915 Connected OK True +20:25:12.943 Description OK Meade Autostar 497 .net +20:25:12.972 DriverInfo OK Information about the driver itself. Version: 0.0 +20:25:13.000 DriverVersion OK 0.0 +20:25:13.029 Name OK Meade Autostar 497 .net +20:25:13.058 CommandString INFO Conform cannot test the CommandString method +20:25:13.065 CommandBlind INFO Conform cannot test the CommandBlind method +20:25:13.071 CommandBool INFO Conform cannot test the CommandBool method +20:25:13.077 Action INFO Conform cannot test the Action method +20:25:13.088 SupportedActions OK Driver returned an empty action list Can Properties -18:42:18.914 CanFindHome OK False -18:42:18.921 CanPark OK True -18:42:18.928 CanPulseGuide OK True -18:42:18.935 CanSetDeclinationRate OK False -18:42:18.942 CanSetGuideRates OK False -18:42:18.950 CanSetPark OK False -18:42:18.959 CanSetPierSide OK False -18:42:18.971 CanSetRightAscensionRate OK False -18:42:18.978 CanSetTracking OK False -18:42:18.985 CanSlew OK True -18:42:18.992 CanSlewltAz OK True -18:42:19.000 CanSlewAltAzAsync OK True -18:42:19.010 CanSlewAsync OK True -18:42:19.019 CanSync OK True -18:42:19.027 CanSyncAltAz OK False -18:42:19.036 CanUnPark OK False +20:25:13.156 CanFindHome OK False +20:25:13.163 CanPark OK True +20:25:13.170 CanPulseGuide OK True +20:25:13.177 CanSetDeclinationRate OK False +20:25:13.187 CanSetGuideRates OK False +20:25:13.195 CanSetPark OK False +20:25:13.202 CanSetPierSide OK False +20:25:13.215 CanSetRightAscensionRate OK False +20:25:13.222 CanSetTracking OK False +20:25:13.230 CanSlew OK True +20:25:13.237 CanSlewltAz OK True +20:25:13.246 CanSlewAltAzAsync OK True +20:25:13.255 CanSlewAsync OK True +20:25:13.264 CanSync OK True +20:25:13.273 CanSyncAltAz OK False +20:25:13.282 CanUnPark OK False Pre-run Checks -18:42:19.083 Mount Safety INFO Scope is not parked, continuing testing -18:42:19.139 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -18:42:19.147 TimeCheck INFO PC UTCDate: 02-May-2019 17:42:19.147 -18:42:19.274 TimeCheck INFO Mount UTCDate: 02-May-2019 17:42:17.000 +20:25:13.332 Mount Safety INFO Scope is not parked, continuing testing +20:25:13.384 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +20:25:13.392 TimeCheck INFO PC UTCDate: 06-May-2019 19:25:13.392 +20:25:13.517 TimeCheck INFO Mount UTCDate: 02-May-2019 20:31:47.000 Properties -18:42:19.348 AlignmentMode OK algPolar -18:42:19.385 Altitude OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.418 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.450 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.482 AtHome OK False -18:42:19.513 AtPark OK False -18:42:19.573 Azimuth OK 323.76 -18:42:19.644 Declination OK 25:33:02.00 -18:42:19.676 DeclinationRate Read OK 0.00 -18:42:19.709 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -18:42:19.741 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.773 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.805 EquatorialSystem OK equLocalTopocentric -18:42:19.837 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.870 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.880 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:42:19.914 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:19.924 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:42:19.958 IsPulseGuiding OK False -18:42:19.990 RightAscension OK 00:00:00.00 -18:42:20.022 RightAscensionRate Read OK 0.00 -18:42:20.055 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -18:42:20.088 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.122 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.132 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.145 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.205 SiteLatitude Read OK 00:00:00.00 -18:42:20.242 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -18:42:20.254 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -18:42:20.290 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -18:42:20.347 SiteLongitude Read OK -06:12:00.00 -18:42:20.382 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -18:42:20.393 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -18:42:20.486 SiteLongitude Write OK Legal value -06:12:00.00 degrees written successfully -18:42:20.526 Slewing OK False -18:42:20.560 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.599 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.611 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.650 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.699 SiderealTime OK 07:52:31.84 -18:42:20.710 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 07:52:31.84, ASCOM: 07:58:56.94 -18:42:20.749 TargetDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.794 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:42:20.811 TargetRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:42:20.849 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:42:20.861 Tracking Read OK True -18:42:20.899 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -18:42:20.940 TrackingRates Found drive rate: driveSidereal -18:42:20.951 TrackingRates OK Drive rates read OK -18:42:20.965 TrackingRates OK Disposed tracking rates OK -18:42:21.001 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -18:42:21.013 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -18:42:21.105 UTCDate Read OK 02-May-2019 17:42:18.000 -18:42:21.272 UTCDate Write OK New UTCDate written successfully: 02/05/2019 18:42:18 +20:25:13.591 AlignmentMode OK algPolar +20:25:13.647 Altitude OK 90.00 +20:25:13.685 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +20:25:13.720 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +20:25:13.752 AtHome OK False +20:25:13.783 AtPark OK False +20:25:13.845 Azimuth OK 22.95 +20:25:13.903 Declination OK 89:59:59.00 +20:25:13.934 DeclinationRate Read OK 0.00 +20:25:13.967 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +20:25:14.000 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.031 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.063 EquatorialSystem OK equLocalTopocentric +20:25:14.096 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.131 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.142 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +20:25:14.174 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.188 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +20:25:14.220 IsPulseGuiding OK False +20:25:14.281 RightAscension OK 01:34:18.00 +20:25:14.313 RightAscensionRate Read OK 0.00 +20:25:14.346 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +20:25:14.380 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.415 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.426 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.437 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.494 SiteLatitude Read OK 00:00:00.00 +20:25:14.534 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +20:25:14.547 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +20:25:14.584 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +20:25:14.641 SiteLongitude Read OK -18:12:00.00 +20:25:14.675 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +20:25:14.690 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +20:25:14.784 SiteLongitude Write OK Legal value -18:12:00.00 degrees written successfully +20:25:14.829 Slewing OK False +20:25:14.863 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.898 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.911 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.946 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +20:25:14.997 SiderealTime OK 09:03:29.25 +20:25:15.009 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 09:03:29.25, ASCOM: 09:09:54.36 +20:25:15.053 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +20:25:15.087 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +20:25:15.100 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +20:25:15.138 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +20:25:15.151 Tracking Read OK True +20:25:15.186 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +20:25:15.226 TrackingRates Found drive rate: driveSidereal +20:25:15.240 TrackingRates OK Drive rates read OK +20:25:15.252 TrackingRates OK Disposed tracking rates OK +20:25:15.288 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +20:25:15.300 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +20:25:15.393 UTCDate Read OK 02-May-2019 20:31:49.000 +20:25:15.555 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:31:49 Methods -18:42:21.516 CanMoveAxis:Primary OK CanMoveAxis:Primary True -18:42:21.551 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -18:42:21.587 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -18:42:21.623 Park/Unpark INFO Tests skipped -18:42:21.645 AbortSlew OK AbortSlew OK when not slewing -18:42:21.714 AxisRate:Primary OK Empty axis rate returned -18:42:21.726 AxisRate:Primary OK Disposed axis rates OK -18:42:21.739 AxisRate:Secondary OK Empty axis rate returned -18:42:21.754 AxisRate:Secondary OK Disposed axis rates OK -18:42:21.769 AxisRate:Tertiary OK Empty axis rate returned -18:42:21.782 AxisRate:Tertiary OK Disposed axis rates OK -18:42:21.797 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -18:42:21.845 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -18:42:21.860 MoveAxis Primary OK AxisRates object successfully disposed -18:42:21.922 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -18:42:21.934 MoveAxis Secondary OK AxisRates object successfully disposed -18:42:21.992 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -18:42:24.032 PulseGuide OK Synchronous pulse guide found OK -18:42:24.128 SlewToCoordinates ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:24.178 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.224 SlewToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.283 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.326 SlewToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.412 SlewToCoordinatesAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:24.451 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.494 SlewToCoordinatesAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.554 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.614 SlewToCoordinatesAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.738 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:24.777 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.824 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.885 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.929 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:24.988 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.003 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.043 TargetRightAscension Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.079 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.094 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.109 TargetDeclination Write OK Optional member threw a PropertyNotImplementedException exception. -18:42:25.174 SlewToTarget ISSUE CanSlew is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.188 SlewToTarget ISSUE CanSlew is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.204 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.243 SlewToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.287 SlewToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.347 SlewToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.392 SlewToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.479 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetRightAscension and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.494 SlewToTargetAsync ISSUE CanSlewAsync is True but can't set TargetDeclination and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.513 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.552 SlewToTargetAsync (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.596 SlewToTargetAsync (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.655 SlewToTargetAsync (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.699 SlewToTargetAsync (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.760 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -18:42:25.778 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:25.820 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:25.837 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:25.899 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:25.920 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:25.984 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.025 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:26.042 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:26.104 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:26.123 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -18:42:26.239 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.278 SyncToTarget (Bad L) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.321 SyncToTarget (Bad L) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.382 SyncToTarget (Bad H) ISSUE Exception setting bad RA coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.427 SyncToTarget (Bad H) ISSUE Exception setting bad Dec coordinate and a PropertyNotImplementedException exception was thrown, this method must function per the ASCOM specification. -18:42:26.538 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +20:25:15.802 CanMoveAxis:Primary OK CanMoveAxis:Primary True +20:25:15.839 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +20:25:15.875 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +20:25:15.913 Park/Unpark INFO Tests skipped +20:25:15.937 AbortSlew OK AbortSlew OK when not slewing +20:25:16.003 AxisRate:Primary OK Empty axis rate returned +20:25:16.015 AxisRate:Primary OK Disposed axis rates OK +20:25:16.028 AxisRate:Secondary OK Empty axis rate returned +20:25:16.039 AxisRate:Secondary OK Disposed axis rates OK +20:25:16.052 AxisRate:Tertiary OK Empty axis rate returned +20:25:16.064 AxisRate:Tertiary OK Disposed axis rates OK +20:25:16.080 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +20:25:16.131 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +20:25:16.143 MoveAxis Primary OK AxisRates object successfully disposed +20:25:16.201 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +20:25:16.213 MoveAxis Secondary OK AxisRates object successfully disposed +20:25:16.270 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +20:25:18.310 PulseGuide OK Synchronous pulse guide found OK +20:25:52.356 SlewToCoordinates OK Slewed OK. RA: 08:03:32.68 +20:25:52.369 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 +20:25:52.403 SlewToCoordinates ERROR The TargetRightAscension property 08:03:32.00 does not match the expected RA 08:03:32.68 +20:25:52.438 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +20:25:52.487 SlewToCoordinates (Bad L) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) +20:26:12.283 SlewToCoordinates (Bad L) ERROR Failed to reject bad Dec coordinate: -100:00:00.00 +20:26:12.343 SlewToCoordinates (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) +20:26:17.522 SlewToCoordinates (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad Dec coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.TimeoutException: The operation has timed out. + at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) + at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) + at System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne) + at System.IO.Ports.SerialPort.ReadTo(String value) + at ASCOM.MeadeAutostar497.Controller.SerialProcessor.ReadTerminated(String terminator) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\SerialProcessor.cs:line 110 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.DoSlewAsync() in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 580 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 547 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) +20:26:36.353 SlewToCoordinatesAsync OK Slewed OK. RA: 07:04:32.06 +20:26:36.367 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 +20:26:36.400 SlewToCoordinatesAsync OK The TargetRightAscension property 07:04:32.06 matches the expected RA OK. +20:26:36.437 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +20:26:36.478 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) +20:26:36.621 SlewToCoordinatesAsync (Bad L) ERROR Failed to reject bad Dec coordinate: -100:00:00.00 +20:26:36.681 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) +20:26:41.892 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad Dec coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.TimeoutException: The operation has timed out. + at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) + at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) + at System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne) + at System.IO.Ports.SerialPort.ReadTo(String value) + at ASCOM.MeadeAutostar497.Controller.SerialProcessor.ReadTerminated(String terminator) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\SerialProcessor.cs:line 110 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.DoSlewAsync() in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 580 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 547 + at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) +20:27:04.329 SyncToCoordinates OK Slewed to start position OK. RA: 06:04:56.54 +20:27:04.343 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +20:27:04.360 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:04.400 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:04.447 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:04.509 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:04.558 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:04.618 TargetRightAscension Write ERROR Unexpected DriverException(0x80131500), : CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:04.636 TargetRightAscension Write ERROR Unexpected DriverException(0x80131500), : CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:04.742 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 05:05:19.25 +20:27:04.825 TargetDeclination Write ISSUE No error generated on set TargetDeclination < -90 degrees +20:27:04.885 TargetDeclination Write ISSUE No error generated on set TargetDeclination > 90 degrees +20:27:04.965 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +20:27:05.118 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:05.160 SlewToTarget (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:05.294 SlewToTarget (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:05.355 SlewToTarget (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:05.490 SlewToTarget (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:05.666 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:05.707 SlewToTargetAsync (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:05.857 SlewToTargetAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:05.921 SlewToTargetAsync (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:06.056 SlewToTargetAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.120 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +20:27:06.139 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:06.185 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.204 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.266 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.284 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.348 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:06.389 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.412 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.475 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:06.493 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:22.333 SyncToTarget INFO Slewed to start position within 18.0 arc seconds of expected RA: 06:05:21.20, actual RA: 06:05:20.00 +20:27:22.348 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +20:27:22.448 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:27:22.490 SyncToTarget (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be below 0 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:22.627 SyncToTarget (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:22.690 SyncToTarget (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. + Parameter name: Right ascension value cannot be greater than 23:59:59 + at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 + at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) +20:27:22.822 SyncToTarget (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:27:22.979 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected + +SideOfPier Model Tests +20:27:23.049 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -18:42:26.651 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +20:27:23.142 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 0 errors, 2 warnings and 45 issues +Your driver had 17 errors, 2 warnings and 27 issues diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 4dba4a4..c11a5c5 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -651,7 +651,7 @@ namespace ASCOM.MeadeAutostar497 { get { - double rightAscension = 0.0; + double rightAscension = _telescopeController.RightAscension; tl.LogMessage("RightAscension", "Get - " + utilities.HoursToHMS(rightAscension)); return rightAscension; } @@ -790,14 +790,14 @@ namespace ASCOM.MeadeAutostar497 public void SlewToCoordinates(double RightAscension, double Declination) { - tl.LogMessage("SlewToCoordinates", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToCoordinates"); + tl.LogMessage("SlewToCoordinates", $"Ra={RightAscension}, Dec={Declination}"); + _telescopeController.SlewToCoordinates(RightAscension, Declination); } public void SlewToCoordinatesAsync(double RightAscension, double Declination) { - tl.LogMessage("SlewToCoordinatesAsync", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToCoordinatesAsync"); + tl.LogMessage("SlewToCoordinatesAsync", $"Ra={RightAscension}, Dec={Declination}"); + _telescopeController.SlewToCoordinatesAsync(RightAscension, Declination); } public void SlewToTarget() @@ -845,13 +845,14 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("TargetDeclination Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TargetDeclination", false); + var targetDec = _telescopeController.TargetDeclination; + tl.LogMessage("TargetDeclination Get", $"{targetDec}"); + return targetDec; } set - { - tl.LogMessage("TargetDeclination Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TargetDeclination", true); + { + tl.LogMessage("TargetDeclination Set", $"{value}"); + _telescopeController.TargetDeclination = value; } } @@ -859,13 +860,14 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("TargetRightAscension Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TargetRightAscension", false); + var targetRa = _telescopeController.TargetRightAscension; + tl.LogMessage("TargetRightAscension Get", $"{targetRa}"); + return targetRa; } set { - tl.LogMessage("TargetRightAscension Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TargetRightAscension", true); + tl.LogMessage("TargetRightAscension Set", $"{value}"); + _telescopeController.TargetRightAscension = value; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 7815e6f..8bf8d05 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -14,11 +14,16 @@ namespace ASCOM.MeadeAutostar497.Controller double SiteLongitude { get; set; } AlignmentModes AlignmentMode { get; set; } bool AtPark { get; } - double Azimuth { get; } - double Declination { get; } double Altitude { get; } + double Azimuth { get; } + double RightAscension { get; } + double Declination { get; } + double TargetRightAscension { get; set; } + double TargetDeclination { get; set; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); + void SlewToCoordinates(double rightAscension, double declination); + void SlewToCoordinatesAsync(double rightAscension, double declination); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 97757cf..8ebebf5 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -3,12 +3,16 @@ using System.IO.Ports; using System.Linq; using System.Threading; using ASCOM.DeviceInterface; +using ASCOM.Utilities; +using ASCOM.Utilities.Interfaces; namespace ASCOM.MeadeAutostar497.Controller { //todo stop this being a singleton, and instead use a server to make only a single instance. public sealed class TelescopeController : ITelescopeController { + private const double INVALID_PARAMETER = -1000; + private static readonly Lazy Lazy = new Lazy(); public static TelescopeController Instance => Lazy.Value; @@ -33,6 +37,19 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private IUtil _util; + public IUtil Util + { + get => _util ?? (_util = new Util()); + set + { + if (Equals(_util, value)) + return; + + _util = value; + } + } + private string _port = "COM1"; public string Port { @@ -333,6 +350,25 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public double RightAscension { + get + { + var result = SerialPort.CommandTerminated(":GR#", "#"); + //:GR# Get Telescope RA + //Returns: HH: MM.T# or HH:MM:SS# + //Depending which precision is set for the telescope + + double ra = HmsToDouble(result); + + return ra; + } + } + + private double HmsToDouble(string hms) + { + return Util.HMSToHours(hms); + } + public double Declination { get @@ -348,6 +384,89 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private double _targetRightAscension = INVALID_PARAMETER; + public double TargetRightAscension { + get + { + if (_targetRightAscension == INVALID_PARAMETER) + throw new ASCOM.InvalidOperationException("Target not set"); + + var result = SerialPort.CommandTerminated(":Gr#", "#"); + //:Gr# Get current/target object RA + //Returns: HH: MM.T# or HH:MM:SS + //Depending upon which precision is set for the telescope + + double targetDec = HmsToDouble(result); + + return targetDec; + } + set + { + if (value < 0) + throw new ArgumentOutOfRangeException("Right ascension value cannot be below 0"); + + if (value >= 24) + throw new ArgumentOutOfRangeException("Right ascension value cannot be greater than 23:59:59"); + + + //todo implement the low precision version + + var hms = _util.HoursToHMS(value, ":", ":", ":", 2); + var response = SerialPort.CommandChar($":Sr{hms}#"); + //:SrHH:MM.T# + //:SrHH:MM:SS# + //Set target object RA to HH:MM.T or HH: MM: SS depending on the current precision setting. + // Returns: + //0 – Invalid + //1 - Valid + + if (response == '0') + throw new InvalidOperationException("Failed to set TargetRightAscension."); + + _targetRightAscension = value; + } + } + + private double _targetDeclination = INVALID_PARAMETER; + public double TargetDeclination { + get + { + if (_targetDeclination == INVALID_PARAMETER) + throw new ASCOM.InvalidOperationException("Target not set"); + + var result = SerialPort.CommandTerminated(":Gd#", "#"); + //:Gd# Get Currently Selected Object/Target Declination + //Returns: sDD* MM# or sDD*MM’SS# + //Depending upon the current precision setting for the telescope. + + double targetDec = DmsToDouble(result); + + return targetDec; + + } + set + { + //todo implement low precision version of this. + + var dms = _util.DegreesToDMS(value, "*", ":", ":", 2); + var s = value < 0 ? '-' : '+'; + + var result = SerialPort.CommandChar($":Sd{s}{dms}#"); + //:SdsDD*MM# + //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting + //Returns: + //1 - Dec Accepted + //0 – Dec invalid + + if (result == '0') + { + throw new ASCOM.InvalidOperationException("Target declination invalid"); + } + + _targetDeclination = value; + } + } + public double Altitude { get { @@ -410,6 +529,62 @@ namespace ASCOM.MeadeAutostar497.Controller _serialPort.Command(":hP#"); } + public void SlewToCoordinates(double rightAscension, double declination) + { + SlewToCoordinatesAsync(rightAscension, declination); + + while (Slewing) //wait for slew to complete + { + _util.WaitForMilliseconds(200); //be responsive to AbortSlew(); + } + } + + public void SlewToCoordinatesAsync(double rightAscension, double declination) + { + TargetRightAscension = rightAscension; + TargetDeclination = declination; + + DoSlewAsync(); + } + + private void DoSlewAsync() + { + char response = Char.MinValue; + switch (AlignmentMode) + { + case AlignmentModes.algPolar: + response = SerialPort.CommandChar(":MS#"); + //:MS# Slew to Target Object + //Returns: + //0 Slew is Possible + //1# Object Below Horizon w/string message + //2# Object Below Higher w/string message + break; + case AlignmentModes.algAltAz: + break; + default: + throw new ASCOM.NotImplementedException("Not implemented"); + } + + switch (response) + { + case '0': + //We're slewing everything should be working just fine. + break; + case '1': + //Below Horizon + string belowHorizonMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowHorizonMessage); + case '2': + //Below Horizon + string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); + default: + throw new ASCOM.DriverException("This error should not happen"); + + } + } + public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting } } diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index 992d4ef..a0d1525 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -47,15 +47,19 @@ namespace ASCOM //Console.WriteLine(device.UTCDate.ToLocalTime()); - Console.WriteLine(device.AlignmentMode); + //Console.WriteLine(device.AlignmentMode); - double l = device.SiteLatitude; - device.SiteLatitude = l; + + + //double l = device.SiteLatitude; + //device.SiteLatitude = l; //double l = device.SiteLongitude; //device.SiteLongitude = l; //Console.WriteLine(device.SiteLongitude); + Console.WriteLine(device.RightAscension); + device.Connected = false; Console.WriteLine("Press Enter to finish"); Console.ReadLine(); From 76eb088d4e4d0668f73ec98d052c1717d7e835ff Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 20:48:18 +0100 Subject: [PATCH 024/109] Sorted out the target RA and Dec exceptions to be compliant with ascom. --- ConformanceResult.txt | 411 ++++++++---------- .../Controller/TelescopeController.cs | 15 +- 2 files changed, 186 insertions(+), 240 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index dc441b0..a0ac7d9 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -15,257 +15,198 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -20:25:07.406 Driver Access Checks OK -20:25:08.054 AccessChecks OK Successfully created driver using late binding -20:25:08.281 AccessChecks OK Successfully connected using late binding -20:25:08.285 AccessChecks INFO The driver is a .NET object -20:25:08.289 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -20:25:08.294 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -20:25:08.987 AccessChecks INFO Device does not expose interface ITelescopeV2 -20:25:09.814 AccessChecks INFO Device exposes interface ITelescopeV3 -20:25:11.132 AccessChecks OK Successfully created driver using driver access toolkit -20:25:11.305 AccessChecks OK Successfully connected using driver access toolkit +20:45:29.137 Driver Access Checks OK +20:45:29.784 AccessChecks OK Successfully created driver using late binding +20:45:30.017 AccessChecks OK Successfully connected using late binding +20:45:30.021 AccessChecks INFO The driver is a .NET object +20:45:30.025 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +20:45:30.030 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +20:45:30.726 AccessChecks INFO Device does not expose interface ITelescopeV2 +20:45:31.533 AccessChecks INFO Device exposes interface ITelescopeV3 +20:45:32.851 AccessChecks OK Successfully created driver using driver access toolkit +20:45:33.015 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -20:25:12.627 ConformanceCheck OK Driver instance created successfully -20:25:12.842 ConformanceCheck OK Connected OK +20:45:34.339 ConformanceCheck OK Driver instance created successfully +20:45:34.555 ConformanceCheck OK Connected OK Common Driver Methods -20:25:12.886 InterfaceVersion OK 3 -20:25:12.915 Connected OK True -20:25:12.943 Description OK Meade Autostar 497 .net -20:25:12.972 DriverInfo OK Information about the driver itself. Version: 0.0 -20:25:13.000 DriverVersion OK 0.0 -20:25:13.029 Name OK Meade Autostar 497 .net -20:25:13.058 CommandString INFO Conform cannot test the CommandString method -20:25:13.065 CommandBlind INFO Conform cannot test the CommandBlind method -20:25:13.071 CommandBool INFO Conform cannot test the CommandBool method -20:25:13.077 Action INFO Conform cannot test the Action method -20:25:13.088 SupportedActions OK Driver returned an empty action list +20:45:34.596 InterfaceVersion OK 3 +20:45:34.624 Connected OK True +20:45:34.653 Description OK Meade Autostar 497 .net +20:45:34.682 DriverInfo OK Information about the driver itself. Version: 0.0 +20:45:34.712 DriverVersion OK 0.0 +20:45:34.741 Name OK Meade Autostar 497 .net +20:45:34.770 CommandString INFO Conform cannot test the CommandString method +20:45:34.776 CommandBlind INFO Conform cannot test the CommandBlind method +20:45:34.783 CommandBool INFO Conform cannot test the CommandBool method +20:45:34.789 Action INFO Conform cannot test the Action method +20:45:34.796 SupportedActions OK Driver returned an empty action list Can Properties -20:25:13.156 CanFindHome OK False -20:25:13.163 CanPark OK True -20:25:13.170 CanPulseGuide OK True -20:25:13.177 CanSetDeclinationRate OK False -20:25:13.187 CanSetGuideRates OK False -20:25:13.195 CanSetPark OK False -20:25:13.202 CanSetPierSide OK False -20:25:13.215 CanSetRightAscensionRate OK False -20:25:13.222 CanSetTracking OK False -20:25:13.230 CanSlew OK True -20:25:13.237 CanSlewltAz OK True -20:25:13.246 CanSlewAltAzAsync OK True -20:25:13.255 CanSlewAsync OK True -20:25:13.264 CanSync OK True -20:25:13.273 CanSyncAltAz OK False -20:25:13.282 CanUnPark OK False +20:45:34.862 CanFindHome OK False +20:45:34.870 CanPark OK True +20:45:34.877 CanPulseGuide OK True +20:45:34.885 CanSetDeclinationRate OK False +20:45:34.893 CanSetGuideRates OK False +20:45:34.901 CanSetPark OK False +20:45:34.909 CanSetPierSide OK False +20:45:34.920 CanSetRightAscensionRate OK False +20:45:34.928 CanSetTracking OK False +20:45:34.937 CanSlew OK True +20:45:34.945 CanSlewltAz OK True +20:45:34.953 CanSlewAltAzAsync OK True +20:45:34.964 CanSlewAsync OK True +20:45:34.972 CanSync OK True +20:45:34.980 CanSyncAltAz OK False +20:45:34.989 CanUnPark OK False Pre-run Checks -20:25:13.332 Mount Safety INFO Scope is not parked, continuing testing -20:25:13.384 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -20:25:13.392 TimeCheck INFO PC UTCDate: 06-May-2019 19:25:13.392 -20:25:13.517 TimeCheck INFO Mount UTCDate: 02-May-2019 20:31:47.000 +20:45:35.034 Mount Safety INFO Scope is not parked, continuing testing +20:45:35.086 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +20:45:35.094 TimeCheck INFO PC UTCDate: 06-May-2019 19:45:35.094 +20:45:35.215 TimeCheck INFO Mount UTCDate: 02-May-2019 20:52:06.000 Properties -20:25:13.591 AlignmentMode OK algPolar -20:25:13.647 Altitude OK 90.00 -20:25:13.685 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -20:25:13.720 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -20:25:13.752 AtHome OK False -20:25:13.783 AtPark OK False -20:25:13.845 Azimuth OK 22.95 -20:25:13.903 Declination OK 89:59:59.00 -20:25:13.934 DeclinationRate Read OK 0.00 -20:25:13.967 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -20:25:14.000 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.031 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.063 EquatorialSystem OK equLocalTopocentric -20:25:14.096 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.131 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.142 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -20:25:14.174 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.188 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -20:25:14.220 IsPulseGuiding OK False -20:25:14.281 RightAscension OK 01:34:18.00 -20:25:14.313 RightAscensionRate Read OK 0.00 -20:25:14.346 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -20:25:14.380 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.415 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.426 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.437 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.494 SiteLatitude Read OK 00:00:00.00 -20:25:14.534 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -20:25:14.547 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -20:25:14.584 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -20:25:14.641 SiteLongitude Read OK -18:12:00.00 -20:25:14.675 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -20:25:14.690 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -20:25:14.784 SiteLongitude Write OK Legal value -18:12:00.00 degrees written successfully -20:25:14.829 Slewing OK False -20:25:14.863 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.898 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.911 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.946 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -20:25:14.997 SiderealTime OK 09:03:29.25 -20:25:15.009 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 09:03:29.25, ASCOM: 09:09:54.36 -20:25:15.053 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -20:25:15.087 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -20:25:15.100 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -20:25:15.138 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -20:25:15.151 Tracking Read OK True -20:25:15.186 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -20:25:15.226 TrackingRates Found drive rate: driveSidereal -20:25:15.240 TrackingRates OK Drive rates read OK -20:25:15.252 TrackingRates OK Disposed tracking rates OK -20:25:15.288 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -20:25:15.300 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -20:25:15.393 UTCDate Read OK 02-May-2019 20:31:49.000 -20:25:15.555 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:31:49 +20:45:35.292 AlignmentMode OK algPolar +20:45:35.346 Altitude OK 0.00 +20:45:35.383 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.417 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.449 AtHome OK False +20:45:35.484 AtPark OK False +20:45:35.542 Azimuth OK 89.17 +20:45:35.599 Declination OK 00:00:00.00 +20:45:35.633 DeclinationRate Read OK 0.00 +20:45:35.668 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +20:45:35.700 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.733 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.765 EquatorialSystem OK equLocalTopocentric +20:45:35.797 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.829 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.840 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +20:45:35.871 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:35.882 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +20:45:35.914 IsPulseGuiding OK False +20:45:35.971 RightAscension OK 06:19:37.00 +20:45:36.004 RightAscensionRate Read OK 0.00 +20:45:36.036 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +20:45:36.069 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.103 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.115 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.128 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.181 SiteLatitude Read OK 00:00:00.00 +20:45:36.220 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +20:45:36.233 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +20:45:36.275 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +20:45:36.330 SiteLongitude Read OK -21:48:00.00 +20:45:36.367 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +20:45:36.381 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +20:45:36.475 SiteLongitude Write OK Legal value -21:48:00.00 degrees written successfully +20:45:36.515 Slewing OK False +20:45:36.550 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.584 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.596 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.631 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +20:45:36.680 SiderealTime OK 09:14:18.28 +20:45:36.692 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 09:14:18.28, ASCOM: 09:15:55.39 +20:45:36.741 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +20:45:36.776 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +20:45:36.788 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +20:45:36.824 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +20:45:36.836 Tracking Read OK True +20:45:36.871 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +20:45:36.912 TrackingRates Found drive rate: driveSidereal +20:45:36.923 TrackingRates OK Drive rates read OK +20:45:36.935 TrackingRates OK Disposed tracking rates OK +20:45:36.971 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +20:45:36.983 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +20:45:37.131 UTCDate Read OK 02-May-2019 20:52:08.000 +20:45:37.300 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:52:08 Methods -20:25:15.802 CanMoveAxis:Primary OK CanMoveAxis:Primary True -20:25:15.839 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -20:25:15.875 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -20:25:15.913 Park/Unpark INFO Tests skipped -20:25:15.937 AbortSlew OK AbortSlew OK when not slewing -20:25:16.003 AxisRate:Primary OK Empty axis rate returned -20:25:16.015 AxisRate:Primary OK Disposed axis rates OK -20:25:16.028 AxisRate:Secondary OK Empty axis rate returned -20:25:16.039 AxisRate:Secondary OK Disposed axis rates OK -20:25:16.052 AxisRate:Tertiary OK Empty axis rate returned -20:25:16.064 AxisRate:Tertiary OK Disposed axis rates OK -20:25:16.080 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -20:25:16.131 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -20:25:16.143 MoveAxis Primary OK AxisRates object successfully disposed -20:25:16.201 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -20:25:16.213 MoveAxis Secondary OK AxisRates object successfully disposed -20:25:16.270 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -20:25:18.310 PulseGuide OK Synchronous pulse guide found OK -20:25:52.356 SlewToCoordinates OK Slewed OK. RA: 08:03:32.68 -20:25:52.369 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 -20:25:52.403 SlewToCoordinates ERROR The TargetRightAscension property 08:03:32.00 does not match the expected RA 08:03:32.68 -20:25:52.438 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -20:25:52.487 SlewToCoordinates (Bad L) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) -20:26:12.283 SlewToCoordinates (Bad L) ERROR Failed to reject bad Dec coordinate: -100:00:00.00 -20:26:12.343 SlewToCoordinates (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) -20:26:17.522 SlewToCoordinates (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad Dec coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinates System.TimeoutException: The operation has timed out. - at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) - at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) - at System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne) - at System.IO.Ports.SerialPort.ReadTo(String value) - at ASCOM.MeadeAutostar497.Controller.SerialProcessor.ReadTerminated(String terminator) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\SerialProcessor.cs:line 110 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.DoSlewAsync() in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 580 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 547 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinates(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 534 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinates(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 794 (See Inner Exception for details) -20:26:36.353 SlewToCoordinatesAsync OK Slewed OK. RA: 07:04:32.06 -20:26:36.367 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 -20:26:36.400 SlewToCoordinatesAsync OK The TargetRightAscension property 07:04:32.06 matches the expected RA OK. -20:26:36.437 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -20:26:36.478 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) -20:26:36.621 SlewToCoordinatesAsync (Bad L) ERROR Failed to reject bad Dec coordinate: -100:00:00.00 -20:26:36.681 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 544 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) -20:26:41.892 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverException(0x80131500), slewing to bad Dec coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope SlewToCoordinatesAsync System.TimeoutException: The operation has timed out. - at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) - at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) - at System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne) - at System.IO.Ports.SerialPort.ReadTo(String value) - at ASCOM.MeadeAutostar497.Controller.SerialProcessor.ReadTerminated(String terminator) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\SerialProcessor.cs:line 110 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.DoSlewAsync() in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 580 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.SlewToCoordinatesAsync(Double rightAscension, Double declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 547 - at ASCOM.MeadeAutostar497.Telescope.SlewToCoordinatesAsync(Double RightAscension, Double Declination) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 800 (See Inner Exception for details) -20:27:04.329 SyncToCoordinates OK Slewed to start position OK. RA: 06:04:56.54 -20:27:04.343 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -20:27:04.360 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:04.400 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:04.447 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:04.509 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:04.558 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:04.618 TargetRightAscension Write ERROR Unexpected DriverException(0x80131500), : CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:04.636 TargetRightAscension Write ERROR Unexpected DriverException(0x80131500), : CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:04.742 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 05:05:19.25 -20:27:04.825 TargetDeclination Write ISSUE No error generated on set TargetDeclination < -90 degrees -20:27:04.885 TargetDeclination Write ISSUE No error generated on set TargetDeclination > 90 degrees -20:27:04.965 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -20:27:05.118 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:05.160 SlewToTarget (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:05.294 SlewToTarget (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:05.355 SlewToTarget (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:05.490 SlewToTarget (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:05.666 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:05.707 SlewToTargetAsync (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:05.857 SlewToTargetAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:05.921 SlewToTargetAsync (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:06.056 SlewToTargetAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.120 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -20:27:06.139 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:06.185 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.204 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.266 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.284 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.348 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:06.389 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.412 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.475 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:06.493 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:22.333 SyncToTarget INFO Slewed to start position within 18.0 arc seconds of expected RA: 06:05:21.20, actual RA: 06:05:20.00 -20:27:22.348 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -20:27:22.448 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:27:22.490 SyncToTarget (Bad L) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be below 0 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 408 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:22.627 SyncToTarget (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:22.690 SyncToTarget (Bad H) ERROR Unexpected DriverException(0x80131500), Exception setting bad RA coordinate: CheckDotNetExceptions ASCOM.MeadeAutostar497.Telescope TargetRightAscensionSet System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. - Parameter name: Right ascension value cannot be greater than 23:59:59 - at ASCOM.MeadeAutostar497.Controller.TelescopeController.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\Controller\TelescopeController.cs:line 414 - at ASCOM.MeadeAutostar497.Telescope.set_TargetRightAscension(Double value) in D:\Code\BitBucket\cjdSkunkWorks\Ascom\MeadeAutostar497\MeadeAutostar497\AscomClasses\Telescope.cs:line 870 (See Inner Exception for details) -20:27:22.822 SyncToTarget (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:27:22.979 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +20:45:37.548 CanMoveAxis:Primary OK CanMoveAxis:Primary True +20:45:37.585 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +20:45:37.623 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +20:45:37.659 Park/Unpark INFO Tests skipped +20:45:37.681 AbortSlew OK AbortSlew OK when not slewing +20:45:37.747 AxisRate:Primary OK Empty axis rate returned +20:45:37.762 AxisRate:Primary OK Disposed axis rates OK +20:45:37.775 AxisRate:Secondary OK Empty axis rate returned +20:45:37.789 AxisRate:Secondary OK Disposed axis rates OK +20:45:37.801 AxisRate:Tertiary OK Empty axis rate returned +20:45:37.816 AxisRate:Tertiary OK Disposed axis rates OK +20:45:37.830 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +20:45:37.878 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +20:45:37.890 MoveAxis Primary OK AxisRates object successfully disposed +20:45:37.947 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +20:45:37.960 MoveAxis Secondary OK AxisRates object successfully disposed +20:45:38.019 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +20:45:40.058 PulseGuide OK Synchronous pulse guide found OK +20:46:05.666 SlewToCoordinates INFO Slewed within 26.7 arc seconds of expected RA: 08:14:21.78, actual RA: 08:14:20.00 +20:46:05.679 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 +20:46:05.713 SlewToCoordinates ERROR The TargetRightAscension property 08:14:20.00 does not match the expected RA 08:14:21.78 +20:46:05.745 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +20:46:05.794 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +20:46:05.878 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +20:46:05.939 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +20:46:06.019 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +20:46:27.678 SlewToCoordinatesAsync INFO Slewed within 57.0 arc seconds of expected RA: 07:14:47.80, actual RA: 07:14:44.00 +20:46:27.691 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 +20:46:27.727 SlewToCoordinatesAsync ERROR The TargetRightAscension property 07:14:44.00 does not match the expected RA 07:14:47.80 +20:46:27.760 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +20:46:27.804 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +20:46:27.893 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +20:46:27.952 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +20:46:28.034 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +20:46:49.662 SyncToCoordinates INFO Slewed to start position within 28.9 arc seconds of expected RA: 06:15:09.93, actual RA: 06:15:08.00 +20:46:49.675 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +20:46:49.689 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:46:49.727 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:49.770 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:49.833 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:49.879 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:49.938 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +20:46:49.951 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +20:46:50.055 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 05:15:31.81 +20:46:50.091 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +20:46:50.106 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +20:46:50.183 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +20:46:50.339 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:46:50.380 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +20:46:50.428 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +20:46:50.488 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +20:46:50.534 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +20:46:50.704 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:46:50.745 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +20:46:50.791 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +20:46:50.850 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +20:46:50.903 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +20:46:50.964 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +20:46:50.981 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:46:51.025 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.041 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.104 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.122 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.184 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:46:51.224 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.241 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.303 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:46:51.323 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +20:47:05.652 SyncToTarget INFO Slewed to start position within 19.1 arc seconds of expected RA: 06:15:33.27, actual RA: 06:15:32.00 +20:47:05.666 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +20:47:05.767 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +20:47:05.805 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +20:47:05.851 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +20:47:05.910 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +20:47:05.953 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +20:47:06.111 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -20:27:23.049 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +20:47:06.180 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -20:27:23.142 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +20:47:06.269 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 17 errors, 2 warnings and 27 issues +Your driver had 2 errors, 2 warnings and 19 issues diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 8ebebf5..6b5047c 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -396,17 +396,16 @@ namespace ASCOM.MeadeAutostar497.Controller //Returns: HH: MM.T# or HH:MM:SS //Depending upon which precision is set for the telescope - double targetDec = HmsToDouble(result); - - return targetDec; + double targetRa = HmsToDouble(result); + return targetRa; } set { if (value < 0) - throw new ArgumentOutOfRangeException("Right ascension value cannot be below 0"); + throw new InvalidValueException("Right ascension value cannot be below 0"); if (value >= 24) - throw new ArgumentOutOfRangeException("Right ascension value cannot be greater than 23:59:59"); + throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); //todo implement the low precision version @@ -447,6 +446,12 @@ namespace ASCOM.MeadeAutostar497.Controller set { //todo implement low precision version of this. + if (value > 90) + throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); + + if (value < -90) + throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); + var dms = _util.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? '-' : '+'; From eab151d295780e7e8d77114d45bce0edbf2db714 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 22:43:01 +0100 Subject: [PATCH 025/109] Implemented SlewToAltAz and SlewToAltAzAsync --- ConformanceResult.txt | 354 +++++++++--------- MeadeAutostar497/AscomClasses/Telescope.cs | 8 +- .../Controller/ITelescopeController.cs | 2 + .../Controller/TelescopeController.cs | 140 +++++-- TestConsole/Program.cs | 4 +- 5 files changed, 296 insertions(+), 212 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index a0ac7d9..650e929 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -15,198 +15,200 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -20:45:29.137 Driver Access Checks OK -20:45:29.784 AccessChecks OK Successfully created driver using late binding -20:45:30.017 AccessChecks OK Successfully connected using late binding -20:45:30.021 AccessChecks INFO The driver is a .NET object -20:45:30.025 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -20:45:30.030 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -20:45:30.726 AccessChecks INFO Device does not expose interface ITelescopeV2 -20:45:31.533 AccessChecks INFO Device exposes interface ITelescopeV3 -20:45:32.851 AccessChecks OK Successfully created driver using driver access toolkit -20:45:33.015 AccessChecks OK Successfully connected using driver access toolkit +22:39:40.567 Driver Access Checks OK +22:39:41.211 AccessChecks OK Successfully created driver using late binding +22:39:41.436 AccessChecks OK Successfully connected using late binding +22:39:41.441 AccessChecks INFO The driver is a .NET object +22:39:41.445 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +22:39:41.450 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +22:39:42.146 AccessChecks INFO Device does not expose interface ITelescopeV2 +22:39:42.952 AccessChecks INFO Device exposes interface ITelescopeV3 +22:39:44.265 AccessChecks OK Successfully created driver using driver access toolkit +22:39:44.439 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -20:45:34.339 ConformanceCheck OK Driver instance created successfully -20:45:34.555 ConformanceCheck OK Connected OK +22:39:45.760 ConformanceCheck OK Driver instance created successfully +22:39:45.978 ConformanceCheck OK Connected OK Common Driver Methods -20:45:34.596 InterfaceVersion OK 3 -20:45:34.624 Connected OK True -20:45:34.653 Description OK Meade Autostar 497 .net -20:45:34.682 DriverInfo OK Information about the driver itself. Version: 0.0 -20:45:34.712 DriverVersion OK 0.0 -20:45:34.741 Name OK Meade Autostar 497 .net -20:45:34.770 CommandString INFO Conform cannot test the CommandString method -20:45:34.776 CommandBlind INFO Conform cannot test the CommandBlind method -20:45:34.783 CommandBool INFO Conform cannot test the CommandBool method -20:45:34.789 Action INFO Conform cannot test the Action method -20:45:34.796 SupportedActions OK Driver returned an empty action list +22:39:46.020 InterfaceVersion OK 3 +22:39:46.047 Connected OK True +22:39:46.075 Description OK Meade Autostar 497 .net +22:39:46.104 DriverInfo OK Information about the driver itself. Version: 0.0 +22:39:46.133 DriverVersion OK 0.0 +22:39:46.163 Name OK Meade Autostar 497 .net +22:39:46.192 CommandString INFO Conform cannot test the CommandString method +22:39:46.198 CommandBlind INFO Conform cannot test the CommandBlind method +22:39:46.204 CommandBool INFO Conform cannot test the CommandBool method +22:39:46.211 Action INFO Conform cannot test the Action method +22:39:46.218 SupportedActions OK Driver returned an empty action list Can Properties -20:45:34.862 CanFindHome OK False -20:45:34.870 CanPark OK True -20:45:34.877 CanPulseGuide OK True -20:45:34.885 CanSetDeclinationRate OK False -20:45:34.893 CanSetGuideRates OK False -20:45:34.901 CanSetPark OK False -20:45:34.909 CanSetPierSide OK False -20:45:34.920 CanSetRightAscensionRate OK False -20:45:34.928 CanSetTracking OK False -20:45:34.937 CanSlew OK True -20:45:34.945 CanSlewltAz OK True -20:45:34.953 CanSlewAltAzAsync OK True -20:45:34.964 CanSlewAsync OK True -20:45:34.972 CanSync OK True -20:45:34.980 CanSyncAltAz OK False -20:45:34.989 CanUnPark OK False +22:39:46.283 CanFindHome OK False +22:39:46.290 CanPark OK True +22:39:46.299 CanPulseGuide OK True +22:39:46.307 CanSetDeclinationRate OK False +22:39:46.315 CanSetGuideRates OK False +22:39:46.322 CanSetPark OK False +22:39:46.330 CanSetPierSide OK False +22:39:46.383 CanSetRightAscensionRate OK False +22:39:46.391 CanSetTracking OK False +22:39:46.399 CanSlew OK True +22:39:46.407 CanSlewltAz OK True +22:39:46.415 CanSlewAltAzAsync OK True +22:39:46.424 CanSlewAsync OK True +22:39:46.432 CanSync OK True +22:39:46.440 CanSyncAltAz OK False +22:39:46.449 CanUnPark OK False Pre-run Checks -20:45:35.034 Mount Safety INFO Scope is not parked, continuing testing -20:45:35.086 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -20:45:35.094 TimeCheck INFO PC UTCDate: 06-May-2019 19:45:35.094 -20:45:35.215 TimeCheck INFO Mount UTCDate: 02-May-2019 20:52:06.000 +22:39:46.496 Mount Safety INFO Scope is not parked, continuing testing +22:39:46.557 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +22:39:46.565 TimeCheck INFO PC UTCDate: 06-May-2019 21:39:46.565 +22:39:46.687 TimeCheck INFO Mount UTCDate: 02-May-2019 19:20:28.000 Properties -20:45:35.292 AlignmentMode OK algPolar -20:45:35.346 Altitude OK 0.00 -20:45:35.383 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.417 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.449 AtHome OK False -20:45:35.484 AtPark OK False -20:45:35.542 Azimuth OK 89.17 -20:45:35.599 Declination OK 00:00:00.00 -20:45:35.633 DeclinationRate Read OK 0.00 -20:45:35.668 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -20:45:35.700 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.733 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.765 EquatorialSystem OK equLocalTopocentric -20:45:35.797 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.829 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.840 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -20:45:35.871 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:35.882 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -20:45:35.914 IsPulseGuiding OK False -20:45:35.971 RightAscension OK 06:19:37.00 -20:45:36.004 RightAscensionRate Read OK 0.00 -20:45:36.036 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -20:45:36.069 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.103 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.115 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.128 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.181 SiteLatitude Read OK 00:00:00.00 -20:45:36.220 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -20:45:36.233 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -20:45:36.275 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -20:45:36.330 SiteLongitude Read OK -21:48:00.00 -20:45:36.367 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -20:45:36.381 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -20:45:36.475 SiteLongitude Write OK Legal value -21:48:00.00 degrees written successfully -20:45:36.515 Slewing OK False -20:45:36.550 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.584 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.596 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.631 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -20:45:36.680 SiderealTime OK 09:14:18.28 -20:45:36.692 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 09:14:18.28, ASCOM: 09:15:55.39 -20:45:36.741 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -20:45:36.776 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -20:45:36.788 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -20:45:36.824 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -20:45:36.836 Tracking Read OK True -20:45:36.871 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -20:45:36.912 TrackingRates Found drive rate: driveSidereal -20:45:36.923 TrackingRates OK Drive rates read OK -20:45:36.935 TrackingRates OK Disposed tracking rates OK -20:45:36.971 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -20:45:36.983 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -20:45:37.131 UTCDate Read OK 02-May-2019 20:52:08.000 -20:45:37.300 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:52:08 +22:39:46.762 AlignmentMode OK algPolar +22:39:46.813 Altitude OK 0.00 +22:39:46.850 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +22:39:46.885 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +22:39:46.917 AtHome OK False +22:39:46.949 AtPark OK False +22:39:47.007 Azimuth OK 127.45 +22:39:47.063 Declination OK 00:00:00.00 +22:39:47.098 DeclinationRate Read OK 0.00 +22:39:47.132 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +22:39:47.165 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.196 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.231 EquatorialSystem OK equLocalTopocentric +22:39:47.263 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.298 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.308 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +22:39:47.341 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.352 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +22:39:47.384 IsPulseGuiding OK False +22:39:47.443 RightAscension OK 08:00:45.00 +22:39:47.476 RightAscensionRate Read OK 0.00 +22:39:47.508 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +22:39:47.542 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.576 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.587 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.597 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:47.655 SiteLatitude Read OK 00:00:00.00 +22:39:47.693 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +22:39:47.705 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +22:39:47.739 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +22:39:47.794 SiteLongitude Read OK -25:48:00.00 +22:39:47.828 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +22:39:47.839 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +22:39:47.936 SiteLongitude Write OK Legal value -25:48:00.00 degrees written successfully +22:39:47.979 Slewing OK False +22:39:48.013 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:48.047 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:48.063 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +22:39:48.098 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +22:39:48.153 SiderealTime OK 10:52:48.51 +22:39:48.166 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:52:48.51, ASCOM: 10:54:25.62 +22:39:48.209 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +22:39:48.243 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +22:39:48.255 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +22:39:48.290 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +22:39:48.301 Tracking Read OK True +22:39:48.336 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +22:39:48.377 TrackingRates Found drive rate: driveSidereal +22:39:48.390 TrackingRates OK Drive rates read OK +22:39:48.401 TrackingRates OK Disposed tracking rates OK +22:39:48.436 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +22:39:48.448 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +22:39:48.543 UTCDate Read OK 02-May-2019 19:20:30.000 +22:39:48.707 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:20:30 Methods -20:45:37.548 CanMoveAxis:Primary OK CanMoveAxis:Primary True -20:45:37.585 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -20:45:37.623 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -20:45:37.659 Park/Unpark INFO Tests skipped -20:45:37.681 AbortSlew OK AbortSlew OK when not slewing -20:45:37.747 AxisRate:Primary OK Empty axis rate returned -20:45:37.762 AxisRate:Primary OK Disposed axis rates OK -20:45:37.775 AxisRate:Secondary OK Empty axis rate returned -20:45:37.789 AxisRate:Secondary OK Disposed axis rates OK -20:45:37.801 AxisRate:Tertiary OK Empty axis rate returned -20:45:37.816 AxisRate:Tertiary OK Disposed axis rates OK -20:45:37.830 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -20:45:37.878 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -20:45:37.890 MoveAxis Primary OK AxisRates object successfully disposed -20:45:37.947 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -20:45:37.960 MoveAxis Secondary OK AxisRates object successfully disposed -20:45:38.019 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -20:45:40.058 PulseGuide OK Synchronous pulse guide found OK -20:46:05.666 SlewToCoordinates INFO Slewed within 26.7 arc seconds of expected RA: 08:14:21.78, actual RA: 08:14:20.00 -20:46:05.679 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 -20:46:05.713 SlewToCoordinates ERROR The TargetRightAscension property 08:14:20.00 does not match the expected RA 08:14:21.78 -20:46:05.745 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -20:46:05.794 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -20:46:05.878 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -20:46:05.939 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -20:46:06.019 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -20:46:27.678 SlewToCoordinatesAsync INFO Slewed within 57.0 arc seconds of expected RA: 07:14:47.80, actual RA: 07:14:44.00 -20:46:27.691 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 -20:46:27.727 SlewToCoordinatesAsync ERROR The TargetRightAscension property 07:14:44.00 does not match the expected RA 07:14:47.80 -20:46:27.760 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -20:46:27.804 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -20:46:27.893 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -20:46:27.952 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -20:46:28.034 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -20:46:49.662 SyncToCoordinates INFO Slewed to start position within 28.9 arc seconds of expected RA: 06:15:09.93, actual RA: 06:15:08.00 -20:46:49.675 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -20:46:49.689 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:46:49.727 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:49.770 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:49.833 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:49.879 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:49.938 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -20:46:49.951 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -20:46:50.055 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 05:15:31.81 -20:46:50.091 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -20:46:50.106 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -20:46:50.183 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -20:46:50.339 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:46:50.380 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -20:46:50.428 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -20:46:50.488 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -20:46:50.534 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -20:46:50.704 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:46:50.745 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -20:46:50.791 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -20:46:50.850 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -20:46:50.903 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -20:46:50.964 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -20:46:50.981 SlewToAltAz ISSUE CanSlewAltAz is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:46:51.025 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.041 SlewToAltAz (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.104 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.122 SlewToAltAz (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.184 SlewToAltAzAsync ISSUE CanSlewAltAzAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:46:51.224 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.241 SlewToAltAzAsync (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.303 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:46:51.323 SlewToAltAzAsync (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -20:47:05.652 SyncToTarget INFO Slewed to start position within 19.1 arc seconds of expected RA: 06:15:33.27, actual RA: 06:15:32.00 -20:47:05.666 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -20:47:05.767 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -20:47:05.805 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -20:47:05.851 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -20:47:05.910 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -20:47:05.953 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -20:47:06.111 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +22:39:48.953 CanMoveAxis:Primary OK CanMoveAxis:Primary True +22:39:48.988 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +22:39:49.023 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +22:39:49.058 Park/Unpark INFO Tests skipped +22:39:49.080 AbortSlew OK AbortSlew OK when not slewing +22:39:49.150 AxisRate:Primary OK Empty axis rate returned +22:39:49.164 AxisRate:Primary OK Disposed axis rates OK +22:39:49.176 AxisRate:Secondary OK Empty axis rate returned +22:39:49.188 AxisRate:Secondary OK Disposed axis rates OK +22:39:49.201 AxisRate:Tertiary OK Empty axis rate returned +22:39:49.213 AxisRate:Tertiary OK Disposed axis rates OK +22:39:49.228 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +22:39:49.280 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +22:39:49.292 MoveAxis Primary OK AxisRates object successfully disposed +22:39:49.349 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +22:39:49.364 MoveAxis Secondary OK AxisRates object successfully disposed +22:39:49.421 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +22:39:51.460 PulseGuide OK Synchronous pulse guide found OK +22:40:15.151 SlewToCoordinates INFO Slewed within 59.1 arc seconds of expected RA: 09:52:51.94, actual RA: 09:52:48.00 +22:40:15.163 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 +22:40:15.195 SlewToCoordinates ERROR The TargetRightAscension property 09:52:48.00 does not match the expected RA 09:52:51.94 +22:40:15.227 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +22:40:15.277 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +22:40:15.358 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +22:40:15.417 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +22:40:15.501 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +22:40:36.950 SlewToCoordinatesAsync OK Slewed OK. RA: 08:53:16.03 +22:40:36.963 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 +22:40:36.996 SlewToCoordinatesAsync OK The TargetRightAscension property 08:53:16.03 matches the expected RA OK. +22:40:37.037 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +22:40:37.079 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +22:40:37.163 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +22:40:37.228 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +22:40:37.311 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +22:40:58.937 SyncToCoordinates INFO Slewed to start position within 29.3 arc seconds of expected RA: 07:53:37.95, actual RA: 07:53:36.00 +22:40:58.950 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +22:40:58.965 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:40:59.004 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +22:40:59.048 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +22:40:59.112 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +22:40:59.156 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. +22:40:59.216 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +22:40:59.232 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +22:40:59.335 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 06:53:59.84 +22:40:59.371 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +22:40:59.389 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +22:40:59.464 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +22:40:59.616 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:40:59.656 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +22:40:59.700 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +22:40:59.758 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +22:40:59.800 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +22:40:59.972 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:41:00.010 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +22:41:00.053 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +22:41:00.113 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +22:41:00.171 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +22:41:00.229 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +22:41:00.498 SlewToAltAz INFO Slewed to within 24:39:03.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +22:41:00.512 SlewToAltAz INFO Slewed to within 49:59:59.00 DD:MM:SS of expected Altitude: 50:00:00.00 +22:41:00.554 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +22:41:00.609 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +22:41:00.670 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +22:41:00.733 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +22:41:06.055 SlewToAltAzAsync INFO Slewed to within 29:38:15.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +22:41:06.069 SlewToAltAzAsync INFO Slewed to within 54:59:59.00 DD:MM:SS of expected Altitude: 55:00:00.00 +22:41:06.110 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +22:41:06.169 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +22:41:06.229 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +22:41:06.341 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +22:41:20.933 SyncToTarget INFO Slewed to start position within 45.9 arc seconds of expected RA: 07:54:07.06, actual RA: 07:54:04.00 +22:41:20.947 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +22:41:21.041 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:41:21.079 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +22:41:21.124 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +22:41:21.184 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +22:41:21.229 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +22:41:21.383 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -20:47:06.180 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +22:41:21.449 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -20:47:06.269 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +22:41:21.545 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 2 errors, 2 warnings and 19 issues +Your driver had 1 error, 2 warnings and 9 issues diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index c11a5c5..336156d 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -778,14 +778,14 @@ namespace ASCOM.MeadeAutostar497 public void SlewToAltAz(double Azimuth, double Altitude) { - tl.LogMessage("SlewToAltAz", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToAltAz"); + tl.LogMessage("SlewToAltAz", $"Az=~{Azimuth} Alt={Altitude}"); + _telescopeController.SlewToAltAz(Azimuth, Altitude); } public void SlewToAltAzAsync(double Azimuth, double Altitude) { - tl.LogMessage("SlewToAltAzAsync", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToAltAzAsync"); + tl.LogMessage("SlewToAltAzAsync", $"Az=~{Azimuth} Alt={Altitude}"); + _telescopeController.SlewToAltAzAsync(Azimuth, Altitude); } public void SlewToCoordinates(double RightAscension, double Declination) diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 8bf8d05..a1ac58c 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -25,5 +25,7 @@ namespace ASCOM.MeadeAutostar497.Controller void Park(); void SlewToCoordinates(double rightAscension, double declination); void SlewToCoordinatesAsync(double rightAscension, double declination); + void SlewToAltAz(double azimuth, double altitude); + void SlewToAltAzAsync(double azimuth, double altitude); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 6b5047c..cf56ace 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -410,7 +410,7 @@ namespace ASCOM.MeadeAutostar497.Controller //todo implement the low precision version - var hms = _util.HoursToHMS(value, ":", ":", ":", 2); + var hms = Util.HoursToHMS(value, ":", ":", ":", 2); var response = SerialPort.CommandChar($":Sr{hms}#"); //:SrHH:MM.T# //:SrHH:MM:SS# @@ -453,7 +453,7 @@ namespace ASCOM.MeadeAutostar497.Controller throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); - var dms = _util.DegreesToDMS(value, "*", ":", ":", 2); + var dms = Util.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? '-' : '+'; var result = SerialPort.CommandChar($":Sd{s}{dms}#"); @@ -540,7 +540,7 @@ namespace ASCOM.MeadeAutostar497.Controller while (Slewing) //wait for slew to complete { - _util.WaitForMilliseconds(200); //be responsive to AbortSlew(); + Util.WaitForMilliseconds(200); //be responsive to AbortSlew(); } } @@ -549,45 +549,123 @@ namespace ASCOM.MeadeAutostar497.Controller TargetRightAscension = rightAscension; TargetDeclination = declination; - DoSlewAsync(); + DoSlewAsync(true); } - private void DoSlewAsync() + public void SlewToAltAz(double azimuth, double altitude) { - char response = Char.MinValue; - switch (AlignmentMode) + SlewToAltAzAsync(azimuth, altitude); + + while (Slewing) //wait for slew to complete { - case AlignmentModes.algPolar: - response = SerialPort.CommandChar(":MS#"); + Util.WaitForMilliseconds(200); //be responsive to AbortSlew(); + } + } + + private double TargetAltitude + { + set + { + if (value > 90) + throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); + + if (value < 0) + throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + + + var dms = Util.DegreesToDMS(value, "*", "'", ".", 2); + var s = value < 0 ? '-' : '+'; + + var result = SerialPort.CommandChar($":Sa{s}{dms}#"); + //:SasDD*MM# + //Set target object altitude to sDD*MM# or sDD*MM’SS# [LX 16â€, Autostar, Autostar II] + //Returns: + //1 Object within slew range + //0 Object out of slew range + + if (result == '0') + throw new ASCOM.InvalidOperationException("Target altitude out of slew range"); + } + } + + private double TargetAzimuth + { + set + { + if (value >= 360) + throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); + + if (value < 0) + throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + + var dms = Util.DegreesToDM(value, "*", ":", 2); + + var result = SerialPort.CommandChar($":Sd{dms}#"); + //:SzDDD*MM# + //Sets the target Object Azimuth[LX 16†and Autostar II only] + //Returns: + //0 – Invalid + //1 - Valid + + if (result == '0') + throw new ASCOM.InvalidOperationException("Target Azimuth out of slew range"); + + } + } + + public void SlewToAltAzAsync(double azimuth, double altitude) + { + TargetAltitude = altitude; + TargetAzimuth = azimuth; + + DoSlewAsync(false); + } + + //todo remove the polar parameter and split method into two. + private void DoSlewAsync( bool polar) + { + switch (polar) + { + case true: + var response = SerialPort.CommandChar(":MS#"); //:MS# Slew to Target Object //Returns: //0 Slew is Possible //1# Object Below Horizon w/string message //2# Object Below Higher w/string message - break; - case AlignmentModes.algAltAz: - break; - default: - throw new ASCOM.NotImplementedException("Not implemented"); - } - switch (response) - { - case '0': - //We're slewing everything should be working just fine. - break; - case '1': - //Below Horizon - string belowHorizonMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowHorizonMessage); - case '2': - //Below Horizon - string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); - default: - throw new ASCOM.DriverException("This error should not happen"); + switch (response) + { + case '0': + //We're slewing everything should be working just fine. + break; + case '1': + //Below Horizon + string belowHorizonMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowHorizonMessage); + case '2': + //Below Horizon + string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); + default: + throw new ASCOM.DriverException("This error should not happen"); - } + } + break; + case false: + var maResponse = SerialPort.CommandChar(":MA#"); + //:MA# Autostar, LX 16â€, Autostar II – Slew to target Alt and Az + //Returns: + //0 - No fault + //1 – Fault + // LX200 – Not supported + + if (maResponse == '1') + { + throw new ASCOM.InvalidOperationException("fault"); + } + break; + } } public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index a0d1525..e906485 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -58,7 +58,9 @@ namespace ASCOM //device.SiteLongitude = l; //Console.WriteLine(device.SiteLongitude); - Console.WriteLine(device.RightAscension); + //Console.WriteLine(device.RightAscension); + + device.SlewToAltAz(0,0); device.Connected = false; Console.WriteLine("Press Enter to finish"); From 56febb46ccbde744ff101f609c3c0ea141df528a Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 23:00:58 +0100 Subject: [PATCH 026/109] Implemented SyncToTarget functionality --- ConformanceResult.txt | 372 +++++++++--------- MeadeAutostar497/AscomClasses/Telescope.cs | 17 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 12 + 4 files changed, 218 insertions(+), 184 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index 650e929..f90bf18 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -15,200 +15,216 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -22:39:40.567 Driver Access Checks OK -22:39:41.211 AccessChecks OK Successfully created driver using late binding -22:39:41.436 AccessChecks OK Successfully connected using late binding -22:39:41.441 AccessChecks INFO The driver is a .NET object -22:39:41.445 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -22:39:41.450 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -22:39:42.146 AccessChecks INFO Device does not expose interface ITelescopeV2 -22:39:42.952 AccessChecks INFO Device exposes interface ITelescopeV3 -22:39:44.265 AccessChecks OK Successfully created driver using driver access toolkit -22:39:44.439 AccessChecks OK Successfully connected using driver access toolkit +22:57:13.923 Driver Access Checks OK +22:57:14.570 AccessChecks OK Successfully created driver using late binding +22:57:14.797 AccessChecks OK Successfully connected using late binding +22:57:14.802 AccessChecks INFO The driver is a .NET object +22:57:14.806 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +22:57:14.811 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +22:57:15.505 AccessChecks INFO Device does not expose interface ITelescopeV2 +22:57:16.310 AccessChecks INFO Device exposes interface ITelescopeV3 +22:57:17.625 AccessChecks OK Successfully created driver using driver access toolkit +22:57:17.798 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -22:39:45.760 ConformanceCheck OK Driver instance created successfully -22:39:45.978 ConformanceCheck OK Connected OK +22:57:19.118 ConformanceCheck OK Driver instance created successfully +22:57:19.335 ConformanceCheck OK Connected OK Common Driver Methods -22:39:46.020 InterfaceVersion OK 3 -22:39:46.047 Connected OK True -22:39:46.075 Description OK Meade Autostar 497 .net -22:39:46.104 DriverInfo OK Information about the driver itself. Version: 0.0 -22:39:46.133 DriverVersion OK 0.0 -22:39:46.163 Name OK Meade Autostar 497 .net -22:39:46.192 CommandString INFO Conform cannot test the CommandString method -22:39:46.198 CommandBlind INFO Conform cannot test the CommandBlind method -22:39:46.204 CommandBool INFO Conform cannot test the CommandBool method -22:39:46.211 Action INFO Conform cannot test the Action method -22:39:46.218 SupportedActions OK Driver returned an empty action list +22:57:19.376 InterfaceVersion OK 3 +22:57:19.403 Connected OK True +22:57:19.431 Description OK Meade Autostar 497 .net +22:57:19.459 DriverInfo OK Information about the driver itself. Version: 0.0 +22:57:19.488 DriverVersion OK 0.0 +22:57:19.517 Name OK Meade Autostar 497 .net +22:57:19.545 CommandString INFO Conform cannot test the CommandString method +22:57:19.551 CommandBlind INFO Conform cannot test the CommandBlind method +22:57:19.557 CommandBool INFO Conform cannot test the CommandBool method +22:57:19.563 Action INFO Conform cannot test the Action method +22:57:19.569 SupportedActions OK Driver returned an empty action list Can Properties -22:39:46.283 CanFindHome OK False -22:39:46.290 CanPark OK True -22:39:46.299 CanPulseGuide OK True -22:39:46.307 CanSetDeclinationRate OK False -22:39:46.315 CanSetGuideRates OK False -22:39:46.322 CanSetPark OK False -22:39:46.330 CanSetPierSide OK False -22:39:46.383 CanSetRightAscensionRate OK False -22:39:46.391 CanSetTracking OK False -22:39:46.399 CanSlew OK True -22:39:46.407 CanSlewltAz OK True -22:39:46.415 CanSlewAltAzAsync OK True -22:39:46.424 CanSlewAsync OK True -22:39:46.432 CanSync OK True -22:39:46.440 CanSyncAltAz OK False -22:39:46.449 CanUnPark OK False +22:57:19.635 CanFindHome OK False +22:57:19.642 CanPark OK True +22:57:19.648 CanPulseGuide OK True +22:57:19.656 CanSetDeclinationRate OK False +22:57:19.664 CanSetGuideRates OK False +22:57:19.673 CanSetPark OK False +22:57:19.682 CanSetPierSide OK False +22:57:19.696 CanSetRightAscensionRate OK False +22:57:19.704 CanSetTracking OK False +22:57:19.712 CanSlew OK True +22:57:19.720 CanSlewltAz OK True +22:57:19.729 CanSlewAltAzAsync OK True +22:57:19.737 CanSlewAsync OK True +22:57:19.746 CanSync OK True +22:57:19.754 CanSyncAltAz OK False +22:57:19.763 CanUnPark OK False Pre-run Checks -22:39:46.496 Mount Safety INFO Scope is not parked, continuing testing -22:39:46.557 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -22:39:46.565 TimeCheck INFO PC UTCDate: 06-May-2019 21:39:46.565 -22:39:46.687 TimeCheck INFO Mount UTCDate: 02-May-2019 19:20:28.000 +22:57:19.809 Mount Safety INFO Scope is not parked, continuing testing +22:57:19.861 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +22:57:19.869 TimeCheck INFO PC UTCDate: 06-May-2019 21:57:19.869 +22:57:19.998 TimeCheck INFO Mount UTCDate: 02-May-2019 19:38:00.000 Properties -22:39:46.762 AlignmentMode OK algPolar -22:39:46.813 Altitude OK 0.00 -22:39:46.850 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -22:39:46.885 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -22:39:46.917 AtHome OK False -22:39:46.949 AtPark OK False -22:39:47.007 Azimuth OK 127.45 -22:39:47.063 Declination OK 00:00:00.00 -22:39:47.098 DeclinationRate Read OK 0.00 -22:39:47.132 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -22:39:47.165 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.196 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.231 EquatorialSystem OK equLocalTopocentric -22:39:47.263 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.298 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.308 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -22:39:47.341 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.352 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -22:39:47.384 IsPulseGuiding OK False -22:39:47.443 RightAscension OK 08:00:45.00 -22:39:47.476 RightAscensionRate Read OK 0.00 -22:39:47.508 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -22:39:47.542 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.576 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.587 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.597 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:47.655 SiteLatitude Read OK 00:00:00.00 -22:39:47.693 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -22:39:47.705 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -22:39:47.739 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -22:39:47.794 SiteLongitude Read OK -25:48:00.00 -22:39:47.828 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -22:39:47.839 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -22:39:47.936 SiteLongitude Write OK Legal value -25:48:00.00 degrees written successfully -22:39:47.979 Slewing OK False -22:39:48.013 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:48.047 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:48.063 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -22:39:48.098 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -22:39:48.153 SiderealTime OK 10:52:48.51 -22:39:48.166 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:52:48.51, ASCOM: 10:54:25.62 -22:39:48.209 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -22:39:48.243 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -22:39:48.255 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -22:39:48.290 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -22:39:48.301 Tracking Read OK True -22:39:48.336 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -22:39:48.377 TrackingRates Found drive rate: driveSidereal -22:39:48.390 TrackingRates OK Drive rates read OK -22:39:48.401 TrackingRates OK Disposed tracking rates OK -22:39:48.436 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -22:39:48.448 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -22:39:48.543 UTCDate Read OK 02-May-2019 19:20:30.000 -22:39:48.707 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:20:30 +22:57:20.071 AlignmentMode OK algPolar +22:57:20.123 Altitude OK 0.00 +22:57:20.161 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.195 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.227 AtHome OK False +22:57:20.258 AtPark OK False +22:57:20.317 Azimuth OK 122.84 +22:57:20.375 Declination OK -00:00:02.00 +22:57:20.406 DeclinationRate Read OK 0.00 +22:57:20.438 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +22:57:20.470 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.506 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.538 EquatorialSystem OK equLocalTopocentric +22:57:20.570 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.606 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.616 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +22:57:20.649 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.660 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +22:57:20.692 IsPulseGuiding OK False +22:57:20.755 RightAscension OK 07:59:56.00 +22:57:20.790 RightAscensionRate Read OK 0.00 +22:57:20.823 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +22:57:20.856 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.890 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.902 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.912 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:20.969 SiteLatitude Read OK 00:00:00.00 +22:57:21.007 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +22:57:21.019 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +22:57:21.058 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +22:57:21.114 SiteLongitude Read OK -27:48:00.00 +22:57:21.150 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +22:57:21.162 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +22:57:21.256 SiteLongitude Write OK Legal value -27:48:00.00 degrees written successfully +22:57:21.296 Slewing OK False +22:57:21.333 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:21.367 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:21.379 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +22:57:21.414 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +22:57:21.465 SiderealTime OK 11:02:24.71 +22:57:21.477 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 11:02:24.71, ASCOM: 11:04:01.82 +22:57:21.520 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +22:57:21.554 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +22:57:21.566 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +22:57:21.601 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +22:57:21.613 Tracking Read OK True +22:57:21.647 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +22:57:21.688 TrackingRates Found drive rate: driveSidereal +22:57:21.702 TrackingRates OK Drive rates read OK +22:57:21.716 TrackingRates OK Disposed tracking rates OK +22:57:21.751 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +22:57:21.763 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +22:57:21.854 UTCDate Read OK 02-May-2019 19:38:02.000 +22:57:22.019 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:38:02 Methods -22:39:48.953 CanMoveAxis:Primary OK CanMoveAxis:Primary True -22:39:48.988 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -22:39:49.023 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -22:39:49.058 Park/Unpark INFO Tests skipped -22:39:49.080 AbortSlew OK AbortSlew OK when not slewing -22:39:49.150 AxisRate:Primary OK Empty axis rate returned -22:39:49.164 AxisRate:Primary OK Disposed axis rates OK -22:39:49.176 AxisRate:Secondary OK Empty axis rate returned -22:39:49.188 AxisRate:Secondary OK Disposed axis rates OK -22:39:49.201 AxisRate:Tertiary OK Empty axis rate returned -22:39:49.213 AxisRate:Tertiary OK Disposed axis rates OK -22:39:49.228 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -22:39:49.280 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -22:39:49.292 MoveAxis Primary OK AxisRates object successfully disposed -22:39:49.349 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -22:39:49.364 MoveAxis Secondary OK AxisRates object successfully disposed -22:39:49.421 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -22:39:51.460 PulseGuide OK Synchronous pulse guide found OK -22:40:15.151 SlewToCoordinates INFO Slewed within 59.1 arc seconds of expected RA: 09:52:51.94, actual RA: 09:52:48.00 -22:40:15.163 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 -22:40:15.195 SlewToCoordinates ERROR The TargetRightAscension property 09:52:48.00 does not match the expected RA 09:52:51.94 -22:40:15.227 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -22:40:15.277 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -22:40:15.358 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -22:40:15.417 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -22:40:15.501 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -22:40:36.950 SlewToCoordinatesAsync OK Slewed OK. RA: 08:53:16.03 -22:40:36.963 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 -22:40:36.996 SlewToCoordinatesAsync OK The TargetRightAscension property 08:53:16.03 matches the expected RA OK. -22:40:37.037 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -22:40:37.079 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -22:40:37.163 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -22:40:37.228 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -22:40:37.311 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -22:40:58.937 SyncToCoordinates INFO Slewed to start position within 29.3 arc seconds of expected RA: 07:53:37.95, actual RA: 07:53:36.00 -22:40:58.950 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -22:40:58.965 SyncToCoordinates ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:40:59.004 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -22:40:59.048 SyncToCoordinates (Bad L) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -22:40:59.112 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -22:40:59.156 SyncToCoordinates (Bad H) ISSUE This member is mandatory but threw a MethodNotImplementedException exception, it must function per the ASCOM specification. -22:40:59.216 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -22:40:59.232 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -22:40:59.335 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 06:53:59.84 -22:40:59.371 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -22:40:59.389 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -22:40:59.464 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -22:40:59.616 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:40:59.656 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -22:40:59.700 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -22:40:59.758 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -22:40:59.800 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -22:40:59.972 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:41:00.010 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -22:41:00.053 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -22:41:00.113 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -22:41:00.171 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -22:41:00.229 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -22:41:00.498 SlewToAltAz INFO Slewed to within 24:39:03.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -22:41:00.512 SlewToAltAz INFO Slewed to within 49:59:59.00 DD:MM:SS of expected Altitude: 50:00:00.00 -22:41:00.554 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -22:41:00.609 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -22:41:00.670 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -22:41:00.733 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -22:41:06.055 SlewToAltAzAsync INFO Slewed to within 29:38:15.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -22:41:06.069 SlewToAltAzAsync INFO Slewed to within 54:59:59.00 DD:MM:SS of expected Altitude: 55:00:00.00 -22:41:06.110 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -22:41:06.169 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -22:41:06.229 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -22:41:06.341 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -22:41:20.933 SyncToTarget INFO Slewed to start position within 45.9 arc seconds of expected RA: 07:54:07.06, actual RA: 07:54:04.00 -22:41:20.947 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -22:41:21.041 SyncToTarget ISSUE CanSync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:41:21.079 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -22:41:21.124 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -22:41:21.184 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -22:41:21.229 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -22:41:21.383 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +22:57:22.264 CanMoveAxis:Primary OK CanMoveAxis:Primary True +22:57:22.299 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +22:57:22.335 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +22:57:22.370 Park/Unpark INFO Tests skipped +22:57:22.392 AbortSlew OK AbortSlew OK when not slewing +22:57:22.457 AxisRate:Primary OK Empty axis rate returned +22:57:22.470 AxisRate:Primary OK Disposed axis rates OK +22:57:22.482 AxisRate:Secondary OK Empty axis rate returned +22:57:22.494 AxisRate:Secondary OK Disposed axis rates OK +22:57:22.506 AxisRate:Tertiary OK Empty axis rate returned +22:57:22.518 AxisRate:Tertiary OK Disposed axis rates OK +22:57:22.534 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +22:57:22.582 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values +22:57:22.594 MoveAxis Primary OK AxisRates object successfully disposed +22:57:22.651 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values +22:57:22.663 MoveAxis Secondary OK AxisRates object successfully disposed +22:57:22.723 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +22:57:24.763 PulseGuide OK Synchronous pulse guide found OK +22:57:48.347 SlewToCoordinates OK Slewed OK. RA: 10:02:28.12 +22:57:48.361 SlewToCoordinates INFO Slewed within 7196.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:56.00 +22:57:48.393 SlewToCoordinates OK The TargetRightAscension property 10:02:28.12 matches the expected RA OK. +22:57:48.430 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +22:57:48.487 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +22:57:48.575 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +22:57:48.634 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +22:57:48.713 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +22:58:10.357 SlewToCoordinatesAsync OK Slewed OK. RA: 09:02:52.13 +22:58:10.369 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 +22:58:10.402 SlewToCoordinatesAsync OK The TargetRightAscension property 09:02:52.13 matches the expected RA OK. +22:58:10.436 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +22:58:10.475 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +22:58:10.559 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +22:58:10.618 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +22:58:10.701 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +22:58:32.348 SyncToCoordinates INFO Slewed to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 +22:58:32.361 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +22:58:33.043 SyncToCoordinates INFO Synced to sync position within 3566.6 arc seconds of expected RA: 07:59:14.23, actual RA: 08:03:12.00 +22:58:33.057 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 +22:58:33.096 SyncToCoordinates ERROR The TargetRightAscension property 07:59:12.00 does not match the expected RA 07:59:14.23 +22:58:33.133 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 +22:58:54.318 SyncToCoordinates INFO Slewed back to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 +22:58:54.333 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +22:58:55.011 SyncToCoordinates INFO Synced to reversed sync position within 3633.4 arc seconds of expected RA: 08:07:14.23, actual RA: 08:03:12.00 +22:58:55.026 SyncToCoordinates INFO Synced to reversed sync position within 3599.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:01.00 +22:59:14.298 SyncToCoordinates INFO Slewed back to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 +22:59:14.326 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +22:59:14.363 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +22:59:14.453 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +22:59:14.513 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +22:59:14.599 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +22:59:14.658 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +22:59:14.674 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +22:59:14.775 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 07:04:18.28 +22:59:14.813 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +22:59:14.829 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +22:59:14.906 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +22:59:15.057 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:59:15.100 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +22:59:15.146 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +22:59:15.205 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +22:59:15.251 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +22:59:15.422 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. +22:59:15.461 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +22:59:15.501 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +22:59:15.560 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +22:59:15.603 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +22:59:15.666 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +22:59:15.866 SlewToAltAz INFO Slewed to within 26:49:39.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +22:59:15.880 SlewToAltAz INFO Slewed to within 49:59:58.00 DD:MM:SS of expected Altitude: 50:00:00.00 +22:59:15.919 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +22:59:15.976 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +22:59:16.037 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +22:59:16.093 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +22:59:21.403 SlewToAltAzAsync INFO Slewed to within 31:51:02.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +22:59:21.417 SlewToAltAzAsync INFO Slewed to within 54:59:58.00 DD:MM:SS of expected Altitude: 55:00:00.00 +22:59:21.457 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +22:59:21.519 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +22:59:21.579 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +22:59:21.698 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +22:59:40.299 SyncToTarget INFO Slewed to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 +22:59:40.313 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +22:59:40.997 SyncToTarget INFO Synced to sync position within 3578.8 arc seconds of expected RA: 08:00:25.41, actual RA: 08:04:24.00 +22:59:41.010 SyncToTarget INFO Synced to sync position within 3601.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:00:01.00 +23:00:00.282 SyncToTarget INFO Slewed back to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 +23:00:00.295 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +23:00:00.979 SyncToTarget INFO Synced to reversed sync position within 3621.2 arc seconds of expected RA: 08:08:25.41, actual RA: 08:04:24.00 +23:00:00.993 SyncToTarget INFO Synced to reversed sync position within 3596.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:04.00 +23:00:20.266 SyncToTarget INFO Slewed back to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 +23:00:20.294 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +23:00:20.333 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +23:00:20.375 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +23:00:20.436 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +23:00:20.480 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +23:00:20.632 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -22:41:21.449 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +23:00:20.699 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -22:41:21.545 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +23:00:20.786 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 1 error, 2 warnings and 9 issues +Your driver had 2 errors, 2 warnings and 3 issues diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 336156d..b584e82 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -297,8 +297,10 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("AlignmentMode Get", "Not implemented"); - return _telescopeController.AlignmentMode; + tl.LogMessage("AlignmentMode Get", "Getting alignmode"); + var alignmode = _telescopeController.AlignmentMode; + tl.LogMessage("AlignmentMode Get", $"alignmode = {alignmode}"); + return alignmode; } } @@ -831,14 +833,17 @@ namespace ASCOM.MeadeAutostar497 public void SyncToCoordinates(double RightAscension, double Declination) { - tl.LogMessage("SyncToCoordinates", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SyncToCoordinates"); + tl.LogMessage("SyncToCoordinates", $"RA={RightAscension} Dec={Declination}"); + _telescopeController.TargetRightAscension = RightAscension; + _telescopeController.TargetDeclination = Declination; + + SyncToTarget(); } public void SyncToTarget() { - tl.LogMessage("SyncToTarget", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SyncToTarget"); + tl.LogMessage("SyncToTarget", "Executing"); + _telescopeController.SyncToTarget(); } public double TargetDeclination diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index a1ac58c..2e7b7b4 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -27,5 +27,6 @@ namespace ASCOM.MeadeAutostar497.Controller void SlewToCoordinatesAsync(double rightAscension, double declination); void SlewToAltAz(double azimuth, double altitude); void SlewToAltAzAsync(double azimuth, double altitude); + void SyncToTarget(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index cf56ace..f79bc7a 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -621,6 +621,18 @@ namespace ASCOM.MeadeAutostar497.Controller DoSlewAsync(false); } + public void SyncToTarget() + { + var result = SerialPort.CommandTerminated(":CM#", "#"); + //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. + //Returns: + //LX200's - a "#" terminated string with the name of the object that was synced. + // Autostars & Autostar II - At static string: " M31 EX GAL MAG 3.5 SZ178.0'#" + + if (result == string.Empty) + throw new ASCOM.InvalidOperationException("Unable to perform sync"); + } + //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { From cc5eabdfab0e04cc5dac40a8ca0f2c55b00887f8 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 6 May 2019 23:10:05 +0100 Subject: [PATCH 027/109] Implemented slew to target --- MeadeAutostar497/AscomClasses/Telescope.cs | 8 ++++---- .../Controller/ITelescopeController.cs | 2 ++ .../Controller/TelescopeController.cs | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index b584e82..f3a966d 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -804,14 +804,14 @@ namespace ASCOM.MeadeAutostar497 public void SlewToTarget() { - tl.LogMessage("SlewToTarget", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToTarget"); + tl.LogMessage("SlewToTarget", "Executing"); + _telescopeController.SlewToTarget(); } public void SlewToTargetAsync() { - tl.LogMessage("SlewToTargetAsync", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SlewToTargetAsync"); + tl.LogMessage("SlewToTargetAsync", "Executing"); + _telescopeController.SlewToTargetAsync(); } public bool Slewing diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 2e7b7b4..10c792d 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -28,5 +28,7 @@ namespace ASCOM.MeadeAutostar497.Controller void SlewToAltAz(double azimuth, double altitude); void SlewToAltAzAsync(double azimuth, double altitude); void SyncToTarget(); + void SlewToTarget(); + void SlewToTargetAsync(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index f79bc7a..ed8e5b1 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -633,6 +633,24 @@ namespace ASCOM.MeadeAutostar497.Controller throw new ASCOM.InvalidOperationException("Unable to perform sync"); } + public void SlewToTarget() + { + SlewToTargetAsync(); + + while (Slewing) + { + Util.WaitForMilliseconds(200); + } + } + + public void SlewToTargetAsync() + { + if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER ) + throw new ASCOM.InvalidOperationException("No target selected to slew to."); + + DoSlewAsync(true); + } + //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { From 5d16edee2e61eff984e04c6c1859a74a6dac4e9f Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 7 May 2019 17:51:08 +0100 Subject: [PATCH 028/109] Added support for MoveAxis --- ConformanceResult.txt | 423 ++++++++++-------- MeadeAutostar497/AscomClasses/Rates.cs | 6 +- MeadeAutostar497/AscomClasses/Telescope.cs | 4 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 105 +++++ 5 files changed, 341 insertions(+), 198 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index f90bf18..ddaa3c9 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -2,6 +2,7 @@ Start-up ASCOM Device Conformance Checker - 64bit mode Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 + ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -15,216 +16,250 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -22:57:13.923 Driver Access Checks OK -22:57:14.570 AccessChecks OK Successfully created driver using late binding -22:57:14.797 AccessChecks OK Successfully connected using late binding -22:57:14.802 AccessChecks INFO The driver is a .NET object -22:57:14.806 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -22:57:14.811 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -22:57:15.505 AccessChecks INFO Device does not expose interface ITelescopeV2 -22:57:16.310 AccessChecks INFO Device exposes interface ITelescopeV3 -22:57:17.625 AccessChecks OK Successfully created driver using driver access toolkit -22:57:17.798 AccessChecks OK Successfully connected using driver access toolkit +17:39:59.289 Driver Access Checks OK +17:39:59.932 AccessChecks OK Successfully created driver using late binding +17:40:00.154 AccessChecks OK Successfully connected using late binding +17:40:00.158 AccessChecks INFO The driver is a .NET object +17:40:00.162 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +17:40:00.167 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +17:40:00.863 AccessChecks INFO Device does not expose interface ITelescopeV2 +17:40:01.673 AccessChecks INFO Device exposes interface ITelescopeV3 +17:40:02.988 AccessChecks OK Successfully created driver using driver access toolkit +17:40:03.161 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -22:57:19.118 ConformanceCheck OK Driver instance created successfully -22:57:19.335 ConformanceCheck OK Connected OK +17:40:04.487 ConformanceCheck OK Driver instance created successfully +17:40:04.705 ConformanceCheck OK Connected OK Common Driver Methods -22:57:19.376 InterfaceVersion OK 3 -22:57:19.403 Connected OK True -22:57:19.431 Description OK Meade Autostar 497 .net -22:57:19.459 DriverInfo OK Information about the driver itself. Version: 0.0 -22:57:19.488 DriverVersion OK 0.0 -22:57:19.517 Name OK Meade Autostar 497 .net -22:57:19.545 CommandString INFO Conform cannot test the CommandString method -22:57:19.551 CommandBlind INFO Conform cannot test the CommandBlind method -22:57:19.557 CommandBool INFO Conform cannot test the CommandBool method -22:57:19.563 Action INFO Conform cannot test the Action method -22:57:19.569 SupportedActions OK Driver returned an empty action list +17:40:04.746 InterfaceVersion OK 3 +17:40:04.774 Connected OK True +17:40:04.803 Description OK Meade Autostar 497 .net +17:40:04.832 DriverInfo OK Information about the driver itself. Version: 0.0 +17:40:04.861 DriverVersion OK 0.0 +17:40:04.891 Name OK Meade Autostar 497 .net +17:40:04.920 CommandString INFO Conform cannot test the CommandString method +17:40:04.926 CommandBlind INFO Conform cannot test the CommandBlind method +17:40:04.933 CommandBool INFO Conform cannot test the CommandBool method +17:40:04.940 Action INFO Conform cannot test the Action method +17:40:04.948 SupportedActions OK Driver returned an empty action list Can Properties -22:57:19.635 CanFindHome OK False -22:57:19.642 CanPark OK True -22:57:19.648 CanPulseGuide OK True -22:57:19.656 CanSetDeclinationRate OK False -22:57:19.664 CanSetGuideRates OK False -22:57:19.673 CanSetPark OK False -22:57:19.682 CanSetPierSide OK False -22:57:19.696 CanSetRightAscensionRate OK False -22:57:19.704 CanSetTracking OK False -22:57:19.712 CanSlew OK True -22:57:19.720 CanSlewltAz OK True -22:57:19.729 CanSlewAltAzAsync OK True -22:57:19.737 CanSlewAsync OK True -22:57:19.746 CanSync OK True -22:57:19.754 CanSyncAltAz OK False -22:57:19.763 CanUnPark OK False +17:40:05.013 CanFindHome OK False +17:40:05.020 CanPark OK True +17:40:05.027 CanPulseGuide OK True +17:40:05.035 CanSetDeclinationRate OK False +17:40:05.043 CanSetGuideRates OK False +17:40:05.051 CanSetPark OK False +17:40:05.060 CanSetPierSide OK False +17:40:05.072 CanSetRightAscensionRate OK False +17:40:05.081 CanSetTracking OK False +17:40:05.088 CanSlew OK True +17:40:05.097 CanSlewltAz OK True +17:40:05.106 CanSlewAltAzAsync OK True +17:40:05.115 CanSlewAsync OK True +17:40:05.123 CanSync OK True +17:40:05.132 CanSyncAltAz OK False +17:40:05.140 CanUnPark OK False Pre-run Checks -22:57:19.809 Mount Safety INFO Scope is not parked, continuing testing -22:57:19.861 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -22:57:19.869 TimeCheck INFO PC UTCDate: 06-May-2019 21:57:19.869 -22:57:19.998 TimeCheck INFO Mount UTCDate: 02-May-2019 19:38:00.000 +17:40:05.190 Mount Safety INFO Scope is not parked, continuing testing +17:40:05.247 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +17:40:05.255 TimeCheck INFO PC UTCDate: 07-May-2019 16:40:05.255 +17:40:05.374 TimeCheck INFO Mount UTCDate: 02-May-2019 19:40:33.000 Properties -22:57:20.071 AlignmentMode OK algPolar -22:57:20.123 Altitude OK 0.00 -22:57:20.161 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.195 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.227 AtHome OK False -22:57:20.258 AtPark OK False -22:57:20.317 Azimuth OK 122.84 -22:57:20.375 Declination OK -00:00:02.00 -22:57:20.406 DeclinationRate Read OK 0.00 -22:57:20.438 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -22:57:20.470 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.506 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.538 EquatorialSystem OK equLocalTopocentric -22:57:20.570 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.606 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.616 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -22:57:20.649 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.660 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -22:57:20.692 IsPulseGuiding OK False -22:57:20.755 RightAscension OK 07:59:56.00 -22:57:20.790 RightAscensionRate Read OK 0.00 -22:57:20.823 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -22:57:20.856 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.890 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.902 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.912 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:20.969 SiteLatitude Read OK 00:00:00.00 -22:57:21.007 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -22:57:21.019 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -22:57:21.058 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -22:57:21.114 SiteLongitude Read OK -27:48:00.00 -22:57:21.150 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -22:57:21.162 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -22:57:21.256 SiteLongitude Write OK Legal value -27:48:00.00 degrees written successfully -22:57:21.296 Slewing OK False -22:57:21.333 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:21.367 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:21.379 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -22:57:21.414 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -22:57:21.465 SiderealTime OK 11:02:24.71 -22:57:21.477 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 11:02:24.71, ASCOM: 11:04:01.82 -22:57:21.520 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -22:57:21.554 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -22:57:21.566 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -22:57:21.601 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -22:57:21.613 Tracking Read OK True -22:57:21.647 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -22:57:21.688 TrackingRates Found drive rate: driveSidereal -22:57:21.702 TrackingRates OK Drive rates read OK -22:57:21.716 TrackingRates OK Disposed tracking rates OK -22:57:21.751 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -22:57:21.763 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -22:57:21.854 UTCDate Read OK 02-May-2019 19:38:02.000 -22:57:22.019 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:38:02 +17:40:05.448 AlignmentMode OK algPolar +17:40:05.499 Altitude OK 8.79 +17:40:05.536 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +17:40:05.569 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +17:40:05.601 AtHome OK False +17:40:05.632 AtPark OK False +17:40:05.745 Azimuth OK 38.02 +17:40:05.802 Declination OK -08:47:23.00 +17:40:05.833 DeclinationRate Read OK 0.00 +17:40:05.866 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +17:40:05.899 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:05.931 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:05.963 EquatorialSystem OK equLocalTopocentric +17:40:05.995 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.028 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.039 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +17:40:06.072 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.084 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +17:40:06.118 IsPulseGuiding OK False +17:40:06.177 RightAscension OK 02:55:14.00 +17:40:06.209 RightAscensionRate Read OK 0.00 +17:40:06.242 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +17:40:06.275 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.310 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.321 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.332 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.388 SiteLatitude Read OK 00:00:00.00 +17:40:06.427 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +17:40:06.438 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +17:40:06.476 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +17:40:06.530 SiteLongitude Read OK -35:48:00.00 +17:40:06.565 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +17:40:06.576 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +17:40:06.666 SiteLongitude Write OK Legal value -35:48:00.00 degrees written successfully +17:40:06.708 Slewing OK False +17:40:06.743 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.778 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.790 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.824 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +17:40:06.880 SiderealTime OK 05:16:14.57 +17:40:06.892 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 05:16:14.57, ASCOM: 05:17:51.67 +17:40:06.943 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +17:40:06.978 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +17:40:06.990 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +17:40:07.025 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +17:40:07.037 Tracking Read OK True +17:40:07.071 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +17:40:07.115 TrackingRates Found drive rate: driveSidereal +17:40:07.128 TrackingRates OK Drive rates read OK +17:40:07.140 TrackingRates OK Disposed tracking rates OK +17:40:07.175 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +17:40:07.188 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. +17:40:07.280 UTCDate Read OK 02-May-2019 19:40:35.000 +17:40:07.461 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:40:35 Methods -22:57:22.264 CanMoveAxis:Primary OK CanMoveAxis:Primary True -22:57:22.299 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -22:57:22.335 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -22:57:22.370 Park/Unpark INFO Tests skipped -22:57:22.392 AbortSlew OK AbortSlew OK when not slewing -22:57:22.457 AxisRate:Primary OK Empty axis rate returned -22:57:22.470 AxisRate:Primary OK Disposed axis rates OK -22:57:22.482 AxisRate:Secondary OK Empty axis rate returned -22:57:22.494 AxisRate:Secondary OK Disposed axis rates OK -22:57:22.506 AxisRate:Tertiary OK Empty axis rate returned -22:57:22.518 AxisRate:Tertiary OK Disposed axis rates OK -22:57:22.534 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -22:57:22.582 MoveAxis Primary WARNING MoveAxis tests skipped because there are no AxisRate values -22:57:22.594 MoveAxis Primary OK AxisRates object successfully disposed -22:57:22.651 MoveAxis Secondary WARNING MoveAxis tests skipped because there are no AxisRate values -22:57:22.663 MoveAxis Secondary OK AxisRates object successfully disposed -22:57:22.723 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -22:57:24.763 PulseGuide OK Synchronous pulse guide found OK -22:57:48.347 SlewToCoordinates OK Slewed OK. RA: 10:02:28.12 -22:57:48.361 SlewToCoordinates INFO Slewed within 7196.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:56.00 -22:57:48.393 SlewToCoordinates OK The TargetRightAscension property 10:02:28.12 matches the expected RA OK. -22:57:48.430 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -22:57:48.487 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -22:57:48.575 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -22:57:48.634 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -22:57:48.713 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -22:58:10.357 SlewToCoordinatesAsync OK Slewed OK. RA: 09:02:52.13 -22:58:10.369 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 -22:58:10.402 SlewToCoordinatesAsync OK The TargetRightAscension property 09:02:52.13 matches the expected RA OK. -22:58:10.436 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -22:58:10.475 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -22:58:10.559 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -22:58:10.618 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -22:58:10.701 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -22:58:32.348 SyncToCoordinates INFO Slewed to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 -22:58:32.361 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -22:58:33.043 SyncToCoordinates INFO Synced to sync position within 3566.6 arc seconds of expected RA: 07:59:14.23, actual RA: 08:03:12.00 -22:58:33.057 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 -22:58:33.096 SyncToCoordinates ERROR The TargetRightAscension property 07:59:12.00 does not match the expected RA 07:59:14.23 -22:58:33.133 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 -22:58:54.318 SyncToCoordinates INFO Slewed back to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 -22:58:54.333 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -22:58:55.011 SyncToCoordinates INFO Synced to reversed sync position within 3633.4 arc seconds of expected RA: 08:07:14.23, actual RA: 08:03:12.00 -22:58:55.026 SyncToCoordinates INFO Synced to reversed sync position within 3599.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:01.00 -22:59:14.298 SyncToCoordinates INFO Slewed back to start position within 33.4 arc seconds of expected RA: 08:03:14.23, actual RA: 08:03:12.00 -22:59:14.326 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -22:59:14.363 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -22:59:14.453 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -22:59:14.513 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -22:59:14.599 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -22:59:14.658 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -22:59:14.674 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -22:59:14.775 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 07:04:18.28 -22:59:14.813 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -22:59:14.829 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -22:59:14.906 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -22:59:15.057 SlewToTarget ISSUE CanSlew is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:59:15.100 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -22:59:15.146 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -22:59:15.205 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -22:59:15.251 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -22:59:15.422 SlewToTargetAsync ISSUE CanSlewAsync is True and a MethodNotImplementedException exception was thrown, this method must function per the ASCOM specification. -22:59:15.461 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -22:59:15.501 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -22:59:15.560 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -22:59:15.603 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -22:59:15.666 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -22:59:15.866 SlewToAltAz INFO Slewed to within 26:49:39.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -22:59:15.880 SlewToAltAz INFO Slewed to within 49:59:58.00 DD:MM:SS of expected Altitude: 50:00:00.00 -22:59:15.919 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -22:59:15.976 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -22:59:16.037 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -22:59:16.093 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -22:59:21.403 SlewToAltAzAsync INFO Slewed to within 31:51:02.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -22:59:21.417 SlewToAltAzAsync INFO Slewed to within 54:59:58.00 DD:MM:SS of expected Altitude: 55:00:00.00 -22:59:21.457 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -22:59:21.519 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -22:59:21.579 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -22:59:21.698 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -22:59:40.299 SyncToTarget INFO Slewed to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 -22:59:40.313 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -22:59:40.997 SyncToTarget INFO Synced to sync position within 3578.8 arc seconds of expected RA: 08:00:25.41, actual RA: 08:04:24.00 -22:59:41.010 SyncToTarget INFO Synced to sync position within 3601.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:00:01.00 -23:00:00.282 SyncToTarget INFO Slewed back to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 -23:00:00.295 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -23:00:00.979 SyncToTarget INFO Synced to reversed sync position within 3621.2 arc seconds of expected RA: 08:08:25.41, actual RA: 08:04:24.00 -23:00:00.993 SyncToTarget INFO Synced to reversed sync position within 3596.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:04.00 -23:00:20.266 SyncToTarget INFO Slewed back to start position within 21.2 arc seconds of expected RA: 08:04:25.41, actual RA: 08:04:24.00 -23:00:20.294 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -23:00:20.333 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -23:00:20.375 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -23:00:20.436 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -23:00:20.480 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -23:00:20.632 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +17:40:07.705 CanMoveAxis:Primary OK CanMoveAxis:Primary True +17:40:07.742 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +17:40:07.778 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +17:40:07.814 Park/Unpark INFO Tests skipped +17:40:07.836 AbortSlew OK AbortSlew OK when not slewing +17:40:07.904 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +17:40:07.916 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +17:40:07.929 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +17:40:07.942 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +17:40:07.954 AxisRate:Primary OK No overlapping axis rates found +17:40:07.966 AxisRate:Primary OK No duplicate axis rates found +17:40:07.978 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +17:40:07.990 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +17:40:08.002 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +17:40:08.014 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +17:40:08.025 AxisRate:Primary OK Disposed axis rates OK +17:40:08.038 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +17:40:08.050 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +17:40:08.064 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +17:40:08.077 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +17:40:08.092 AxisRate:Secondary OK No overlapping axis rates found +17:40:08.104 AxisRate:Secondary OK No duplicate axis rates found +17:40:08.117 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +17:40:08.131 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +17:40:08.144 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +17:40:08.158 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +17:40:08.171 AxisRate:Secondary OK Disposed axis rates OK +17:40:08.187 AxisRate:Tertiary OK Empty axis rate returned +17:40:08.203 AxisRate:Tertiary OK Disposed axis rates OK +17:40:08.219 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +17:40:08.272 MoveAxis Primary OK Can successfully set a movement rate of zero +17:40:08.287 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +17:40:08.323 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +17:40:12.533 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +17:40:16.852 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +17:40:21.063 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +17:40:21.078 MoveAxis Primary OK AxisRates object successfully disposed +17:40:21.137 MoveAxis Secondary OK Can successfully set a movement rate of zero +17:40:21.154 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +17:40:21.193 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +17:40:25.403 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +17:40:29.692 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +17:40:33.903 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +17:40:33.918 MoveAxis Secondary OK AxisRates object successfully disposed +17:40:33.978 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +17:40:36.018 PulseGuide OK Synchronous pulse guide found OK +17:40:58.303 SlewToCoordinates INFO Slewed within 58.4 arc seconds of expected RA: 04:16:43.90, actual RA: 04:16:40.00 +17:40:58.316 SlewToCoordinates INFO Slewed within 7204.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:04.00 +17:40:58.353 SlewToCoordinates ERROR The TargetRightAscension property 04:16:40.00 does not match the expected RA 04:16:43.90 +17:40:58.388 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +17:40:58.438 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +17:40:58.519 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +17:40:58.579 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +17:40:58.666 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +17:41:20.304 SlewToCoordinatesAsync INFO Slewed within 38.9 arc seconds of expected RA: 03:17:06.59, actual RA: 03:17:04.00 +17:41:20.318 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 +17:41:20.353 SlewToCoordinatesAsync ERROR The TargetRightAscension property 03:17:04.00 does not match the expected RA 03:17:06.59 +17:41:20.390 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +17:41:20.429 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +17:41:20.510 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +17:41:20.570 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +17:41:20.654 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +17:41:42.297 SyncToCoordinates INFO Slewed to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 +17:41:42.310 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +17:41:42.995 SyncToCoordinates INFO Synced to sync position within 3589.6 arc seconds of expected RA: 02:13:28.69, actual RA: 02:17:28.00 +17:41:43.007 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 +17:41:43.043 SyncToCoordinates ERROR The TargetRightAscension property 02:13:28.00 does not match the expected RA 02:13:28.69 +17:41:43.075 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 +17:42:02.261 SyncToCoordinates INFO Slewed back to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 +17:42:02.273 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +17:42:02.954 SyncToCoordinates INFO Synced to reversed sync position within 3610.4 arc seconds of expected RA: 02:21:28.69, actual RA: 02:17:28.00 +17:42:02.967 SyncToCoordinates INFO Synced to reversed sync position within 3596.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:04.00 +17:42:22.265 SyncToCoordinates INFO Slewed back to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 +17:42:22.278 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +17:42:22.321 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +17:42:22.407 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +17:42:22.472 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +17:42:22.554 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +17:42:22.611 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +17:42:22.625 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +17:42:22.724 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 01:18:30.74 +17:42:22.760 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +17:42:22.777 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +17:42:22.854 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +17:42:40.263 SlewToTarget INFO Slewed within 44.9 arc seconds of expected RA: 02:18:30.99, actual RA: 02:18:28.00 +17:42:40.276 SlewToTarget INFO Slewed within 21594.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:54.00 +17:42:40.311 SlewToTarget ERROR The TargetRightAscension property 02:18:28.00 does not match the expected RA 02:18:30.99 +17:42:40.345 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +17:42:40.384 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +17:42:40.425 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +17:42:40.486 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +17:42:40.529 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +17:43:02.273 SlewToTargetAsync INFO Slewed within 11.0 arc seconds of expected RA: 01:18:48.73, actual RA: 01:18:48.00 +17:43:02.286 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 +17:43:02.321 SlewToTargetAsync ERROR The TargetRightAscension property 01:18:48.00 does not match the expected RA 01:18:48.73 +17:43:02.355 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +17:43:02.394 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +17:43:02.437 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +17:43:02.495 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +17:43:02.538 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +17:43:02.597 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +17:43:02.786 SlewToAltAz INFO Slewed to within 136:49:26.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +17:43:02.800 SlewToAltAz INFO Slewed to within 46:00:02.00 DD:MM:SS of expected Altitude: 50:00:00.00 +17:43:02.843 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +17:43:02.903 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +17:43:02.963 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +17:43:03.027 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +17:43:08.342 SlewToAltAzAsync INFO Slewed to within 141:50:51.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +17:43:08.355 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 +17:43:08.396 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +17:43:08.451 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +17:43:08.513 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +17:43:08.568 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +17:43:30.263 SyncToTarget INFO Slewed to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 +17:43:30.277 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +17:43:30.960 SyncToTarget INFO Synced to sync position within 3586.6 arc seconds of expected RA: 02:15:16.90, actual RA: 02:19:16.00 +17:43:30.974 SyncToTarget INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 +17:43:54.229 SyncToTarget INFO Slewed back to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 +17:43:54.243 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +17:43:54.921 SyncToTarget INFO Synced to reversed sync position within 3613.4 arc seconds of expected RA: 02:23:16.90, actual RA: 02:19:16.00 +17:43:54.935 SyncToTarget INFO Synced to reversed sync position within 3599.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:01.00 +17:44:14.213 SyncToTarget INFO Slewed back to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 +17:44:14.232 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +17:44:14.269 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +17:44:14.313 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +17:44:14.372 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +17:44:14.415 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +17:44:14.571 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -23:00:20.699 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +17:44:14.640 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -23:00:20.786 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +17:44:14.728 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 2 errors, 2 warnings and 3 issues +Your driver had 6 errors, 0 warnings and 1 issues diff --git a/MeadeAutostar497/AscomClasses/Rates.cs b/MeadeAutostar497/AscomClasses/Rates.cs index 233bf9d..bd29429 100644 --- a/MeadeAutostar497/AscomClasses/Rates.cs +++ b/MeadeAutostar497/AscomClasses/Rates.cs @@ -99,11 +99,13 @@ namespace ASCOM.MeadeAutostar497 case TelescopeAxes.axisPrimary: // TODO Initialize this array with any Primary axis rates that your driver may provide // Example: m_Rates = new Rate[] { new Rate(10.5, 30.2), new Rate(54.0, 43.6) } - this.rates = new Rate[0]; + //this.rates = new Rate[0]; + this.rates = new Rate[] {new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4)}; break; case TelescopeAxes.axisSecondary: // TODO Initialize this array with any Secondary axis rates that your driver may provide - this.rates = new Rate[0]; + //this.rates = new Rate[0]; + this.rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisTertiary: // TODO Initialize this array with any Tertiary axis rates that your driver may provide diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index f3a966d..c05c959 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -633,8 +633,8 @@ namespace ASCOM.MeadeAutostar497 public void MoveAxis(TelescopeAxes Axis, double Rate) { - tl.LogMessage("MoveAxis", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("MoveAxis"); + tl.LogMessage("MoveAxis", $"Axis={Axis} rate={Rate}"); + _telescopeController.MoveAxis(Axis, Rate); } public void Park() diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 10c792d..02e40f3 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -30,5 +30,6 @@ namespace ASCOM.MeadeAutostar497.Controller void SyncToTarget(); void SlewToTarget(); void SlewToTargetAsync(); + void MoveAxis(TelescopeAxes axis, double rate); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index ed8e5b1..fa15f0a 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -129,6 +129,10 @@ namespace ASCOM.MeadeAutostar497.Controller { if (!Connected) return false; + + if (movingAxis()) + return true; + var result = SerialPort.CommandTerminated(":D#", "#"); return result != string.Empty; } @@ -651,6 +655,107 @@ namespace ASCOM.MeadeAutostar497.Controller DoSlewAsync(true); } + private bool movingAxis() + { + return _movingPrimary || _movingSecondary; + } + + private bool _movingPrimary; + private bool _movingSecondary; + public void MoveAxis(TelescopeAxes axis, double rate) + { + var absrate = Math.Abs(rate); + + switch(absrate) + { + case 0: + //do nothing, it's ok this time as we're halting the slew. + break; + case 1: + SerialPort.Command(":RG#"); + //:RG# Set Slew rate to Guiding Rate (slowest) + //Returns: Nothing + break; + case 2: + SerialPort.Command(":RC#"); + //:RC# Set Slew rate to Centering rate (2nd slowest) + //Returns: Nothing + break; + case 3: + SerialPort.Command(":RM#"); + //:RM# Set Slew rate to Find Rate (2nd Fastest) + //Returns: Nothing + break; + case 4: + SerialPort.Command(":RS#"); + //:RS# Set Slew rate to max (fastest) + //Returns: Nothing + break; + default: + throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); + + } + + switch (axis) + { + case TelescopeAxes.axisPrimary: + if (rate == 0) + { + _movingPrimary = false; + SerialPort.Command(":Qe#"); + //:Qe# Halt eastward Slews + //Returns: Nothing + SerialPort.Command(":Qw#"); + //:Qw# Halt westward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SerialPort.Command(":Me#"); + //:Me# Move Telescope East at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + else + { + SerialPort.Command(":Mw#"); + //:Mw# Move Telescope West at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + break; + case TelescopeAxes.axisSecondary: + if (rate == 0) + { + _movingSecondary = false; + SerialPort.Command(":Qn#"); + //:Qn# Halt northward Slews + //Returns: Nothing + SerialPort.Command(":Qs#"); + //:Qs# Halt southward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SerialPort.Command(":Mn#"); + //:Mn# Move Telescope North at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + else + { + SerialPort.Command(":Ms#"); + //:Ms# Move Telescope South at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + + break; + default: + throw new ASCOM.MethodNotImplementedException("Can not move this axis."); + } + } + //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { From 9608e5a31f78ec6078bc8f1c1287635fa39787fd Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 7 May 2019 18:10:17 +0100 Subject: [PATCH 029/109] Added support for tracking rate --- ConformanceResult.txt | 459 +++++++++--------- MeadeAutostar497/AscomClasses/Telescope.cs | 5 +- .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 43 ++ TestConsole/Program.cs | 5 +- 5 files changed, 281 insertions(+), 232 deletions(-) diff --git a/ConformanceResult.txt b/ConformanceResult.txt index ddaa3c9..0b9572e 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -2,7 +2,6 @@ Start-up ASCOM Device Conformance Checker - 64bit mode Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 - ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 @@ -16,250 +15,252 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -17:39:59.289 Driver Access Checks OK -17:39:59.932 AccessChecks OK Successfully created driver using late binding -17:40:00.154 AccessChecks OK Successfully connected using late binding -17:40:00.158 AccessChecks INFO The driver is a .NET object -17:40:00.162 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -17:40:00.167 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -17:40:00.863 AccessChecks INFO Device does not expose interface ITelescopeV2 -17:40:01.673 AccessChecks INFO Device exposes interface ITelescopeV3 -17:40:02.988 AccessChecks OK Successfully created driver using driver access toolkit -17:40:03.161 AccessChecks OK Successfully connected using driver access toolkit +18:05:11.632 Driver Access Checks OK +18:05:12.272 AccessChecks OK Successfully created driver using late binding +18:05:12.505 AccessChecks OK Successfully connected using late binding +18:05:12.509 AccessChecks INFO The driver is a .NET object +18:05:12.514 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +18:05:12.518 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +18:05:13.217 AccessChecks INFO Device does not expose interface ITelescopeV2 +18:05:14.028 AccessChecks INFO Device exposes interface ITelescopeV3 +18:05:15.344 AccessChecks OK Successfully created driver using driver access toolkit +18:05:15.517 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -17:40:04.487 ConformanceCheck OK Driver instance created successfully -17:40:04.705 ConformanceCheck OK Connected OK +18:05:16.845 ConformanceCheck OK Driver instance created successfully +18:05:17.057 ConformanceCheck OK Connected OK Common Driver Methods -17:40:04.746 InterfaceVersion OK 3 -17:40:04.774 Connected OK True -17:40:04.803 Description OK Meade Autostar 497 .net -17:40:04.832 DriverInfo OK Information about the driver itself. Version: 0.0 -17:40:04.861 DriverVersion OK 0.0 -17:40:04.891 Name OK Meade Autostar 497 .net -17:40:04.920 CommandString INFO Conform cannot test the CommandString method -17:40:04.926 CommandBlind INFO Conform cannot test the CommandBlind method -17:40:04.933 CommandBool INFO Conform cannot test the CommandBool method -17:40:04.940 Action INFO Conform cannot test the Action method -17:40:04.948 SupportedActions OK Driver returned an empty action list +18:05:17.098 InterfaceVersion OK 3 +18:05:17.127 Connected OK True +18:05:17.155 Description OK Meade Autostar 497 .net +18:05:17.184 DriverInfo OK Information about the driver itself. Version: 0.0 +18:05:17.214 DriverVersion OK 0.0 +18:05:17.243 Name OK Meade Autostar 497 .net +18:05:17.272 CommandString INFO Conform cannot test the CommandString method +18:05:17.278 CommandBlind INFO Conform cannot test the CommandBlind method +18:05:17.284 CommandBool INFO Conform cannot test the CommandBool method +18:05:17.291 Action INFO Conform cannot test the Action method +18:05:17.298 SupportedActions OK Driver returned an empty action list Can Properties -17:40:05.013 CanFindHome OK False -17:40:05.020 CanPark OK True -17:40:05.027 CanPulseGuide OK True -17:40:05.035 CanSetDeclinationRate OK False -17:40:05.043 CanSetGuideRates OK False -17:40:05.051 CanSetPark OK False -17:40:05.060 CanSetPierSide OK False -17:40:05.072 CanSetRightAscensionRate OK False -17:40:05.081 CanSetTracking OK False -17:40:05.088 CanSlew OK True -17:40:05.097 CanSlewltAz OK True -17:40:05.106 CanSlewAltAzAsync OK True -17:40:05.115 CanSlewAsync OK True -17:40:05.123 CanSync OK True -17:40:05.132 CanSyncAltAz OK False -17:40:05.140 CanUnPark OK False +18:05:17.364 CanFindHome OK False +18:05:17.372 CanPark OK True +18:05:17.379 CanPulseGuide OK True +18:05:17.386 CanSetDeclinationRate OK False +18:05:17.393 CanSetGuideRates OK False +18:05:17.401 CanSetPark OK False +18:05:17.412 CanSetPierSide OK False +18:05:17.425 CanSetRightAscensionRate OK False +18:05:17.432 CanSetTracking OK False +18:05:17.440 CanSlew OK True +18:05:17.449 CanSlewltAz OK True +18:05:17.458 CanSlewAltAzAsync OK True +18:05:17.466 CanSlewAsync OK True +18:05:17.475 CanSync OK True +18:05:17.484 CanSyncAltAz OK False +18:05:17.493 CanUnPark OK False Pre-run Checks -17:40:05.190 Mount Safety INFO Scope is not parked, continuing testing -17:40:05.247 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -17:40:05.255 TimeCheck INFO PC UTCDate: 07-May-2019 16:40:05.255 -17:40:05.374 TimeCheck INFO Mount UTCDate: 02-May-2019 19:40:33.000 +18:05:17.542 Mount Safety INFO Scope is not parked, continuing testing +18:05:17.594 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +18:05:17.602 TimeCheck INFO PC UTCDate: 07-May-2019 17:05:17.602 +18:05:17.727 TimeCheck INFO Mount UTCDate: 02-May-2019 20:05:41.000 Properties -17:40:05.448 AlignmentMode OK algPolar -17:40:05.499 Altitude OK 8.79 -17:40:05.536 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -17:40:05.569 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -17:40:05.601 AtHome OK False -17:40:05.632 AtPark OK False -17:40:05.745 Azimuth OK 38.02 -17:40:05.802 Declination OK -08:47:23.00 -17:40:05.833 DeclinationRate Read OK 0.00 -17:40:05.866 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -17:40:05.899 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:05.931 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:05.963 EquatorialSystem OK equLocalTopocentric -17:40:05.995 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.028 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.039 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -17:40:06.072 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.084 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -17:40:06.118 IsPulseGuiding OK False -17:40:06.177 RightAscension OK 02:55:14.00 -17:40:06.209 RightAscensionRate Read OK 0.00 -17:40:06.242 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -17:40:06.275 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.310 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.321 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.332 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.388 SiteLatitude Read OK 00:00:00.00 -17:40:06.427 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -17:40:06.438 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -17:40:06.476 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -17:40:06.530 SiteLongitude Read OK -35:48:00.00 -17:40:06.565 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -17:40:06.576 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -17:40:06.666 SiteLongitude Write OK Legal value -35:48:00.00 degrees written successfully -17:40:06.708 Slewing OK False -17:40:06.743 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.778 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.790 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.824 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -17:40:06.880 SiderealTime OK 05:16:14.57 -17:40:06.892 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 05:16:14.57, ASCOM: 05:17:51.67 -17:40:06.943 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -17:40:06.978 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -17:40:06.990 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -17:40:07.025 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -17:40:07.037 Tracking Read OK True -17:40:07.071 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -17:40:07.115 TrackingRates Found drive rate: driveSidereal -17:40:07.128 TrackingRates OK Drive rates read OK -17:40:07.140 TrackingRates OK Disposed tracking rates OK -17:40:07.175 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -17:40:07.188 TrackingRate Read ISSUE This member is mandatory but threw a PropertyNotImplementedException exception, it must function per the ASCOM specification. -17:40:07.280 UTCDate Read OK 02-May-2019 19:40:35.000 -17:40:07.461 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:40:35 +18:05:17.801 AlignmentMode OK algPolar +18:05:17.854 Altitude WARNING Altitude is <0.0 degrees: -0.97166667 +18:05:17.892 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +18:05:17.927 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +18:05:17.959 AtHome OK False +18:05:17.990 AtPark OK False +18:05:18.052 Azimuth OK 22.80 +18:05:18.107 Declination OK 00:58:18.00 +18:05:18.139 DeclinationRate Read OK 0.00 +18:05:18.171 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +18:05:18.204 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.237 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.269 EquatorialSystem OK equLocalTopocentric +18:05:18.301 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.334 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.345 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:05:18.377 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.388 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:05:18.421 IsPulseGuiding OK False +18:05:18.482 RightAscension OK 02:43:28.00 +18:05:18.515 RightAscensionRate Read OK 0.00 +18:05:18.548 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +18:05:18.582 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.617 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.628 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.640 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:18.700 SiteLatitude Read OK 00:00:00.00 +18:05:18.738 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +18:05:18.751 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +18:05:18.787 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +18:05:18.866 SiteLongitude Read OK -36:12:00.00 +18:05:18.901 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +18:05:18.913 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +18:05:19.006 SiteLongitude Write OK Legal value -36:12:00.00 degrees written successfully +18:05:19.050 Slewing OK False +18:05:19.084 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.119 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.132 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.167 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.221 SiderealTime OK 05:35:07.05 +18:05:19.233 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:35:07.05, ASCOM: 05:41:32.15 +18:05:19.280 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +18:05:19.314 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:05:19.327 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +18:05:19.361 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:05:19.373 Tracking Read OK True +18:05:19.408 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +18:05:19.450 TrackingRates Found drive rate: driveSidereal +18:05:19.463 TrackingRates OK Drive rates read OK +18:05:19.476 TrackingRates OK Disposed tracking rates OK +18:05:19.511 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +18:05:19.545 TrackingRate Read OK driveLunar +18:05:19.579 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.592 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:05:19.685 UTCDate Read OK 02-May-2019 20:05:43.000 +18:05:19.854 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:05:43 Methods -17:40:07.705 CanMoveAxis:Primary OK CanMoveAxis:Primary True -17:40:07.742 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -17:40:07.778 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -17:40:07.814 Park/Unpark INFO Tests skipped -17:40:07.836 AbortSlew OK AbortSlew OK when not slewing -17:40:07.904 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -17:40:07.916 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -17:40:07.929 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -17:40:07.942 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -17:40:07.954 AxisRate:Primary OK No overlapping axis rates found -17:40:07.966 AxisRate:Primary OK No duplicate axis rates found -17:40:07.978 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -17:40:07.990 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -17:40:08.002 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -17:40:08.014 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -17:40:08.025 AxisRate:Primary OK Disposed axis rates OK -17:40:08.038 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -17:40:08.050 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -17:40:08.064 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -17:40:08.077 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -17:40:08.092 AxisRate:Secondary OK No overlapping axis rates found -17:40:08.104 AxisRate:Secondary OK No duplicate axis rates found -17:40:08.117 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -17:40:08.131 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -17:40:08.144 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -17:40:08.158 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -17:40:08.171 AxisRate:Secondary OK Disposed axis rates OK -17:40:08.187 AxisRate:Tertiary OK Empty axis rate returned -17:40:08.203 AxisRate:Tertiary OK Disposed axis rates OK -17:40:08.219 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -17:40:08.272 MoveAxis Primary OK Can successfully set a movement rate of zero -17:40:08.287 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -17:40:08.323 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -17:40:12.533 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -17:40:16.852 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -17:40:21.063 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -17:40:21.078 MoveAxis Primary OK AxisRates object successfully disposed -17:40:21.137 MoveAxis Secondary OK Can successfully set a movement rate of zero -17:40:21.154 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -17:40:21.193 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -17:40:25.403 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -17:40:29.692 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -17:40:33.903 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -17:40:33.918 MoveAxis Secondary OK AxisRates object successfully disposed -17:40:33.978 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -17:40:36.018 PulseGuide OK Synchronous pulse guide found OK -17:40:58.303 SlewToCoordinates INFO Slewed within 58.4 arc seconds of expected RA: 04:16:43.90, actual RA: 04:16:40.00 -17:40:58.316 SlewToCoordinates INFO Slewed within 7204.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:04.00 -17:40:58.353 SlewToCoordinates ERROR The TargetRightAscension property 04:16:40.00 does not match the expected RA 04:16:43.90 -17:40:58.388 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -17:40:58.438 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -17:40:58.519 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -17:40:58.579 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -17:40:58.666 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -17:41:20.304 SlewToCoordinatesAsync INFO Slewed within 38.9 arc seconds of expected RA: 03:17:06.59, actual RA: 03:17:04.00 -17:41:20.318 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 -17:41:20.353 SlewToCoordinatesAsync ERROR The TargetRightAscension property 03:17:04.00 does not match the expected RA 03:17:06.59 -17:41:20.390 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -17:41:20.429 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -17:41:20.510 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -17:41:20.570 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -17:41:20.654 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -17:41:42.297 SyncToCoordinates INFO Slewed to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 -17:41:42.310 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -17:41:42.995 SyncToCoordinates INFO Synced to sync position within 3589.6 arc seconds of expected RA: 02:13:28.69, actual RA: 02:17:28.00 -17:41:43.007 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 -17:41:43.043 SyncToCoordinates ERROR The TargetRightAscension property 02:13:28.00 does not match the expected RA 02:13:28.69 -17:41:43.075 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 -17:42:02.261 SyncToCoordinates INFO Slewed back to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 -17:42:02.273 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -17:42:02.954 SyncToCoordinates INFO Synced to reversed sync position within 3610.4 arc seconds of expected RA: 02:21:28.69, actual RA: 02:17:28.00 -17:42:02.967 SyncToCoordinates INFO Synced to reversed sync position within 3596.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:04.00 -17:42:22.265 SyncToCoordinates INFO Slewed back to start position within 10.4 arc seconds of expected RA: 02:17:28.69, actual RA: 02:17:28.00 -17:42:22.278 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -17:42:22.321 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -17:42:22.407 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -17:42:22.472 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -17:42:22.554 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -17:42:22.611 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -17:42:22.625 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -17:42:22.724 TargetRightAscension Write OK Target RightAscension is within 5 seconds of the value set: 01:18:30.74 -17:42:22.760 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -17:42:22.777 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -17:42:22.854 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -17:42:40.263 SlewToTarget INFO Slewed within 44.9 arc seconds of expected RA: 02:18:30.99, actual RA: 02:18:28.00 -17:42:40.276 SlewToTarget INFO Slewed within 21594.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:54.00 -17:42:40.311 SlewToTarget ERROR The TargetRightAscension property 02:18:28.00 does not match the expected RA 02:18:30.99 -17:42:40.345 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -17:42:40.384 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -17:42:40.425 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -17:42:40.486 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -17:42:40.529 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -17:43:02.273 SlewToTargetAsync INFO Slewed within 11.0 arc seconds of expected RA: 01:18:48.73, actual RA: 01:18:48.00 -17:43:02.286 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 -17:43:02.321 SlewToTargetAsync ERROR The TargetRightAscension property 01:18:48.00 does not match the expected RA 01:18:48.73 -17:43:02.355 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -17:43:02.394 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -17:43:02.437 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -17:43:02.495 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -17:43:02.538 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -17:43:02.597 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -17:43:02.786 SlewToAltAz INFO Slewed to within 136:49:26.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -17:43:02.800 SlewToAltAz INFO Slewed to within 46:00:02.00 DD:MM:SS of expected Altitude: 50:00:00.00 -17:43:02.843 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -17:43:02.903 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -17:43:02.963 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -17:43:03.027 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -17:43:08.342 SlewToAltAzAsync INFO Slewed to within 141:50:51.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -17:43:08.355 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 -17:43:08.396 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -17:43:08.451 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -17:43:08.513 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -17:43:08.568 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -17:43:30.263 SyncToTarget INFO Slewed to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 -17:43:30.277 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -17:43:30.960 SyncToTarget INFO Synced to sync position within 3586.6 arc seconds of expected RA: 02:15:16.90, actual RA: 02:19:16.00 -17:43:30.974 SyncToTarget INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 -17:43:54.229 SyncToTarget INFO Slewed back to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 -17:43:54.243 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -17:43:54.921 SyncToTarget INFO Synced to reversed sync position within 3613.4 arc seconds of expected RA: 02:23:16.90, actual RA: 02:19:16.00 -17:43:54.935 SyncToTarget INFO Synced to reversed sync position within 3599.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:01.00 -17:44:14.213 SyncToTarget INFO Slewed back to start position within 13.4 arc seconds of expected RA: 02:19:16.90, actual RA: 02:19:16.00 -17:44:14.232 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -17:44:14.269 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -17:44:14.313 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -17:44:14.372 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -17:44:14.415 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -17:44:14.571 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +18:05:20.107 CanMoveAxis:Primary OK CanMoveAxis:Primary True +18:05:20.142 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +18:05:20.178 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +18:05:20.214 Park/Unpark INFO Tests skipped +18:05:20.236 AbortSlew OK AbortSlew OK when not slewing +18:05:20.302 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:05:20.315 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:05:20.327 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:05:20.339 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:05:20.351 AxisRate:Primary OK No overlapping axis rates found +18:05:20.363 AxisRate:Primary OK No duplicate axis rates found +18:05:20.376 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +18:05:20.387 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +18:05:20.401 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +18:05:20.413 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +18:05:20.426 AxisRate:Primary OK Disposed axis rates OK +18:05:20.439 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:05:20.453 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:05:20.466 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:05:20.482 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:05:20.495 AxisRate:Secondary OK No overlapping axis rates found +18:05:20.510 AxisRate:Secondary OK No duplicate axis rates found +18:05:20.523 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +18:05:20.536 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +18:05:20.552 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +18:05:20.564 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +18:05:20.577 AxisRate:Secondary OK Disposed axis rates OK +18:05:20.590 AxisRate:Tertiary OK Empty axis rate returned +18:05:20.603 AxisRate:Tertiary OK Disposed axis rates OK +18:05:20.618 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +18:05:20.671 MoveAxis Primary OK Can successfully set a movement rate of zero +18:05:20.689 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:05:20.726 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +18:05:24.935 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +18:05:29.204 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +18:05:33.391 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:05:33.406 MoveAxis Primary OK AxisRates object successfully disposed +18:05:33.466 MoveAxis Secondary OK Can successfully set a movement rate of zero +18:05:33.481 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:05:33.520 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +18:05:37.730 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +18:05:42.005 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +18:05:46.216 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:05:46.231 MoveAxis Secondary OK AxisRates object successfully disposed +18:05:46.290 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +18:05:48.330 PulseGuide OK Synchronous pulse guide found OK +18:06:09.428 SlewToCoordinates OK Slewed OK. RA: 04:35:36.36 +18:06:09.443 SlewToCoordinates INFO Slewed within 7204.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:04.00 +18:06:09.479 SlewToCoordinates OK The TargetRightAscension property 04:35:36.36 matches the expected RA OK. +18:06:09.514 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +18:06:09.565 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:06:09.647 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:06:09.707 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:06:09.791 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:06:31.440 SlewToCoordinatesAsync INFO Slewed within 27.8 arc seconds of expected RA: 03:35:57.86, actual RA: 03:35:56.00 +18:06:31.454 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 +18:06:31.489 SlewToCoordinatesAsync ERROR The TargetRightAscension property 03:35:56.00 does not match the expected RA 03:35:57.86 +18:06:31.523 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +18:06:31.567 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:06:31.652 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:06:31.712 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:06:31.796 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:06:53.436 SyncToCoordinates INFO Slewed to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 +18:06:53.450 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +18:06:54.136 SyncToCoordinates INFO Synced to sync position within 3540.5 arc seconds of expected RA: 02:32:19.97, actual RA: 02:36:16.00 +18:06:54.151 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 +18:06:54.188 SyncToCoordinates ERROR The TargetRightAscension property 02:32:16.00 does not match the expected RA 02:32:19.97 +18:06:54.222 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 +18:07:15.394 SyncToCoordinates INFO Slewed back to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 +18:07:15.407 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:07:16.086 SyncToCoordinates INFO Synced to reversed sync position within 3659.5 arc seconds of expected RA: 02:40:19.97, actual RA: 02:36:16.00 +18:07:16.103 SyncToCoordinates INFO Synced to reversed sync position within 3598.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:02.00 +18:07:35.385 SyncToCoordinates INFO Slewed back to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 +18:07:35.399 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:07:35.439 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:07:35.524 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:07:35.586 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:07:35.668 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:07:35.730 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +18:07:35.743 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +18:07:35.847 TargetRightAscension Write OK Target RightAscension is within 1 second of the value set: 01:37:24.00 +18:07:35.885 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:07:35.901 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:07:35.994 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +18:07:55.393 SlewToTarget OK Slewed OK. RA: 02:37:24.28 +18:07:55.408 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 +18:07:55.443 SlewToTarget OK The TargetRightAscension property 02:37:24.28 matches the expected RA OK. +18:07:55.478 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +18:07:55.518 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:07:55.570 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:07:55.628 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:07:55.670 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:08:17.404 SlewToTargetAsync OK Slewed OK. RA: 01:37:44.03 +18:08:17.418 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 +18:08:17.452 SlewToTargetAsync OK The TargetRightAscension property 01:37:44.03 matches the expected RA OK. +18:08:17.486 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +18:08:17.525 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:08:17.569 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:08:17.628 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:08:17.672 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:08:17.731 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +18:08:17.928 SlewToAltAz INFO Slewed to within 144:23:20.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +18:08:17.944 SlewToAltAz INFO Slewed to within 46:00:02.00 DD:MM:SS of expected Altitude: 50:00:00.00 +18:08:17.985 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:08:18.048 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:08:18.108 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:08:18.167 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:08:23.478 SlewToAltAzAsync INFO Slewed to within 149:24:45.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +18:08:23.492 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 +18:08:23.534 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:08:23.590 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:08:23.652 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:08:23.712 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:08:47.383 SyncToTarget OK Slewed to start position OK. RA: 02:38:12.20 +18:08:47.398 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +18:08:48.087 SyncToTarget INFO Synced to sync position within 3597.1 arc seconds of expected RA: 02:34:12.20, actual RA: 02:38:12.00 +18:08:48.101 SyncToTarget INFO Synced to sync position within 3599.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:01.00 +18:09:07.348 SyncToTarget OK Slewed back to start position OK. RA: 02:38:12.20 +18:09:07.366 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:09:08.050 SyncToTarget INFO Synced to reversed sync position within 3602.9 arc seconds of expected RA: 02:42:12.20, actual RA: 02:38:12.00 +18:09:08.065 SyncToTarget INFO Synced to reversed sync position within 3598.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:02.00 +18:09:27.338 SyncToTarget OK Slewed back to start position OK. RA: 02:38:12.20 +18:09:27.353 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:09:27.396 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:09:27.438 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:09:27.498 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:09:27.542 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:09:27.695 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -17:44:14.640 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +18:09:27.762 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -17:44:14.728 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +18:09:27.856 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 6 errors, 0 warnings and 1 issues +Your driver had 3 errors, 1 warning and 0 issue diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index c05c959..8af1855 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -896,8 +896,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("TrackingRate Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TrackingRate", false); + var tr = _telescopeController.TrackingRate; + tl.LogMessage("TrackingRate Get", $"{tr}"); + return tr; } set { diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 02e40f3..06698ea 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -20,6 +20,7 @@ namespace ASCOM.MeadeAutostar497.Controller double Declination { get; } double TargetRightAscension { get; set; } double TargetDeclination { get; set; } + DriveRates TrackingRate { get; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index fa15f0a..89a4828 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -476,6 +476,49 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public DriveRates TrackingRate + { + get + { + var result = SerialPort.CommandTerminated(":GT#", "#"); + + double rate = double.Parse(result); + + + if (rate == 60.1) + return DriveRates.driveLunar; + else if (rate == 60.1) + return DriveRates.driveSidereal; + + return DriveRates.driveKing; + } + set + { + switch (value) + { + case DriveRates.driveSidereal: + SerialPort.Command(":TQ#"); + //:TQ# Selects sidereal tracking rate + //Returns: Nothing + break; + case DriveRates.driveLunar: + SerialPort.Command(":TL#"); + //:TL# Set Lunar Tracking Rage + //Returns: Nothing + break; + case DriveRates.driveSolar: + SerialPort.Command(":TS#"); + //:TS# Select Solar tracking rate. [LS Only] + //Returns: Nothing + break; + case DriveRates.driveKing: + break; + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + } + } + public double Altitude { get { diff --git a/TestConsole/Program.cs b/TestConsole/Program.cs index e906485..6c8fa71 100644 --- a/TestConsole/Program.cs +++ b/TestConsole/Program.cs @@ -60,7 +60,10 @@ namespace ASCOM //Console.WriteLine(device.RightAscension); - device.SlewToAltAz(0,0); + //device.SlewToAltAz(0,0); + + + Console.WriteLine(device.TrackingRate); device.Connected = false; Console.WriteLine("Press Enter to finish"); From 6a4c08a7c46dbeb0c2601d9e211024a04365c5a7 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 7 May 2019 22:38:29 +0100 Subject: [PATCH 030/109] Added IFocuserV3 to the driver and made sure that it's registered for ASCOM as a focuser as well. --- MeadeAutostar497/AscomClasses/Telescope.cs | 141 ++++++++++++++++++++- 1 file changed, 136 insertions(+), 5 deletions(-) diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 8af1855..9892ea6 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -56,7 +56,7 @@ namespace ASCOM.MeadeAutostar497 /// [Guid("58e4fe97-1760-4e22-8ecd-2225876aeefc")] [ClassInterface(ClassInterfaceType.None)] - public class Telescope : ITelescopeV3 + public class Telescope : ITelescopeV3, IFocuserV3 { private ITelescopeController _telescopeController; @@ -947,6 +947,124 @@ namespace ASCOM.MeadeAutostar497 #endregion + #region IFocuser Implementation + + private int focuserPosition = 0; // Class level variable to hold the current focuser position + private const int focuserSteps = 10000; + + public bool Absolute + { + get + { + tl.LogMessage("Absolute Get", true.ToString()); + return true; // This is an absolute focuser + } + } + + public void Halt() + { + tl.LogMessage("Halt", "Not implemented"); + throw new ASCOM.MethodNotImplementedException("Halt"); + } + + public bool IsMoving + { + get + { + tl.LogMessage("IsMoving Get", false.ToString()); + return false; // This focuser always moves instantaneously so no need for IsMoving ever to be True + } + } + + public bool Link + { + get + { + tl.LogMessage("Link Get", this.Connected.ToString()); + return this.Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility + } + set + { + tl.LogMessage("Link Set", value.ToString()); + this.Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility + } + } + + public int MaxIncrement + { + get + { + tl.LogMessage("MaxIncrement Get", focuserSteps.ToString()); + return focuserSteps; // Maximum change in one move + } + } + + public int MaxStep + { + get + { + tl.LogMessage("MaxStep Get", focuserSteps.ToString()); + return focuserSteps; // Maximum extent of the focuser, so position range is 0 to 10,000 + } + } + + public void Move(int Position) + { + tl.LogMessage("Move", Position.ToString()); + focuserPosition = Position; // Set the focuser position + } + + public int Position + { + get + { + return focuserPosition; // Return the focuser position + } + } + + public double StepSize + { + get + { + tl.LogMessage("StepSize Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("StepSize", false); + } + } + + public bool TempComp + { + get + { + tl.LogMessage("TempComp Get", false.ToString()); + return false; + } + set + { + tl.LogMessage("TempComp Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("TempComp", false); + } + } + + public bool TempCompAvailable + { + get + { + tl.LogMessage("TempCompAvailable Get", false.ToString()); + return false; // Temperature compensation is not available in this driver + } + } + + public double Temperature + { + get + { + tl.LogMessage("Temperature Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("Temperature", false); + } + } + + #endregion + #region Private properties and methods // here are some useful properties and methods that can be used as required // to help with driver development @@ -963,16 +1081,29 @@ namespace ASCOM.MeadeAutostar497 /// If true, registers the driver, otherwise unregisters it. private static void RegUnregASCOM(bool bRegister) { - using (var P = new ASCOM.Utilities.Profile()) + using (var p = new ASCOM.Utilities.Profile()) { - P.DeviceType = "Telescope"; + p.DeviceType = "Telescope"; if (bRegister) { - P.Register(driverID, driverDescription); + p.Register(driverID, driverDescription); } else { - P.Unregister(driverID); + p.Unregister(driverID); + } + } + + using (var p = new ASCOM.Utilities.Profile()) + { + p.DeviceType = "Focuser"; + if (bRegister) + { + p.Register(driverID, driverDescription); + } + else + { + p.Unregister(driverID); } } } From fed8b1a24b35c00d7ccf0424b942c410d24c245c Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 8 May 2019 17:45:42 +0100 Subject: [PATCH 031/109] Fixed issue with Target RA and Dec loosing precision --- .../Controller/TelescopeController.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 89a4828..db3916d 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -395,13 +395,14 @@ namespace ASCOM.MeadeAutostar497.Controller if (_targetRightAscension == INVALID_PARAMETER) throw new ASCOM.InvalidOperationException("Target not set"); - var result = SerialPort.CommandTerminated(":Gr#", "#"); - //:Gr# Get current/target object RA - //Returns: HH: MM.T# or HH:MM:SS - //Depending upon which precision is set for the telescope + //var result = SerialPort.CommandTerminated(":Gr#", "#"); + ////:Gr# Get current/target object RA + ////Returns: HH: MM.T# or HH:MM:SS + ////Depending upon which precision is set for the telescope - double targetRa = HmsToDouble(result); - return targetRa; + //double targetRa = HmsToDouble(result); + //return targetRa; + return _targetRightAscension; } set { @@ -437,15 +438,15 @@ namespace ASCOM.MeadeAutostar497.Controller if (_targetDeclination == INVALID_PARAMETER) throw new ASCOM.InvalidOperationException("Target not set"); - var result = SerialPort.CommandTerminated(":Gd#", "#"); - //:Gd# Get Currently Selected Object/Target Declination - //Returns: sDD* MM# or sDD*MM’SS# - //Depending upon the current precision setting for the telescope. + //var result = SerialPort.CommandTerminated(":Gd#", "#"); + ////:Gd# Get Currently Selected Object/Target Declination + ////Returns: sDD* MM# or sDD*MM’SS# + ////Depending upon the current precision setting for the telescope. - double targetDec = DmsToDouble(result); - - return targetDec; + //double targetDec = DmsToDouble(result); + //return targetDec; + return _targetDeclination; } set { From 3f8853c7c55c0fc91604d3c656e78e57058c4201 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 8 May 2019 18:19:23 +0100 Subject: [PATCH 032/109] Telescope driver now passes the Ascom conformance. --- ....MeadeAutostar497.Telescope.Validation.txt | 268 ++++++++++ ConformanceResult.txt | 466 +++++++++--------- 2 files changed, 504 insertions(+), 230 deletions(-) create mode 100644 ASCOM.MeadeAutostar497.Telescope.Validation.txt diff --git a/ASCOM.MeadeAutostar497.Telescope.Validation.txt b/ASCOM.MeadeAutostar497.Telescope.Validation.txt new file mode 100644 index 0000000..eff5811 --- /dev/null +++ b/ASCOM.MeadeAutostar497.Telescope.Validation.txt @@ -0,0 +1,268 @@ +Conform Report Hash (V1): 671D83C15427DD14D9FA7F5A6C62D6B21372362C5173A2B95171D14D7442358DCF3950481797D63EB94E642D2563C3094C387C23D65466833FEA5E64CD045B46 + + +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040401 +Error number for "Invalid Value 2" is: 80040405 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +18:07:45.625 Driver Access Checks OK +18:07:46.272 AccessChecks OK Successfully created driver using late binding +18:07:46.685 AccessChecks OK Successfully connected using late binding +18:07:46.689 AccessChecks INFO The driver is a .NET object +18:07:46.693 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +18:07:46.697 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +18:07:46.701 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +18:07:47.416 AccessChecks INFO Device does not expose interface ITelescopeV2 +18:07:48.387 AccessChecks INFO Device exposes interface ITelescopeV3 +18:07:49.708 AccessChecks OK Successfully created driver using driver access toolkit +18:07:50.029 AccessChecks OK Successfully connected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object +18:07:51.351 ConformanceCheck OK Driver instance created successfully +18:07:51.775 ConformanceCheck OK Connected OK + +Common Driver Methods +18:07:51.817 InterfaceVersion OK 3 +18:07:51.845 Connected OK True +18:07:51.874 Description OK Meade Autostar 497 .net +18:07:51.903 DriverInfo OK Information about the driver itself. Version: 0.0 +18:07:51.932 DriverVersion OK 0.0 +18:07:51.961 Name OK Meade Autostar 497 .net +18:07:51.990 CommandString INFO Conform cannot test the CommandString method +18:07:51.996 CommandBlind INFO Conform cannot test the CommandBlind method +18:07:52.002 CommandBool INFO Conform cannot test the CommandBool method +18:07:52.008 Action INFO Conform cannot test the Action method +18:07:52.015 SupportedActions OK Driver returned an empty action list + +Can Properties +18:07:52.082 CanFindHome OK False +18:07:52.089 CanPark OK True +18:07:52.096 CanPulseGuide OK True +18:07:52.102 CanSetDeclinationRate OK False +18:07:52.109 CanSetGuideRates OK False +18:07:52.117 CanSetPark OK False +18:07:52.125 CanSetPierSide OK False +18:07:52.177 CanSetRightAscensionRate OK False +18:07:52.185 CanSetTracking OK False +18:07:52.193 CanSlew OK True +18:07:52.200 CanSlewltAz OK True +18:07:52.208 CanSlewAltAzAsync OK True +18:07:52.216 CanSlewAsync OK True +18:07:52.224 CanSync OK True +18:07:52.231 CanSyncAltAz OK False +18:07:52.239 CanUnPark OK False + +Pre-run Checks +18:07:52.286 Mount Safety INFO Scope is not parked, continuing testing +18:07:52.339 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +18:07:52.348 TimeCheck INFO PC UTCDate: 08-May-2019 17:07:52.347 +18:07:53.254 TimeCheck INFO Mount UTCDate: 02-May-2019 19:33:55.000 + +Properties +18:07:53.358 AlignmentMode OK algPolar +18:07:53.515 Altitude OK 1.00 +18:07:53.555 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +18:07:53.591 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +18:07:53.622 AtHome OK False +18:07:53.654 AtPark OK False +18:07:53.847 Azimuth OK 45.67 +18:07:54.028 Declination OK -01:00:01.00 +18:07:54.060 DeclinationRate Read OK 0.00 +18:07:54.093 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.126 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.159 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.193 EquatorialSystem OK equLocalTopocentric +18:07:54.227 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.260 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.270 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.303 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.314 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.347 IsPulseGuiding OK False +18:07:54.541 RightAscension OK 03:59:09.00 +18:07:54.575 RightAscensionRate Read OK 0.00 +18:07:54.609 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.644 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.678 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.691 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.703 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.861 SiteLatitude Read OK 00:00:00.00 +18:07:54.900 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +18:07:54.912 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +18:07:55.315 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +18:07:55.455 SiteLongitude Read OK -42:12:00.00 +18:07:55.490 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +18:07:55.502 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +18:07:56.090 SiteLongitude Write OK Legal value -42:12:00.00 degrees written successfully +18:07:56.246 Slewing OK False +18:07:56.280 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.315 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.328 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.363 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.578 SiderealTime OK 05:17:41.24 +18:07:56.590 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:17:41.24, ASCOM: 05:24:06.50 +18:07:56.626 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +18:07:56.661 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:07:56.673 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +18:07:56.708 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:07:56.720 Tracking Read OK True +18:07:56.756 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +18:07:56.797 TrackingRates Found drive rate: driveSidereal +18:07:56.809 TrackingRates OK Drive rates read OK +18:07:56.822 TrackingRates OK Disposed tracking rates OK +18:07:56.858 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +18:07:57.039 TrackingRate Read OK driveLunar +18:07:57.075 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:57.088 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:57.624 UTCDate Read OK 02-May-2019 19:33:59.000 +18:07:58.626 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:33:59 + +Methods +18:07:59.997 CanMoveAxis:Primary OK CanMoveAxis:Primary True +18:08:00.035 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +18:08:00.072 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +18:08:00.108 Park/Unpark INFO Tests skipped +18:08:00.131 AbortSlew OK AbortSlew OK when not slewing +18:08:00.199 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:08:00.211 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:08:00.225 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:08:00.239 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:08:00.253 AxisRate:Primary OK No overlapping axis rates found +18:08:00.266 AxisRate:Primary OK No duplicate axis rates found +18:08:00.279 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +18:08:00.295 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +18:08:00.310 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +18:08:00.322 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +18:08:00.336 AxisRate:Primary OK Disposed axis rates OK +18:08:00.350 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:08:00.362 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:08:00.375 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:08:00.387 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:08:00.400 AxisRate:Secondary OK No overlapping axis rates found +18:08:00.414 AxisRate:Secondary OK No duplicate axis rates found +18:08:00.445 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +18:08:00.458 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +18:08:00.472 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +18:08:00.487 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +18:08:00.501 AxisRate:Secondary OK Disposed axis rates OK +18:08:00.517 AxisRate:Tertiary OK Empty axis rate returned +18:08:00.531 AxisRate:Tertiary OK Disposed axis rates OK +18:08:00.550 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +18:08:00.606 MoveAxis Primary OK Can successfully set a movement rate of zero +18:08:00.622 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:08:00.659 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +18:08:04.867 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +18:08:09.770 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +18:08:13.981 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:08:13.998 MoveAxis Primary OK AxisRates object successfully disposed +18:08:14.057 MoveAxis Secondary OK Can successfully set a movement rate of zero +18:08:14.072 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:08:14.107 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +18:08:18.317 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +18:08:23.262 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +18:08:27.473 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:08:27.492 MoveAxis Secondary OK AxisRates object successfully disposed +18:08:27.551 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +18:08:29.592 PulseGuide OK Synchronous pulse guide found OK +18:08:54.449 SlewToCoordinates INFO Slewed within 39.2 arc seconds of expected RA: 04:18:14.61, actual RA: 04:18:12.00 +18:08:54.463 SlewToCoordinates INFO Slewed within 7199.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:59.00 +18:08:54.478 SlewToCoordinates OK The TargetRightAscension property 04:18:14.61 matches the expected RA OK. +18:08:54.492 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +18:08:54.548 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:08:55.301 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:08:55.360 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:08:56.199 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:09:20.477 SlewToCoordinatesAsync INFO Slewed within 19.3 arc seconds of expected RA: 03:18:41.28, actual RA: 03:18:40.00 +18:09:20.490 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 +18:09:20.503 SlewToCoordinatesAsync OK The TargetRightAscension property 03:18:41.28 matches the expected RA OK. +18:09:20.516 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +18:09:20.558 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:09:21.381 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:09:21.442 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:09:22.292 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:09:44.520 SyncToCoordinates INFO Slewed to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:09:44.534 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +18:09:47.045 SyncToCoordinates INFO Synced to sync position within 71.8 arc seconds of expected RA: 02:15:07.79, actual RA: 02:15:03.00 +18:09:47.058 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +18:09:47.071 SyncToCoordinates OK The TargetRightAscension property 02:15:07.79 matches the expected RA OK. +18:09:47.085 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. +18:10:08.444 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:10:08.458 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:10:10.791 SyncToCoordinates INFO Synced to reversed sync position within 71.8 arc seconds of expected RA: 02:23:07.79, actual RA: 02:23:03.00 +18:10:10.806 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +18:10:32.484 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:10:32.498 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:10:32.537 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:10:33.329 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:10:33.389 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:10:34.242 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:10:34.301 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +18:10:34.315 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +18:10:34.979 TargetRightAscension Write OK Legal value 01:20:19.62 HH:MM:SS written successfully +18:10:35.016 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:10:35.032 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:10:35.652 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +18:10:56.417 SlewToTarget INFO Slewed within 14.8 arc seconds of expected RA: 02:20:20.99, actual RA: 02:20:20.00 +18:10:56.434 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 +18:10:56.449 SlewToTarget OK The TargetRightAscension property 02:20:20.99 matches the expected RA OK. +18:10:56.463 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +18:10:56.504 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:10:56.676 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:10:56.736 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:10:56.915 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:11:20.512 SlewToTargetAsync INFO Slewed within 35.1 arc seconds of expected RA: 01:20:42.34, actual RA: 01:20:40.00 +18:11:20.526 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 +18:11:20.539 SlewToTargetAsync OK The TargetRightAscension property 01:20:42.34 matches the expected RA OK. +18:11:20.553 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +18:11:20.593 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:11:20.774 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:11:20.833 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:11:21.032 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:11:21.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +18:11:22.864 SlewToAltAz INFO Slewed to within 144:49:47.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +18:11:22.880 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 +18:11:22.920 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:11:23.710 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:11:23.771 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:11:24.447 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:11:31.196 SlewToAltAzAsync INFO Slewed to within 149:51:53.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +18:11:31.210 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 +18:11:31.251 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:11:32.060 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:11:32.121 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:11:32.814 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:11:56.494 SyncToTarget INFO Slewed to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:11:56.509 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +18:11:59.005 SyncToTarget INFO Synced to sync position within 55.1 arc seconds of expected RA: 02:17:18.67, actual RA: 02:17:15.00 +18:11:59.019 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +18:12:22.398 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:12:22.416 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:12:24.739 SyncToTarget INFO Synced to reversed sync position within 55.1 arc seconds of expected RA: 02:25:18.67, actual RA: 02:25:15.00 +18:12:24.754 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +18:12:46.438 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:12:46.452 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:12:46.491 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:12:46.643 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:12:46.702 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:12:46.884 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:12:47.702 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected + +SideOfPier Model Tests +18:12:47.769 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read + +Post-run Checks +18:12:47.862 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. + +Conformance test complete + +No errors, warnings or issues found: your driver passes ASCOM validation!! + +Driver Hash Value: 0C55C8535B9B3A4048581454F9D6A263EFD16E20AEC783762006739F671F586B64F1D8DD3E1E613C27A5B24838AEB8656C2A19BD1EE69177ECF2619599C0DA3C diff --git a/ConformanceResult.txt b/ConformanceResult.txt index 0b9572e..beecf54 100644 --- a/ConformanceResult.txt +++ b/ConformanceResult.txt @@ -15,252 +15,258 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -18:05:11.632 Driver Access Checks OK -18:05:12.272 AccessChecks OK Successfully created driver using late binding -18:05:12.505 AccessChecks OK Successfully connected using late binding -18:05:12.509 AccessChecks INFO The driver is a .NET object -18:05:12.514 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -18:05:12.518 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -18:05:13.217 AccessChecks INFO Device does not expose interface ITelescopeV2 -18:05:14.028 AccessChecks INFO Device exposes interface ITelescopeV3 -18:05:15.344 AccessChecks OK Successfully created driver using driver access toolkit -18:05:15.517 AccessChecks OK Successfully connected using driver access toolkit +18:07:45.625 Driver Access Checks OK +18:07:46.272 AccessChecks OK Successfully created driver using late binding +18:07:46.685 AccessChecks OK Successfully connected using late binding +18:07:46.689 AccessChecks INFO The driver is a .NET object +18:07:46.693 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +18:07:46.697 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +18:07:46.701 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +18:07:47.416 AccessChecks INFO Device does not expose interface ITelescopeV2 +18:07:48.387 AccessChecks INFO Device exposes interface ITelescopeV3 +18:07:49.708 AccessChecks OK Successfully created driver using driver access toolkit +18:07:50.029 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -18:05:16.845 ConformanceCheck OK Driver instance created successfully -18:05:17.057 ConformanceCheck OK Connected OK +18:07:51.351 ConformanceCheck OK Driver instance created successfully +18:07:51.775 ConformanceCheck OK Connected OK Common Driver Methods -18:05:17.098 InterfaceVersion OK 3 -18:05:17.127 Connected OK True -18:05:17.155 Description OK Meade Autostar 497 .net -18:05:17.184 DriverInfo OK Information about the driver itself. Version: 0.0 -18:05:17.214 DriverVersion OK 0.0 -18:05:17.243 Name OK Meade Autostar 497 .net -18:05:17.272 CommandString INFO Conform cannot test the CommandString method -18:05:17.278 CommandBlind INFO Conform cannot test the CommandBlind method -18:05:17.284 CommandBool INFO Conform cannot test the CommandBool method -18:05:17.291 Action INFO Conform cannot test the Action method -18:05:17.298 SupportedActions OK Driver returned an empty action list +18:07:51.817 InterfaceVersion OK 3 +18:07:51.845 Connected OK True +18:07:51.874 Description OK Meade Autostar 497 .net +18:07:51.903 DriverInfo OK Information about the driver itself. Version: 0.0 +18:07:51.932 DriverVersion OK 0.0 +18:07:51.961 Name OK Meade Autostar 497 .net +18:07:51.990 CommandString INFO Conform cannot test the CommandString method +18:07:51.996 CommandBlind INFO Conform cannot test the CommandBlind method +18:07:52.002 CommandBool INFO Conform cannot test the CommandBool method +18:07:52.008 Action INFO Conform cannot test the Action method +18:07:52.015 SupportedActions OK Driver returned an empty action list Can Properties -18:05:17.364 CanFindHome OK False -18:05:17.372 CanPark OK True -18:05:17.379 CanPulseGuide OK True -18:05:17.386 CanSetDeclinationRate OK False -18:05:17.393 CanSetGuideRates OK False -18:05:17.401 CanSetPark OK False -18:05:17.412 CanSetPierSide OK False -18:05:17.425 CanSetRightAscensionRate OK False -18:05:17.432 CanSetTracking OK False -18:05:17.440 CanSlew OK True -18:05:17.449 CanSlewltAz OK True -18:05:17.458 CanSlewAltAzAsync OK True -18:05:17.466 CanSlewAsync OK True -18:05:17.475 CanSync OK True -18:05:17.484 CanSyncAltAz OK False -18:05:17.493 CanUnPark OK False +18:07:52.082 CanFindHome OK False +18:07:52.089 CanPark OK True +18:07:52.096 CanPulseGuide OK True +18:07:52.102 CanSetDeclinationRate OK False +18:07:52.109 CanSetGuideRates OK False +18:07:52.117 CanSetPark OK False +18:07:52.125 CanSetPierSide OK False +18:07:52.177 CanSetRightAscensionRate OK False +18:07:52.185 CanSetTracking OK False +18:07:52.193 CanSlew OK True +18:07:52.200 CanSlewltAz OK True +18:07:52.208 CanSlewAltAzAsync OK True +18:07:52.216 CanSlewAsync OK True +18:07:52.224 CanSync OK True +18:07:52.231 CanSyncAltAz OK False +18:07:52.239 CanUnPark OK False Pre-run Checks -18:05:17.542 Mount Safety INFO Scope is not parked, continuing testing -18:05:17.594 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -18:05:17.602 TimeCheck INFO PC UTCDate: 07-May-2019 17:05:17.602 -18:05:17.727 TimeCheck INFO Mount UTCDate: 02-May-2019 20:05:41.000 +18:07:52.286 Mount Safety INFO Scope is not parked, continuing testing +18:07:52.339 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +18:07:52.348 TimeCheck INFO PC UTCDate: 08-May-2019 17:07:52.347 +18:07:53.254 TimeCheck INFO Mount UTCDate: 02-May-2019 19:33:55.000 Properties -18:05:17.801 AlignmentMode OK algPolar -18:05:17.854 Altitude WARNING Altitude is <0.0 degrees: -0.97166667 -18:05:17.892 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -18:05:17.927 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -18:05:17.959 AtHome OK False -18:05:17.990 AtPark OK False -18:05:18.052 Azimuth OK 22.80 -18:05:18.107 Declination OK 00:58:18.00 -18:05:18.139 DeclinationRate Read OK 0.00 -18:05:18.171 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -18:05:18.204 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.237 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.269 EquatorialSystem OK equLocalTopocentric -18:05:18.301 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.334 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.345 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:05:18.377 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.388 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:05:18.421 IsPulseGuiding OK False -18:05:18.482 RightAscension OK 02:43:28.00 -18:05:18.515 RightAscensionRate Read OK 0.00 -18:05:18.548 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -18:05:18.582 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.617 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.628 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.640 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:18.700 SiteLatitude Read OK 00:00:00.00 -18:05:18.738 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -18:05:18.751 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -18:05:18.787 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -18:05:18.866 SiteLongitude Read OK -36:12:00.00 -18:05:18.901 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -18:05:18.913 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -18:05:19.006 SiteLongitude Write OK Legal value -36:12:00.00 degrees written successfully -18:05:19.050 Slewing OK False -18:05:19.084 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.119 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.132 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.167 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.221 SiderealTime OK 05:35:07.05 -18:05:19.233 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:35:07.05, ASCOM: 05:41:32.15 -18:05:19.280 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -18:05:19.314 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:05:19.327 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -18:05:19.361 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:05:19.373 Tracking Read OK True -18:05:19.408 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -18:05:19.450 TrackingRates Found drive rate: driveSidereal -18:05:19.463 TrackingRates OK Drive rates read OK -18:05:19.476 TrackingRates OK Disposed tracking rates OK -18:05:19.511 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -18:05:19.545 TrackingRate Read OK driveLunar -18:05:19.579 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.592 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:05:19.685 UTCDate Read OK 02-May-2019 20:05:43.000 -18:05:19.854 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:05:43 +18:07:53.358 AlignmentMode OK algPolar +18:07:53.515 Altitude OK 1.00 +18:07:53.555 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +18:07:53.591 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +18:07:53.622 AtHome OK False +18:07:53.654 AtPark OK False +18:07:53.847 Azimuth OK 45.67 +18:07:54.028 Declination OK -01:00:01.00 +18:07:54.060 DeclinationRate Read OK 0.00 +18:07:54.093 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.126 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.159 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.193 EquatorialSystem OK equLocalTopocentric +18:07:54.227 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.260 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.270 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.303 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.314 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.347 IsPulseGuiding OK False +18:07:54.541 RightAscension OK 03:59:09.00 +18:07:54.575 RightAscensionRate Read OK 0.00 +18:07:54.609 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +18:07:54.644 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.678 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.691 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.703 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:54.861 SiteLatitude Read OK 00:00:00.00 +18:07:54.900 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +18:07:54.912 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +18:07:55.315 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +18:07:55.455 SiteLongitude Read OK -42:12:00.00 +18:07:55.490 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +18:07:55.502 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +18:07:56.090 SiteLongitude Write OK Legal value -42:12:00.00 degrees written successfully +18:07:56.246 Slewing OK False +18:07:56.280 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.315 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.328 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.363 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +18:07:56.578 SiderealTime OK 05:17:41.24 +18:07:56.590 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:17:41.24, ASCOM: 05:24:06.50 +18:07:56.626 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +18:07:56.661 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:07:56.673 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +18:07:56.708 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +18:07:56.720 Tracking Read OK True +18:07:56.756 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected +18:07:56.797 TrackingRates Found drive rate: driveSidereal +18:07:56.809 TrackingRates OK Drive rates read OK +18:07:56.822 TrackingRates OK Disposed tracking rates OK +18:07:56.858 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +18:07:57.039 TrackingRate Read OK driveLunar +18:07:57.075 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:57.088 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. +18:07:57.624 UTCDate Read OK 02-May-2019 19:33:59.000 +18:07:58.626 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:33:59 Methods -18:05:20.107 CanMoveAxis:Primary OK CanMoveAxis:Primary True -18:05:20.142 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -18:05:20.178 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -18:05:20.214 Park/Unpark INFO Tests skipped -18:05:20.236 AbortSlew OK AbortSlew OK when not slewing -18:05:20.302 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:05:20.315 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:05:20.327 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:05:20.339 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:05:20.351 AxisRate:Primary OK No overlapping axis rates found -18:05:20.363 AxisRate:Primary OK No duplicate axis rates found -18:05:20.376 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -18:05:20.387 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -18:05:20.401 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -18:05:20.413 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -18:05:20.426 AxisRate:Primary OK Disposed axis rates OK -18:05:20.439 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:05:20.453 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:05:20.466 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:05:20.482 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:05:20.495 AxisRate:Secondary OK No overlapping axis rates found -18:05:20.510 AxisRate:Secondary OK No duplicate axis rates found -18:05:20.523 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -18:05:20.536 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -18:05:20.552 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -18:05:20.564 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -18:05:20.577 AxisRate:Secondary OK Disposed axis rates OK -18:05:20.590 AxisRate:Tertiary OK Empty axis rate returned -18:05:20.603 AxisRate:Tertiary OK Disposed axis rates OK -18:05:20.618 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -18:05:20.671 MoveAxis Primary OK Can successfully set a movement rate of zero -18:05:20.689 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:05:20.726 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -18:05:24.935 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -18:05:29.204 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -18:05:33.391 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:05:33.406 MoveAxis Primary OK AxisRates object successfully disposed -18:05:33.466 MoveAxis Secondary OK Can successfully set a movement rate of zero -18:05:33.481 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:05:33.520 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -18:05:37.730 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -18:05:42.005 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -18:05:46.216 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:05:46.231 MoveAxis Secondary OK AxisRates object successfully disposed -18:05:46.290 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -18:05:48.330 PulseGuide OK Synchronous pulse guide found OK -18:06:09.428 SlewToCoordinates OK Slewed OK. RA: 04:35:36.36 -18:06:09.443 SlewToCoordinates INFO Slewed within 7204.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:04.00 -18:06:09.479 SlewToCoordinates OK The TargetRightAscension property 04:35:36.36 matches the expected RA OK. -18:06:09.514 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -18:06:09.565 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:06:09.647 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:06:09.707 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:06:09.791 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:06:31.440 SlewToCoordinatesAsync INFO Slewed within 27.8 arc seconds of expected RA: 03:35:57.86, actual RA: 03:35:56.00 -18:06:31.454 SlewToCoordinatesAsync INFO Slewed within 14396.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:56.00 -18:06:31.489 SlewToCoordinatesAsync ERROR The TargetRightAscension property 03:35:56.00 does not match the expected RA 03:35:57.86 -18:06:31.523 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -18:06:31.567 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:06:31.652 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:06:31.712 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:06:31.796 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:06:53.436 SyncToCoordinates INFO Slewed to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 -18:06:53.450 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -18:06:54.136 SyncToCoordinates INFO Synced to sync position within 3540.5 arc seconds of expected RA: 02:32:19.97, actual RA: 02:36:16.00 -18:06:54.151 SyncToCoordinates INFO Synced to sync position within 3598.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:02.00 -18:06:54.188 SyncToCoordinates ERROR The TargetRightAscension property 02:32:16.00 does not match the expected RA 02:32:19.97 -18:06:54.222 SyncToCoordinates ERROR The TargetDeclination property -00:01:00.00 does not match the expected Declination -01:00:00.00 -18:07:15.394 SyncToCoordinates INFO Slewed back to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 -18:07:15.407 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:07:16.086 SyncToCoordinates INFO Synced to reversed sync position within 3659.5 arc seconds of expected RA: 02:40:19.97, actual RA: 02:36:16.00 -18:07:16.103 SyncToCoordinates INFO Synced to reversed sync position within 3598.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:02.00 -18:07:35.385 SyncToCoordinates INFO Slewed back to start position within 59.5 arc seconds of expected RA: 02:36:19.97, actual RA: 02:36:16.00 -18:07:35.399 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:07:35.439 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:07:35.524 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:07:35.586 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:07:35.668 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:07:35.730 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -18:07:35.743 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -18:07:35.847 TargetRightAscension Write OK Target RightAscension is within 1 second of the value set: 01:37:24.00 -18:07:35.885 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:07:35.901 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:07:35.994 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -18:07:55.393 SlewToTarget OK Slewed OK. RA: 02:37:24.28 -18:07:55.408 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 -18:07:55.443 SlewToTarget OK The TargetRightAscension property 02:37:24.28 matches the expected RA OK. -18:07:55.478 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -18:07:55.518 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:07:55.570 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:07:55.628 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:07:55.670 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:08:17.404 SlewToTargetAsync OK Slewed OK. RA: 01:37:44.03 -18:08:17.418 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 -18:08:17.452 SlewToTargetAsync OK The TargetRightAscension property 01:37:44.03 matches the expected RA OK. -18:08:17.486 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -18:08:17.525 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:08:17.569 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:08:17.628 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:08:17.672 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:08:17.731 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -18:08:17.928 SlewToAltAz INFO Slewed to within 144:23:20.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -18:08:17.944 SlewToAltAz INFO Slewed to within 46:00:02.00 DD:MM:SS of expected Altitude: 50:00:00.00 -18:08:17.985 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:08:18.048 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:08:18.108 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:08:18.167 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:08:23.478 SlewToAltAzAsync INFO Slewed to within 149:24:45.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -18:08:23.492 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 -18:08:23.534 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:08:23.590 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:08:23.652 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:08:23.712 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:08:47.383 SyncToTarget OK Slewed to start position OK. RA: 02:38:12.20 -18:08:47.398 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -18:08:48.087 SyncToTarget INFO Synced to sync position within 3597.1 arc seconds of expected RA: 02:34:12.20, actual RA: 02:38:12.00 -18:08:48.101 SyncToTarget INFO Synced to sync position within 3599.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: -00:00:01.00 -18:09:07.348 SyncToTarget OK Slewed back to start position OK. RA: 02:38:12.20 -18:09:07.366 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:09:08.050 SyncToTarget INFO Synced to reversed sync position within 3602.9 arc seconds of expected RA: 02:42:12.20, actual RA: 02:38:12.00 -18:09:08.065 SyncToTarget INFO Synced to reversed sync position within 3598.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 00:00:02.00 -18:09:27.338 SyncToTarget OK Slewed back to start position OK. RA: 02:38:12.20 -18:09:27.353 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:09:27.396 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:09:27.438 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:09:27.498 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:09:27.542 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:09:27.695 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +18:07:59.997 CanMoveAxis:Primary OK CanMoveAxis:Primary True +18:08:00.035 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +18:08:00.072 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +18:08:00.108 Park/Unpark INFO Tests skipped +18:08:00.131 AbortSlew OK AbortSlew OK when not slewing +18:08:00.199 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:08:00.211 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:08:00.225 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:08:00.239 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:08:00.253 AxisRate:Primary OK No overlapping axis rates found +18:08:00.266 AxisRate:Primary OK No duplicate axis rates found +18:08:00.279 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +18:08:00.295 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +18:08:00.310 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +18:08:00.322 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +18:08:00.336 AxisRate:Primary OK Disposed axis rates OK +18:08:00.350 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +18:08:00.362 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +18:08:00.375 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +18:08:00.387 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +18:08:00.400 AxisRate:Secondary OK No overlapping axis rates found +18:08:00.414 AxisRate:Secondary OK No duplicate axis rates found +18:08:00.445 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +18:08:00.458 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +18:08:00.472 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +18:08:00.487 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +18:08:00.501 AxisRate:Secondary OK Disposed axis rates OK +18:08:00.517 AxisRate:Tertiary OK Empty axis rate returned +18:08:00.531 AxisRate:Tertiary OK Disposed axis rates OK +18:08:00.550 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +18:08:00.606 MoveAxis Primary OK Can successfully set a movement rate of zero +18:08:00.622 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:08:00.659 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +18:08:04.867 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +18:08:09.770 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +18:08:13.981 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:08:13.998 MoveAxis Primary OK AxisRates object successfully disposed +18:08:14.057 MoveAxis Secondary OK Can successfully set a movement rate of zero +18:08:14.072 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +18:08:14.107 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +18:08:18.317 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +18:08:23.262 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +18:08:27.473 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false +18:08:27.492 MoveAxis Secondary OK AxisRates object successfully disposed +18:08:27.551 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +18:08:29.592 PulseGuide OK Synchronous pulse guide found OK +18:08:54.449 SlewToCoordinates INFO Slewed within 39.2 arc seconds of expected RA: 04:18:14.61, actual RA: 04:18:12.00 +18:08:54.463 SlewToCoordinates INFO Slewed within 7199.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:59.00 +18:08:54.478 SlewToCoordinates OK The TargetRightAscension property 04:18:14.61 matches the expected RA OK. +18:08:54.492 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +18:08:54.548 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:08:55.301 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:08:55.360 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:08:56.199 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:09:20.477 SlewToCoordinatesAsync INFO Slewed within 19.3 arc seconds of expected RA: 03:18:41.28, actual RA: 03:18:40.00 +18:09:20.490 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 +18:09:20.503 SlewToCoordinatesAsync OK The TargetRightAscension property 03:18:41.28 matches the expected RA OK. +18:09:20.516 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +18:09:20.558 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:09:21.381 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:09:21.442 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:09:22.292 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:09:44.520 SyncToCoordinates INFO Slewed to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:09:44.534 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +18:09:47.045 SyncToCoordinates INFO Synced to sync position within 71.8 arc seconds of expected RA: 02:15:07.79, actual RA: 02:15:03.00 +18:09:47.058 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +18:09:47.071 SyncToCoordinates OK The TargetRightAscension property 02:15:07.79 matches the expected RA OK. +18:09:47.085 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. +18:10:08.444 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:10:08.458 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:10:10.791 SyncToCoordinates INFO Synced to reversed sync position within 71.8 arc seconds of expected RA: 02:23:07.79, actual RA: 02:23:03.00 +18:10:10.806 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +18:10:32.484 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 +18:10:32.498 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +18:10:32.537 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +18:10:33.329 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +18:10:33.389 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +18:10:34.242 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +18:10:34.301 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +18:10:34.315 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +18:10:34.979 TargetRightAscension Write OK Legal value 01:20:19.62 HH:MM:SS written successfully +18:10:35.016 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:10:35.032 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +18:10:35.652 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +18:10:56.417 SlewToTarget INFO Slewed within 14.8 arc seconds of expected RA: 02:20:20.99, actual RA: 02:20:20.00 +18:10:56.434 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 +18:10:56.449 SlewToTarget OK The TargetRightAscension property 02:20:20.99 matches the expected RA OK. +18:10:56.463 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +18:10:56.504 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:10:56.676 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:10:56.736 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:10:56.915 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:11:20.512 SlewToTargetAsync INFO Slewed within 35.1 arc seconds of expected RA: 01:20:42.34, actual RA: 01:20:40.00 +18:11:20.526 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 +18:11:20.539 SlewToTargetAsync OK The TargetRightAscension property 01:20:42.34 matches the expected RA OK. +18:11:20.553 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +18:11:20.593 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:11:20.774 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:11:20.833 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:11:21.032 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:11:21.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +18:11:22.864 SlewToAltAz INFO Slewed to within 144:49:47.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +18:11:22.880 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 +18:11:22.920 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:11:23.710 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:11:23.771 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:11:24.447 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:11:31.196 SlewToAltAzAsync INFO Slewed to within 149:51:53.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +18:11:31.210 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 +18:11:31.251 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +18:11:32.060 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +18:11:32.121 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +18:11:32.814 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +18:11:56.494 SyncToTarget INFO Slewed to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:11:56.509 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +18:11:59.005 SyncToTarget INFO Synced to sync position within 55.1 arc seconds of expected RA: 02:17:18.67, actual RA: 02:17:15.00 +18:11:59.019 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +18:12:22.398 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:12:22.416 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:12:24.739 SyncToTarget INFO Synced to reversed sync position within 55.1 arc seconds of expected RA: 02:25:18.67, actual RA: 02:25:15.00 +18:12:24.754 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +18:12:46.438 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 +18:12:46.452 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +18:12:46.491 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +18:12:46.643 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +18:12:46.702 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +18:12:46.884 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +18:12:47.702 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -18:09:27.762 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +18:12:47.769 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -18:09:27.856 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. +18:12:47.862 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. Conformance test complete -Your driver had 3 errors, 1 warning and 0 issue +No errors, warnings or issues found: your driver passes ASCOM validation!! + +Driver Hash Value: 0C55C8535B9B3A4048581454F9D6A263EFD16E20AEC783762006739F671F586B64F1D8DD3E1E613C27A5B24838AEB8656C2A19BD1EE69177ECF2619599C0DA3C +Report Hash Value: 671D83C15427DD14D9FA7F5A6C62D6B21372362C5173A2B95171D14D7442358DCF3950481797D63EB94E642D2563C3094C387C23D65466833FEA5E64CD045B46 + +The validation file is: C:\Users\colin\Documents\ASCOM\Logs 2019-05-08\ASCOM.MeadeAutostar497.Telescope.Validation.txt From 9b7a85060747aad9d9beca1e5c539d7975cf49e1 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 8 May 2019 18:26:39 +0100 Subject: [PATCH 033/109] Upgraded driver version to 0.1 --- MeadeAutostar497/AscomClasses/Telescope.cs | 8 ++--- .../Controller/FirmwareVersion.cs | 34 +++++++++++++++++++ .../Controller/ITelescopeController.cs | 1 + .../Controller/TelescopeController.cs | 7 ++++ MeadeAutostar497/MeadeAutostar497.csproj | 1 + MeadeAutostar497/Properties/AssemblyInfo.cs | 4 +-- 6 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 MeadeAutostar497/Controller/FirmwareVersion.cs diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index 9892ea6..d17efa0 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -956,15 +956,15 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("Absolute Get", true.ToString()); - return true; // This is an absolute focuser + tl.LogMessage("Absolute Get", false.ToString()); + return false; // This is an absolute focuser } } public void Halt() { - tl.LogMessage("Halt", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("Halt"); + tl.LogMessage("Halt", "Halting"); + _telescopeController.FocuserHalt(); } public bool IsMoving diff --git a/MeadeAutostar497/Controller/FirmwareVersion.cs b/MeadeAutostar497/Controller/FirmwareVersion.cs new file mode 100644 index 0000000..bdd0976 --- /dev/null +++ b/MeadeAutostar497/Controller/FirmwareVersion.cs @@ -0,0 +1,34 @@ +namespace ASCOM.MeadeAutostar497.Controller +{ + enum FirmwareVersion + { + autostar497_30eb, + autostar497_30ed, + autostar497_30ee, + autostar497_31ee, + autostar497_32ea, + //PEC added for Polar mounted scopes + + autostar497_32ee, + autostar497_32eh, + //Some serial strings fixed. + + autostar497_32ei, + autostar497_33ef, + //Some serial strings fixed. + + autostar497_33el, + autostar497_40eb, + autostar497_40ee, + autostar497_40ef, + autostar497_41ec, + autostar497_42ed, + //Get serial command for daylight savings (:GH# returns 0 for disabled 1 for enabled) + //Set serial command for daylight savings (:SH0# disables, :SH1# enables) + + autostar497_43ea, + autostar497_43ed, + autostar497_43eg + //Added :GW#, :AL#, :AA#, & :AP# + } +} \ No newline at end of file diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index 06698ea..bcc7b23 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -32,5 +32,6 @@ namespace ASCOM.MeadeAutostar497.Controller void SlewToTarget(); void SlewToTargetAsync(); void MoveAxis(TelescopeAxes axis, double rate); + void FocuserHalt(); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index db3916d..ffa83a9 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -800,6 +800,13 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public void FocuserHalt() + { + SerialPort.Command(":FQ#"); + //:FQ# Halt Focuser Motion + //Returns: Nothing + } + //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 6de6351..5109500 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -89,6 +89,7 @@ + diff --git a/MeadeAutostar497/Properties/AssemblyInfo.cs b/MeadeAutostar497/Properties/AssemblyInfo.cs index 2a06abf..a4133d1 100644 --- a/MeadeAutostar497/Properties/AssemblyInfo.cs +++ b/MeadeAutostar497/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.0.0.0")] -[assembly: AssemblyFileVersion("0.0.0.0")] +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] From 0c1d7d7f091266de13e521948aea3e549ef6ca78 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 9 May 2019 18:00:17 +0100 Subject: [PATCH 034/109] Added explicit locks around all sequences of commands. --- .../Controller/TelescopeController.cs | 317 ++++++++++-------- 1 file changed, 180 insertions(+), 137 deletions(-) diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index ffa83a9..ca72cc1 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -562,14 +562,22 @@ namespace ASCOM.MeadeAutostar497.Controller } else { - _serialPort.Command(":RG#"); //Make sure we are at guide rate - _serialPort.Command($":M{d}#"); - Thread.Sleep(duration); - _serialPort.Command($":Q{d}#"); + SerialPort.Lock(); + try + { + _serialPort.Command(":RG#"); //Make sure we are at guide rate + _serialPort.Command($":M{d}#"); + Thread.Sleep(duration); + _serialPort.Command($":Q{d}#"); - //classic only !!!, this is needed since once in a while one is not enough - Thread.Sleep(200); - _serialPort.Command($":Q{d}#"); + //classic only !!!, this is needed since once in a while one is not enough + Thread.Sleep(200); + _serialPort.Command($":Q{d}#"); + } + finally + { + SerialPort.Unlock(); + } } } @@ -594,10 +602,18 @@ namespace ASCOM.MeadeAutostar497.Controller public void SlewToCoordinatesAsync(double rightAscension, double declination) { - TargetRightAscension = rightAscension; - TargetDeclination = declination; + SerialPort.Lock(); + try + { + TargetRightAscension = rightAscension; + TargetDeclination = declination; - DoSlewAsync(true); + DoSlewAsync(true); + } + finally + { + SerialPort.Unlock(); + } } public void SlewToAltAz(double azimuth, double altitude) @@ -663,10 +679,18 @@ namespace ASCOM.MeadeAutostar497.Controller public void SlewToAltAzAsync(double azimuth, double altitude) { - TargetAltitude = altitude; - TargetAzimuth = azimuth; + SerialPort.Lock(); + try + { + TargetAltitude = altitude; + TargetAzimuth = azimuth; - DoSlewAsync(false); + DoSlewAsync(false); + } + finally + { + SerialPort.Unlock(); + } } public void SyncToTarget() @@ -708,95 +732,104 @@ namespace ASCOM.MeadeAutostar497.Controller private bool _movingSecondary; public void MoveAxis(TelescopeAxes axis, double rate) { - var absrate = Math.Abs(rate); - - switch(absrate) + SerialPort.Lock(); + try { - case 0: - //do nothing, it's ok this time as we're halting the slew. - break; - case 1: - SerialPort.Command(":RG#"); - //:RG# Set Slew rate to Guiding Rate (slowest) - //Returns: Nothing - break; - case 2: - SerialPort.Command(":RC#"); - //:RC# Set Slew rate to Centering rate (2nd slowest) - //Returns: Nothing - break; - case 3: - SerialPort.Command(":RM#"); - //:RM# Set Slew rate to Find Rate (2nd Fastest) - //Returns: Nothing - break; - case 4: - SerialPort.Command(":RS#"); - //:RS# Set Slew rate to max (fastest) - //Returns: Nothing - break; - default: - throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); - + var absrate = Math.Abs(rate); + + switch (absrate) + { + case 0: + //do nothing, it's ok this time as we're halting the slew. + break; + case 1: + SerialPort.Command(":RG#"); + //:RG# Set Slew rate to Guiding Rate (slowest) + //Returns: Nothing + break; + case 2: + SerialPort.Command(":RC#"); + //:RC# Set Slew rate to Centering rate (2nd slowest) + //Returns: Nothing + break; + case 3: + SerialPort.Command(":RM#"); + //:RM# Set Slew rate to Find Rate (2nd Fastest) + //Returns: Nothing + break; + case 4: + SerialPort.Command(":RS#"); + //:RS# Set Slew rate to max (fastest) + //Returns: Nothing + break; + default: + throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); + + } + + switch (axis) + { + case TelescopeAxes.axisPrimary: + if (rate == 0) + { + _movingPrimary = false; + SerialPort.Command(":Qe#"); + //:Qe# Halt eastward Slews + //Returns: Nothing + SerialPort.Command(":Qw#"); + //:Qw# Halt westward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SerialPort.Command(":Me#"); + //:Me# Move Telescope East at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + else + { + SerialPort.Command(":Mw#"); + //:Mw# Move Telescope West at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + + break; + case TelescopeAxes.axisSecondary: + if (rate == 0) + { + _movingSecondary = false; + SerialPort.Command(":Qn#"); + //:Qn# Halt northward Slews + //Returns: Nothing + SerialPort.Command(":Qs#"); + //:Qs# Halt southward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SerialPort.Command(":Mn#"); + //:Mn# Move Telescope North at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + else + { + SerialPort.Command(":Ms#"); + //:Ms# Move Telescope South at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + + break; + default: + throw new ASCOM.MethodNotImplementedException("Can not move this axis."); + } } - - switch (axis) + finally { - case TelescopeAxes.axisPrimary: - if (rate == 0) - { - _movingPrimary = false; - SerialPort.Command(":Qe#"); - //:Qe# Halt eastward Slews - //Returns: Nothing - SerialPort.Command(":Qw#"); - //:Qw# Halt westward Slews - //Returns: Nothing - } - else if (rate > 0) - { - SerialPort.Command(":Me#"); - //:Me# Move Telescope East at current slew rate - //Returns: Nothing - _movingPrimary = true; - } - else - { - SerialPort.Command(":Mw#"); - //:Mw# Move Telescope West at current slew rate - //Returns: Nothing - _movingPrimary = true; - } - break; - case TelescopeAxes.axisSecondary: - if (rate == 0) - { - _movingSecondary = false; - SerialPort.Command(":Qn#"); - //:Qn# Halt northward Slews - //Returns: Nothing - SerialPort.Command(":Qs#"); - //:Qs# Halt southward Slews - //Returns: Nothing - } - else if (rate > 0) - { - SerialPort.Command(":Mn#"); - //:Mn# Move Telescope North at current slew rate - //Returns: Nothing - _movingSecondary = true; - } - else - { - SerialPort.Command(":Ms#"); - //:Ms# Move Telescope South at current slew rate - //Returns: Nothing - _movingSecondary = true; - } - - break; - default: - throw new ASCOM.MethodNotImplementedException("Can not move this axis."); + SerialPort.Unlock(); } } @@ -810,48 +843,58 @@ namespace ASCOM.MeadeAutostar497.Controller //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { - switch (polar) + SerialPort.Lock(); + try { - case true: - var response = SerialPort.CommandChar(":MS#"); - //:MS# Slew to Target Object - //Returns: - //0 Slew is Possible - //1# Object Below Horizon w/string message - //2# Object Below Higher w/string message + switch (polar) + { + case true: + var response = SerialPort.CommandChar(":MS#"); + //:MS# Slew to Target Object + //Returns: + //0 Slew is Possible + //1# Object Below Horizon w/string message + //2# Object Below Higher w/string message - switch (response) - { - case '0': - //We're slewing everything should be working just fine. - break; - case '1': - //Below Horizon - string belowHorizonMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowHorizonMessage); - case '2': - //Below Horizon - string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); - default: - throw new ASCOM.DriverException("This error should not happen"); + switch (response) + { + case '0': + //We're slewing everything should be working just fine. + break; + case '1': + //Below Horizon + string belowHorizonMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowHorizonMessage); + case '2': + //Below Horizon + string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); + throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); + default: + throw new ASCOM.DriverException("This error should not happen"); - } - break; - case false: - var maResponse = SerialPort.CommandChar(":MA#"); - //:MA# Autostar, LX 16â€, Autostar II – Slew to target Alt and Az - //Returns: - //0 - No fault - //1 – Fault - // LX200 – Not supported + } - if (maResponse == '1') - { - throw new ASCOM.InvalidOperationException("fault"); - } - break; - } + break; + case false: + var maResponse = SerialPort.CommandChar(":MA#"); + //:MA# Autostar, LX 16â€, Autostar II – Slew to target Alt and Az + //Returns: + //0 - No fault + //1 – Fault + // LX200 – Not supported + + if (maResponse == '1') + { + throw new ASCOM.InvalidOperationException("fault"); + } + + break; + } + } + finally + { + SerialPort.Unlock(); + } } public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting From 3dc5efee9abc16733d31354fd39dd5faa4c38553 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 14 May 2019 00:20:49 +0100 Subject: [PATCH 035/109] Basic implementation of the IFocusserV3 --- MeadeAutostar497/AscomClasses/Telescope.cs | 20 +++-- .../Controller/ITelescopeController.cs | 3 + .../Controller/TelescopeController.cs | 74 +++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index d17efa0..b9acd64 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -949,8 +949,8 @@ namespace ASCOM.MeadeAutostar497 #region IFocuser Implementation - private int focuserPosition = 0; // Class level variable to hold the current focuser position - private const int focuserSteps = 10000; + //private int focuserPosition = 0; // Class level variable to hold the current focuser position + //private const int focuserSteps = 10000; public bool Absolute { @@ -994,8 +994,9 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("MaxIncrement Get", focuserSteps.ToString()); - return focuserSteps; // Maximum change in one move + var maxIncrement = _telescopeController.FocuserMaxIncrement; + tl.LogMessage("MaxIncrement Get", maxIncrement.ToString()); + return maxIncrement; // Maximum change in one move } } @@ -1003,22 +1004,25 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("MaxStep Get", focuserSteps.ToString()); - return focuserSteps; // Maximum extent of the focuser, so position range is 0 to 10,000 + var maxStep = _telescopeController.FocuserMaxStep; + tl.LogMessage("MaxStep Get", maxStep.ToString()); + return maxStep; } } public void Move(int Position) { tl.LogMessage("Move", Position.ToString()); - focuserPosition = Position; // Set the focuser position + _telescopeController.FocuserMove(Position); + //focuserPosition = Position; // Set the focuser position } public int Position { get { - return focuserPosition; // Return the focuser position + throw new ASCOM.PropertyNotImplementedException("Position", false); + //return focuserPosition; // Return the focuser position } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index bcc7b23..a31d9d9 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -21,6 +21,8 @@ namespace ASCOM.MeadeAutostar497.Controller double TargetRightAscension { get; set; } double TargetDeclination { get; set; } DriveRates TrackingRate { get; } + int FocuserMaxIncrement { get; set; } + int FocuserMaxStep { get; set; } void AbortSlew(); void PulseGuide(GuideDirections direction, int duration); void Park(); @@ -33,5 +35,6 @@ namespace ASCOM.MeadeAutostar497.Controller void SlewToTargetAsync(); void MoveAxis(TelescopeAxes axis, double rate); void FocuserHalt(); + void FocuserMove(int position); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index ca72cc1..209dd09 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -97,6 +97,7 @@ namespace ASCOM.MeadeAutostar497.Controller SerialPort.Open(); TestConnectionActive(); + SetFocuserSpeedFastest(); } catch (Exception) { @@ -520,6 +521,10 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public int FocuserMaxIncrement { get; set; } = 7000; + + public int FocuserMaxStep { get; set; } = 7000; + public double Altitude { get { @@ -730,6 +735,7 @@ namespace ASCOM.MeadeAutostar497.Controller private bool _movingPrimary; private bool _movingSecondary; + public void MoveAxis(TelescopeAxes axis, double rate) { SerialPort.Lock(); @@ -840,6 +846,74 @@ namespace ASCOM.MeadeAutostar497.Controller //Returns: Nothing } + public void FocuserMove(int newPosition) + { + //todo implement backlash compensation + //todo implement direction reverse + //todo implement dynamic braking + + if (newPosition < -FocuserMaxIncrement || newPosition > FocuserMaxIncrement) + { + throw new ASCOM.InvalidValueException($"position out of range {-FocuserMaxIncrement} < {newPosition} < {FocuserMaxIncrement}"); + } + + if (newPosition == 0) + return; + + if (newPosition > 0) + { + //desired move direction is out + MoveFocuser(true, Math.Abs(newPosition)); + } + else + { + //desired move direction is in + MoveFocuser(false, Math.Abs(newPosition)); + } + } + + private void MoveFocuser(bool directionOut, int steps) + { + SerialPort.Command(directionOut ? ":F+#" : ":F-#"); + //:F+# Start Focuser moving inward (toward objective) + //Returns: None + + //:F-# Start Focuser moving outward (away from objective) + //Returns: None + + Util.WaitForMilliseconds(steps); + + FocuserHalt(); + } + + private void SetFocuserSpeedFastest() + { + SerialPort.Command(":FF#"); + //:FF# Set Focus speed to fastest setting + //Returns: Nothing + } + + private void SetFocuserSpeedSlowest() + { + SerialPort.Command(":FS#"); + //:FS# Set Focus speed to slowest setting + //Returns: Nothing + } + + private void SetFocuserSpeed( int speed) + { + if (speed < 1) + throw new ArgumentOutOfRangeException("speed is too low"); + + if (speed > 4) + throw new ArgumentOutOfRangeException("speed is too high"); + + SerialPort.Command($":F{speed}#"); + //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 + //Returns: Nothing + //All others – Not Supported + } + //todo remove the polar parameter and split method into two. private void DoSlewAsync( bool polar) { From 404366d5523eaf8adae8f88929a8a23dd20e7332 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 14 May 2019 00:23:17 +0100 Subject: [PATCH 036/109] Focuser passes validation, this makes the code V0.2 --- ASCOM.MeadeAutostar497.Focuser.Validation.txt | 68 +++++++++++++++++++ MeadeAutostar497/Properties/AssemblyInfo.cs | 4 +- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 ASCOM.MeadeAutostar497.Focuser.Validation.txt diff --git a/ASCOM.MeadeAutostar497.Focuser.Validation.txt b/ASCOM.MeadeAutostar497.Focuser.Validation.txt new file mode 100644 index 0000000..8dedf49 --- /dev/null +++ b/ASCOM.MeadeAutostar497.Focuser.Validation.txt @@ -0,0 +1,68 @@ +Conform Report Hash (V1): 55AB333E4394ADF3F35929567EAB46A092F3574DF38E1F00BF586967B7EE826AA2D92647409F699E62954B07AF3389CEA7DB7FAAFFE04E05BE358A744E95A624 + + +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040404 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +00:21:34.375 Driver Access Checks OK +00:21:35.008 AccessChecks OK Successfully created driver using late binding +00:21:35.253 AccessChecks OK Successfully connected using late binding +00:21:35.257 AccessChecks INFO The driver is a .NET object +00:21:35.260 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= +00:21:35.265 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +00:21:35.269 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +00:21:35.992 AccessChecks INFO Device does not expose IFocuser interface +00:21:36.147 AccessChecks INFO Device does not expose IFocuserV2 interface +00:21:36.479 AccessChecks INFO Device exposes IFocuserV3 interface +00:21:36.692 AccessChecks OK Successfully created driver using driver access toolkit +00:21:36.895 AccessChecks OK Successfully connected using driver access toolkit +00:21:36.958 AccessChecks OK Successfully disconnected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Focuser to get a Focuser object +00:21:37.078 ConformanceCheck OK Driver instance created successfully +00:21:37.311 ConformanceCheck OK Connected OK + +Common Driver Methods +00:21:37.348 InterfaceVersion OK 3 +00:21:37.374 Connected OK True +00:21:37.401 Description OK Meade Autostar 497 .net +00:21:37.428 DriverInfo OK Information about the driver itself. Version: 0.2 +00:21:37.457 DriverVersion OK 0.2 +00:21:37.485 Name OK Meade Autostar 497 .net +00:21:37.511 CommandXXX INFO Tests skipped +00:21:37.515 Action INFO Conform cannot test the Action method +00:21:37.521 SupportedActions OK Driver returned an empty action list + +Properties +00:21:37.626 Absolute OK False +00:21:37.631 IsMoving OK False +00:21:37.637 MaxStep OK 7000 +00:21:37.642 MaxIncrement OK 7000 +00:21:37.820 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected +00:21:37.988 StepSize OK Optional member threw a PropertyNotImplementedException exception. +00:21:37.993 TempCompAvailable OK False +00:21:37.999 TempComp Read OK False +00:21:38.167 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected +00:21:38.504 Temperature OK Optional member threw a PropertyNotImplementedException exception. + +Methods +00:21:38.544 Halt OK Focuser halted OK +00:21:38.552 Move - TempComp False Moving by: 700 +00:21:39.264 Move - TempComp False Asynchronous move found +00:21:39.270 Move - TempComp False OK Relative move OK +00:21:39.278 Move - TempComp False INFO Returning to original position: 0 + +Conformance test complete + +No errors, warnings or issues found: your driver passes ASCOM validation!! + +Driver Hash Value: DBF36156F87DA91F130E0AABEFE80B250D62C2DB689AD8B44243AE0D9322245CF15AAE2E663962402E87B6B1A15440A6DDB46562EFB9527E3596096319C2AC85 diff --git a/MeadeAutostar497/Properties/AssemblyInfo.cs b/MeadeAutostar497/Properties/AssemblyInfo.cs index a4133d1..495f3d8 100644 --- a/MeadeAutostar497/Properties/AssemblyInfo.cs +++ b/MeadeAutostar497/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.1.0.0")] -[assembly: AssemblyFileVersion("0.1.0.0")] +[assembly: AssemblyVersion("0.2.0.0")] +[assembly: AssemblyFileVersion("0.2.0.0")] From b795634d707016b048f881a8bac0ebbbe95e5663 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 15 May 2019 00:52:40 +0100 Subject: [PATCH 037/109] Added support for CommandBlind and CommandString Modified the tracking rates to be setable. However, the get is now simulated. --- .../MeadeAutostar497.UnitTests.csproj | 2 +- MeadeAutostar497/AscomClasses/Telescope.cs | 29 +++++++++----- .../Controller/ITelescopeController.cs | 4 +- .../Controller/TelescopeController.cs | 40 +++++++++++++------ MeadeAutostar497/MeadeAutostar497.csproj | 2 +- TestConsole/TestConsole.csproj | 2 +- 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj index a7a4fae..47bf469 100644 --- a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj +++ b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj @@ -26,7 +26,7 @@ prompt 4 false - x64 + AnyCPU pdbonly diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs index b9acd64..5f3c794 100644 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ b/MeadeAutostar497/AscomClasses/Telescope.cs @@ -163,16 +163,20 @@ namespace ASCOM.MeadeAutostar497 public void CommandBlind(string command, bool raw) { + tl.LogMessage("CommandBlind", $"command={command} raw={raw}"); + CheckConnected("CommandBlind"); // Call CommandString and return as soon as it finishes //this.CommandString(command, raw); + _telescopeController.CommandBlind(command, raw); // or - throw new ASCOM.MethodNotImplementedException("CommandBlind"); + //throw new ASCOM.MethodNotImplementedException("CommandBlind"); // DO NOT have both these sections! One or the other } public bool CommandBool(string command, bool raw) { + tl.LogMessage("CommandBool", $"command={command} raw={raw}"); CheckConnected("CommandBool"); string ret = CommandString(command, raw); // TODO decode the return string and return true or false @@ -183,11 +187,13 @@ namespace ASCOM.MeadeAutostar497 public string CommandString(string command, bool raw) { + tl.LogMessage("CommandString", $"command={command} raw={raw}"); // it's a good idea to put all the low level communication with the device here, // then all communication calls this function // you need something to ensure that only one command is in progress at a time CheckConnected("CommandString"); - throw new ASCOM.MethodNotImplementedException("CommandString"); + //throw new ASCOM.MethodNotImplementedException("CommandString"); + return _telescopeController.CommandString(command, raw); } public void Dispose() @@ -455,8 +461,8 @@ namespace ASCOM.MeadeAutostar497 { get { - tl.LogMessage("CanSetTracking", "Get - " + false.ToString()); - return false; + tl.LogMessage("CanSetTracking", "Get - " + true.ToString()); + return true; } } @@ -876,19 +882,20 @@ namespace ASCOM.MeadeAutostar497 } } + private bool _tracking = true; public bool Tracking { get { //todo implementing this, it exists. - bool tracking = true; - tl.LogMessage("Tracking", "Get - " + tracking.ToString()); - return tracking; + + tl.LogMessage("Tracking", $"Get - {_tracking}" ); + return _tracking; } set { - tl.LogMessage("Tracking Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Tracking", true); + tl.LogMessage($"Tracking Set", $"{value}"); + _tracking = value; } } @@ -902,8 +909,8 @@ namespace ASCOM.MeadeAutostar497 } set { - tl.LogMessage("TrackingRate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TrackingRate", true); + tl.LogMessage("TrackingRate Set", $"{value}"); + _telescopeController.TrackingRate = value; } } diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs index a31d9d9..9873c48 100644 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ b/MeadeAutostar497/Controller/ITelescopeController.cs @@ -20,7 +20,7 @@ namespace ASCOM.MeadeAutostar497.Controller double Declination { get; } double TargetRightAscension { get; set; } double TargetDeclination { get; set; } - DriveRates TrackingRate { get; } + DriveRates TrackingRate { get; set; } int FocuserMaxIncrement { get; set; } int FocuserMaxStep { get; set; } void AbortSlew(); @@ -36,5 +36,7 @@ namespace ASCOM.MeadeAutostar497.Controller void MoveAxis(TelescopeAxes axis, double rate); void FocuserHalt(); void FocuserMove(int position); + string CommandString(string command, bool raw); + void CommandBlind(string command, bool raw); } } \ No newline at end of file diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs index 209dd09..e314982 100644 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ b/MeadeAutostar497/Controller/TelescopeController.cs @@ -478,21 +478,23 @@ namespace ASCOM.MeadeAutostar497.Controller } } + private DriveRates _trackingRate = DriveRates.driveSidereal; public DriveRates TrackingRate { get { - var result = SerialPort.CommandTerminated(":GT#", "#"); + //var result = SerialPort.CommandTerminated(":GT#", "#"); - double rate = double.Parse(result); + //double rate = double.Parse(result); - if (rate == 60.1) - return DriveRates.driveLunar; - else if (rate == 60.1) - return DriveRates.driveSidereal; + //if (rate == 60.1) + // return DriveRates.driveLunar; + //else if (rate == 60.1) + // return DriveRates.driveSidereal; - return DriveRates.driveKing; + //return DriveRates.driveKing; + return _trackingRate; } set { @@ -508,16 +510,20 @@ namespace ASCOM.MeadeAutostar497.Controller //:TL# Set Lunar Tracking Rage //Returns: Nothing break; - case DriveRates.driveSolar: - SerialPort.Command(":TS#"); - //:TS# Select Solar tracking rate. [LS Only] - //Returns: Nothing - break; + //case DriveRates.driveSolar: + // SerialPort.Command(":TS#"); + // //:TS# Select Solar tracking rate. [LS Only] + // //Returns: Nothing + // break; case DriveRates.driveKing: + //:TM# Select custom tracking rate [ no-op in Autostar II] + //Returns: Nothing break; default: throw new ArgumentOutOfRangeException(nameof(value), value, null); } + + _trackingRate = value; } } @@ -872,6 +878,16 @@ namespace ASCOM.MeadeAutostar497.Controller } } + public string CommandString(string command, bool raw) + { + return SerialPort.CommandTerminated(command, "#"); + } + + public void CommandBlind(string command, bool raw) + { + SerialPort.Command(command); + } + private void MoveFocuser(bool directionOut, int steps) { SerialPort.Command(directionOut ? ":F+#" : ":F-#"); diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/MeadeAutostar497/MeadeAutostar497.csproj index 5109500..fe89ffa 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/MeadeAutostar497/MeadeAutostar497.csproj @@ -46,7 +46,7 @@ prompt 4 true - x64 + AnyCPU false diff --git a/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj index 4392996..34ad58e 100644 --- a/TestConsole/TestConsole.csproj +++ b/TestConsole/TestConsole.csproj @@ -16,7 +16,7 @@ 512 - x64 + AnyCPU true full false From 79a77d4e1dd7850350877eff4690f80f2e8373e0 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Fri, 17 May 2019 14:21:26 +0000 Subject: [PATCH 038/109] Merged in feature/LocalServer (pull request #5) Feature/LocalServer * Major refactor. Switching over to a local server hub style driver allowing multiple programs to control the telescope at one time without the need for the POTH Hub * Unified the setup dialog * Implemented shared serial port, Both Telescope and Driver can connect at the same time. * Ported the focuser implementation from the non server based version. * Ported the telescope driver code. * Fixed problem with # not being stripped from the returned string ends. Fixed issue with RA being returned as degress rather than hours. * Telescope passes validation * Added a lock around the focuser move. * Reimplemented CommandBlind and CommandString * Corrected version information * Removed the Altitude support as there's a bug in the Autostar and Audiostar firmware --- ASCOM.MeadeAutostar497.Focuser.Validation.txt | 68 - ....MeadeAutostar497.Telescope.Validation.txt | 268 --- ASCOM.MeadeGeneric.Telescope.Validation.txt | 269 +++ ASCOM.MeadeGeneric.focuser.Validation.txt | 69 + ConformanceResult.txt | 272 --- FocuserTestConsole/FocuserTestConsole.csproj | 64 + FocuserTestConsole/Program.cs | 55 + .../Properties/AssemblyInfo.cs | 26 +- .../app.config | 2 +- .../ASCOM.ico | Bin .../ASCOM.png | Bin .../ASCOMDriverTemplate.snk | Bin .../Meade.net.Telescope.csproj | 45 +- .../Properties/AssemblyInfo.cs | 14 +- .../Properties/Resources.Designer.cs | 4 +- .../Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 2 +- .../Properties/Settings.settings | 0 .../Rates.cs | 18 +- .../ReadMe.htm | 0 .../Resources/ASCOM.bmp | Bin .../StringExtensions.cs | 10 +- Meade.net.Telescope/Telescope.cs | 1672 +++++++++++++++++ .../app.config | 2 +- Meade.net.focuser/ASCOM.ico | Bin 0 -> 125783 bytes Meade.net.focuser/ASCOM.png | Bin 0 -> 1922 bytes Meade.net.focuser/ASCOMDriverTemplate.snk | Bin 0 -> 596 bytes Meade.net.focuser/Focuser.cs | 570 ++++++ Meade.net.focuser/Meade.net.focuser.csproj | 151 ++ Meade.net.focuser/Properties/AssemblyInfo.cs | 39 + .../Properties/Resources.Designer.cs | 83 + Meade.net.focuser/Properties/Resources.resx | 127 ++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 5 + Meade.net.focuser/ReadMe.htm | 147 ++ Meade.net.focuser/Resources/ASCOM.bmp | Bin 0 -> 3382 bytes Meade.net.focuser/app.config | 8 + Meade.net.sln | 73 + Meade.net/ASCOM.ico | Bin 0 -> 125783 bytes Meade.net/ASCOM.png | Bin 0 -> 1922 bytes Meade.net/ClassFactory.cs | 244 +++ Meade.net/GarbageCollection.cs | 57 + Meade.net/LocalServer.cs | 642 +++++++ Meade.net/LocalServer.snk | Bin 0 -> 596 bytes Meade.net/Meade.net.csproj | 153 ++ Meade.net/Properties/AssemblyInfo.cs | 27 + Meade.net/Properties/Resources.Designer.cs | 73 + Meade.net/Properties/Resources.resx | 124 ++ Meade.net/ReadMe.htm | 666 +++++++ Meade.net/ReferenceCountedObject.cs | 24 + Meade.net/Resources/ASCOM.bmp | Bin 0 -> 3382 bytes .../SetupDialogForm.cs | 35 +- .../SetupDialogForm.designer.cs | 7 +- .../SetupDialogForm.resx | 0 Meade.net/SharedResources.cs | 382 ++++ Meade.net/app.config | 3 + Meade.net/frmMain.Designer.cs | 63 + Meade.net/frmMain.cs | 20 + Meade.net/frmMain.resx | 120 ++ .../BootstrapAscomProfileStore.ps1 | 36 - .../MeadeAutostar497.UnitTests.csproj | 126 -- .../TelescopeControllerUnitTests.cs | 556 ------ MeadeAutostar497.UnitTests/packages.config | 9 - MeadeAutostar497.sln | 49 - MeadeAutostar497/AscomClasses/Telescope.cs | 1226 ------------ .../Controller/FirmwareVersion.cs | 34 - .../Controller/ISerialProcessor.cs | 28 - .../Controller/ITelescopeController.cs | 42 - .../Controller/SerialProcessor.cs | 142 -- .../Controller/TelescopeController.cs | 992 ---------- TargetToBeat.txt | 249 --- .../Program.cs | 30 +- .../Properties/AssemblyInfo.cs | 4 +- .../TelescopeTestConsole.csproj | 8 +- TelescopeTestConsole/app.config | 3 + 75 files changed, 6043 insertions(+), 4220 deletions(-) delete mode 100644 ASCOM.MeadeAutostar497.Focuser.Validation.txt delete mode 100644 ASCOM.MeadeAutostar497.Telescope.Validation.txt create mode 100644 ASCOM.MeadeGeneric.Telescope.Validation.txt create mode 100644 ASCOM.MeadeGeneric.focuser.Validation.txt delete mode 100644 ConformanceResult.txt create mode 100644 FocuserTestConsole/FocuserTestConsole.csproj create mode 100644 FocuserTestConsole/Program.cs rename {MeadeAutostar497.UnitTests => FocuserTestConsole}/Properties/AssemblyInfo.cs (68%) rename {TestConsole => FocuserTestConsole}/app.config (71%) rename {MeadeAutostar497 => Meade.net.Telescope}/ASCOM.ico (100%) rename {MeadeAutostar497 => Meade.net.Telescope}/ASCOM.png (100%) rename {MeadeAutostar497 => Meade.net.Telescope}/ASCOMDriverTemplate.snk (100%) rename MeadeAutostar497/MeadeAutostar497.csproj => Meade.net.Telescope/Meade.net.Telescope.csproj (81%) rename {MeadeAutostar497 => Meade.net.Telescope}/Properties/AssemblyInfo.cs (75%) rename {MeadeAutostar497 => Meade.net.Telescope}/Properties/Resources.Designer.cs (95%) rename {MeadeAutostar497 => Meade.net.Telescope}/Properties/Resources.resx (100%) rename {MeadeAutostar497 => Meade.net.Telescope}/Properties/Settings.Designer.cs (95%) rename {MeadeAutostar497 => Meade.net.Telescope}/Properties/Settings.settings (100%) rename {MeadeAutostar497/AscomClasses => Meade.net.Telescope}/Rates.cs (93%) rename {MeadeAutostar497 => Meade.net.Telescope}/ReadMe.htm (100%) rename {MeadeAutostar497 => Meade.net.Telescope}/Resources/ASCOM.bmp (100%) rename {MeadeAutostar497 => Meade.net.Telescope}/StringExtensions.cs (51%) create mode 100644 Meade.net.Telescope/Telescope.cs rename {MeadeAutostar497 => Meade.net.Telescope}/app.config (93%) create mode 100644 Meade.net.focuser/ASCOM.ico create mode 100644 Meade.net.focuser/ASCOM.png create mode 100644 Meade.net.focuser/ASCOMDriverTemplate.snk create mode 100644 Meade.net.focuser/Focuser.cs create mode 100644 Meade.net.focuser/Meade.net.focuser.csproj create mode 100644 Meade.net.focuser/Properties/AssemblyInfo.cs create mode 100644 Meade.net.focuser/Properties/Resources.Designer.cs create mode 100644 Meade.net.focuser/Properties/Resources.resx create mode 100644 Meade.net.focuser/Properties/Settings.Designer.cs create mode 100644 Meade.net.focuser/Properties/Settings.settings create mode 100644 Meade.net.focuser/ReadMe.htm create mode 100644 Meade.net.focuser/Resources/ASCOM.bmp create mode 100644 Meade.net.focuser/app.config create mode 100644 Meade.net.sln create mode 100644 Meade.net/ASCOM.ico create mode 100644 Meade.net/ASCOM.png create mode 100644 Meade.net/ClassFactory.cs create mode 100644 Meade.net/GarbageCollection.cs create mode 100644 Meade.net/LocalServer.cs create mode 100644 Meade.net/LocalServer.snk create mode 100644 Meade.net/Meade.net.csproj create mode 100644 Meade.net/Properties/AssemblyInfo.cs create mode 100644 Meade.net/Properties/Resources.Designer.cs create mode 100644 Meade.net/Properties/Resources.resx create mode 100644 Meade.net/ReadMe.htm create mode 100644 Meade.net/ReferenceCountedObject.cs create mode 100644 Meade.net/Resources/ASCOM.bmp rename {MeadeAutostar497/AscomClasses => Meade.net}/SetupDialogForm.cs (66%) rename {MeadeAutostar497/AscomClasses => Meade.net}/SetupDialogForm.designer.cs (96%) rename {MeadeAutostar497/AscomClasses => Meade.net}/SetupDialogForm.resx (100%) create mode 100644 Meade.net/SharedResources.cs create mode 100644 Meade.net/app.config create mode 100644 Meade.net/frmMain.Designer.cs create mode 100644 Meade.net/frmMain.cs create mode 100644 Meade.net/frmMain.resx delete mode 100644 MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 delete mode 100644 MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj delete mode 100644 MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs delete mode 100644 MeadeAutostar497.UnitTests/packages.config delete mode 100644 MeadeAutostar497.sln delete mode 100644 MeadeAutostar497/AscomClasses/Telescope.cs delete mode 100644 MeadeAutostar497/Controller/FirmwareVersion.cs delete mode 100644 MeadeAutostar497/Controller/ISerialProcessor.cs delete mode 100644 MeadeAutostar497/Controller/ITelescopeController.cs delete mode 100644 MeadeAutostar497/Controller/SerialProcessor.cs delete mode 100644 MeadeAutostar497/Controller/TelescopeController.cs delete mode 100644 TargetToBeat.txt rename {TestConsole => TelescopeTestConsole}/Program.cs (71%) rename {TestConsole => TelescopeTestConsole}/Properties/AssemblyInfo.cs (93%) rename TestConsole/TestConsole.csproj => TelescopeTestConsole/TelescopeTestConsole.csproj (92%) create mode 100644 TelescopeTestConsole/app.config diff --git a/ASCOM.MeadeAutostar497.Focuser.Validation.txt b/ASCOM.MeadeAutostar497.Focuser.Validation.txt deleted file mode 100644 index 8dedf49..0000000 --- a/ASCOM.MeadeAutostar497.Focuser.Validation.txt +++ /dev/null @@ -1,68 +0,0 @@ -Conform Report Hash (V1): 55AB333E4394ADF3F35929567EAB46A092F3574DF38E1F00BF586967B7EE826AA2D92647409F699E62954B07AF3389CEA7DB7FAAFFE04E05BE358A744E95A624 - - -ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 -ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 - -ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope - -Error handling -Error number for "Not Implemented" is: 80040400 -Error number for "Invalid Value 1" is: 80040404 -Error number for "Value Not Set 1" is: 80040402 -Error number for "Value Not Set 2" is: 80040403 -Error messages will not be interpreted to infer state. - -00:21:34.375 Driver Access Checks OK -00:21:35.008 AccessChecks OK Successfully created driver using late binding -00:21:35.253 AccessChecks OK Successfully connected using late binding -00:21:35.257 AccessChecks INFO The driver is a .NET object -00:21:35.260 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -00:21:35.265 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -00:21:35.269 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 -00:21:35.992 AccessChecks INFO Device does not expose IFocuser interface -00:21:36.147 AccessChecks INFO Device does not expose IFocuserV2 interface -00:21:36.479 AccessChecks INFO Device exposes IFocuserV3 interface -00:21:36.692 AccessChecks OK Successfully created driver using driver access toolkit -00:21:36.895 AccessChecks OK Successfully connected using driver access toolkit -00:21:36.958 AccessChecks OK Successfully disconnected using driver access toolkit - -Conform is using ASCOM.DriverAccess.Focuser to get a Focuser object -00:21:37.078 ConformanceCheck OK Driver instance created successfully -00:21:37.311 ConformanceCheck OK Connected OK - -Common Driver Methods -00:21:37.348 InterfaceVersion OK 3 -00:21:37.374 Connected OK True -00:21:37.401 Description OK Meade Autostar 497 .net -00:21:37.428 DriverInfo OK Information about the driver itself. Version: 0.2 -00:21:37.457 DriverVersion OK 0.2 -00:21:37.485 Name OK Meade Autostar 497 .net -00:21:37.511 CommandXXX INFO Tests skipped -00:21:37.515 Action INFO Conform cannot test the Action method -00:21:37.521 SupportedActions OK Driver returned an empty action list - -Properties -00:21:37.626 Absolute OK False -00:21:37.631 IsMoving OK False -00:21:37.637 MaxStep OK 7000 -00:21:37.642 MaxIncrement OK 7000 -00:21:37.820 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected -00:21:37.988 StepSize OK Optional member threw a PropertyNotImplementedException exception. -00:21:37.993 TempCompAvailable OK False -00:21:37.999 TempComp Read OK False -00:21:38.167 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected -00:21:38.504 Temperature OK Optional member threw a PropertyNotImplementedException exception. - -Methods -00:21:38.544 Halt OK Focuser halted OK -00:21:38.552 Move - TempComp False Moving by: 700 -00:21:39.264 Move - TempComp False Asynchronous move found -00:21:39.270 Move - TempComp False OK Relative move OK -00:21:39.278 Move - TempComp False INFO Returning to original position: 0 - -Conformance test complete - -No errors, warnings or issues found: your driver passes ASCOM validation!! - -Driver Hash Value: DBF36156F87DA91F130E0AABEFE80B250D62C2DB689AD8B44243AE0D9322245CF15AAE2E663962402E87B6B1A15440A6DDB46562EFB9527E3596096319C2AC85 diff --git a/ASCOM.MeadeAutostar497.Telescope.Validation.txt b/ASCOM.MeadeAutostar497.Telescope.Validation.txt deleted file mode 100644 index eff5811..0000000 --- a/ASCOM.MeadeAutostar497.Telescope.Validation.txt +++ /dev/null @@ -1,268 +0,0 @@ -Conform Report Hash (V1): 671D83C15427DD14D9FA7F5A6C62D6B21372362C5173A2B95171D14D7442358DCF3950481797D63EB94E642D2563C3094C387C23D65466833FEA5E64CD045B46 - - -ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 -ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 - -ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope - -Error handling -Error number for "Not Implemented" is: 80040400 -Error number for "Invalid Value 1" is: 80040401 -Error number for "Invalid Value 2" is: 80040405 -Error number for "Value Not Set 1" is: 80040402 -Error number for "Value Not Set 2" is: 80040403 -Error messages will not be interpreted to infer state. - -18:07:45.625 Driver Access Checks OK -18:07:46.272 AccessChecks OK Successfully created driver using late binding -18:07:46.685 AccessChecks OK Successfully connected using late binding -18:07:46.689 AccessChecks INFO The driver is a .NET object -18:07:46.693 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -18:07:46.697 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -18:07:46.701 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 -18:07:47.416 AccessChecks INFO Device does not expose interface ITelescopeV2 -18:07:48.387 AccessChecks INFO Device exposes interface ITelescopeV3 -18:07:49.708 AccessChecks OK Successfully created driver using driver access toolkit -18:07:50.029 AccessChecks OK Successfully connected using driver access toolkit - -Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -18:07:51.351 ConformanceCheck OK Driver instance created successfully -18:07:51.775 ConformanceCheck OK Connected OK - -Common Driver Methods -18:07:51.817 InterfaceVersion OK 3 -18:07:51.845 Connected OK True -18:07:51.874 Description OK Meade Autostar 497 .net -18:07:51.903 DriverInfo OK Information about the driver itself. Version: 0.0 -18:07:51.932 DriverVersion OK 0.0 -18:07:51.961 Name OK Meade Autostar 497 .net -18:07:51.990 CommandString INFO Conform cannot test the CommandString method -18:07:51.996 CommandBlind INFO Conform cannot test the CommandBlind method -18:07:52.002 CommandBool INFO Conform cannot test the CommandBool method -18:07:52.008 Action INFO Conform cannot test the Action method -18:07:52.015 SupportedActions OK Driver returned an empty action list - -Can Properties -18:07:52.082 CanFindHome OK False -18:07:52.089 CanPark OK True -18:07:52.096 CanPulseGuide OK True -18:07:52.102 CanSetDeclinationRate OK False -18:07:52.109 CanSetGuideRates OK False -18:07:52.117 CanSetPark OK False -18:07:52.125 CanSetPierSide OK False -18:07:52.177 CanSetRightAscensionRate OK False -18:07:52.185 CanSetTracking OK False -18:07:52.193 CanSlew OK True -18:07:52.200 CanSlewltAz OK True -18:07:52.208 CanSlewAltAzAsync OK True -18:07:52.216 CanSlewAsync OK True -18:07:52.224 CanSync OK True -18:07:52.231 CanSyncAltAz OK False -18:07:52.239 CanUnPark OK False - -Pre-run Checks -18:07:52.286 Mount Safety INFO Scope is not parked, continuing testing -18:07:52.339 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -18:07:52.348 TimeCheck INFO PC UTCDate: 08-May-2019 17:07:52.347 -18:07:53.254 TimeCheck INFO Mount UTCDate: 02-May-2019 19:33:55.000 - -Properties -18:07:53.358 AlignmentMode OK algPolar -18:07:53.515 Altitude OK 1.00 -18:07:53.555 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -18:07:53.591 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -18:07:53.622 AtHome OK False -18:07:53.654 AtPark OK False -18:07:53.847 Azimuth OK 45.67 -18:07:54.028 Declination OK -01:00:01.00 -18:07:54.060 DeclinationRate Read OK 0.00 -18:07:54.093 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.126 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.159 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.193 EquatorialSystem OK equLocalTopocentric -18:07:54.227 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.260 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.270 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.303 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.314 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.347 IsPulseGuiding OK False -18:07:54.541 RightAscension OK 03:59:09.00 -18:07:54.575 RightAscensionRate Read OK 0.00 -18:07:54.609 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.644 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.678 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.691 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.703 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.861 SiteLatitude Read OK 00:00:00.00 -18:07:54.900 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -18:07:54.912 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -18:07:55.315 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -18:07:55.455 SiteLongitude Read OK -42:12:00.00 -18:07:55.490 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -18:07:55.502 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -18:07:56.090 SiteLongitude Write OK Legal value -42:12:00.00 degrees written successfully -18:07:56.246 Slewing OK False -18:07:56.280 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.315 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.328 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.363 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.578 SiderealTime OK 05:17:41.24 -18:07:56.590 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:17:41.24, ASCOM: 05:24:06.50 -18:07:56.626 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -18:07:56.661 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:07:56.673 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -18:07:56.708 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:07:56.720 Tracking Read OK True -18:07:56.756 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -18:07:56.797 TrackingRates Found drive rate: driveSidereal -18:07:56.809 TrackingRates OK Drive rates read OK -18:07:56.822 TrackingRates OK Disposed tracking rates OK -18:07:56.858 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -18:07:57.039 TrackingRate Read OK driveLunar -18:07:57.075 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:57.088 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:57.624 UTCDate Read OK 02-May-2019 19:33:59.000 -18:07:58.626 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:33:59 - -Methods -18:07:59.997 CanMoveAxis:Primary OK CanMoveAxis:Primary True -18:08:00.035 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -18:08:00.072 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -18:08:00.108 Park/Unpark INFO Tests skipped -18:08:00.131 AbortSlew OK AbortSlew OK when not slewing -18:08:00.199 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:08:00.211 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:08:00.225 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:08:00.239 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:08:00.253 AxisRate:Primary OK No overlapping axis rates found -18:08:00.266 AxisRate:Primary OK No duplicate axis rates found -18:08:00.279 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -18:08:00.295 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -18:08:00.310 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -18:08:00.322 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -18:08:00.336 AxisRate:Primary OK Disposed axis rates OK -18:08:00.350 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:08:00.362 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:08:00.375 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:08:00.387 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:08:00.400 AxisRate:Secondary OK No overlapping axis rates found -18:08:00.414 AxisRate:Secondary OK No duplicate axis rates found -18:08:00.445 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -18:08:00.458 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -18:08:00.472 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -18:08:00.487 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -18:08:00.501 AxisRate:Secondary OK Disposed axis rates OK -18:08:00.517 AxisRate:Tertiary OK Empty axis rate returned -18:08:00.531 AxisRate:Tertiary OK Disposed axis rates OK -18:08:00.550 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -18:08:00.606 MoveAxis Primary OK Can successfully set a movement rate of zero -18:08:00.622 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:08:00.659 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -18:08:04.867 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -18:08:09.770 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -18:08:13.981 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:08:13.998 MoveAxis Primary OK AxisRates object successfully disposed -18:08:14.057 MoveAxis Secondary OK Can successfully set a movement rate of zero -18:08:14.072 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:08:14.107 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -18:08:18.317 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -18:08:23.262 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -18:08:27.473 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:08:27.492 MoveAxis Secondary OK AxisRates object successfully disposed -18:08:27.551 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -18:08:29.592 PulseGuide OK Synchronous pulse guide found OK -18:08:54.449 SlewToCoordinates INFO Slewed within 39.2 arc seconds of expected RA: 04:18:14.61, actual RA: 04:18:12.00 -18:08:54.463 SlewToCoordinates INFO Slewed within 7199.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:59.00 -18:08:54.478 SlewToCoordinates OK The TargetRightAscension property 04:18:14.61 matches the expected RA OK. -18:08:54.492 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -18:08:54.548 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:08:55.301 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:08:55.360 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:08:56.199 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:09:20.477 SlewToCoordinatesAsync INFO Slewed within 19.3 arc seconds of expected RA: 03:18:41.28, actual RA: 03:18:40.00 -18:09:20.490 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 -18:09:20.503 SlewToCoordinatesAsync OK The TargetRightAscension property 03:18:41.28 matches the expected RA OK. -18:09:20.516 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -18:09:20.558 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:09:21.381 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:09:21.442 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:09:22.292 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:09:44.520 SyncToCoordinates INFO Slewed to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:09:44.534 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -18:09:47.045 SyncToCoordinates INFO Synced to sync position within 71.8 arc seconds of expected RA: 02:15:07.79, actual RA: 02:15:03.00 -18:09:47.058 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -18:09:47.071 SyncToCoordinates OK The TargetRightAscension property 02:15:07.79 matches the expected RA OK. -18:09:47.085 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. -18:10:08.444 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:10:08.458 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:10:10.791 SyncToCoordinates INFO Synced to reversed sync position within 71.8 arc seconds of expected RA: 02:23:07.79, actual RA: 02:23:03.00 -18:10:10.806 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -18:10:32.484 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:10:32.498 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:10:32.537 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:10:33.329 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:10:33.389 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:10:34.242 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:10:34.301 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -18:10:34.315 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -18:10:34.979 TargetRightAscension Write OK Legal value 01:20:19.62 HH:MM:SS written successfully -18:10:35.016 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:10:35.032 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:10:35.652 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -18:10:56.417 SlewToTarget INFO Slewed within 14.8 arc seconds of expected RA: 02:20:20.99, actual RA: 02:20:20.00 -18:10:56.434 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 -18:10:56.449 SlewToTarget OK The TargetRightAscension property 02:20:20.99 matches the expected RA OK. -18:10:56.463 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -18:10:56.504 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:10:56.676 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:10:56.736 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:10:56.915 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:11:20.512 SlewToTargetAsync INFO Slewed within 35.1 arc seconds of expected RA: 01:20:42.34, actual RA: 01:20:40.00 -18:11:20.526 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 -18:11:20.539 SlewToTargetAsync OK The TargetRightAscension property 01:20:42.34 matches the expected RA OK. -18:11:20.553 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -18:11:20.593 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:11:20.774 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:11:20.833 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:11:21.032 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:11:21.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -18:11:22.864 SlewToAltAz INFO Slewed to within 144:49:47.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -18:11:22.880 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 -18:11:22.920 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:11:23.710 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:11:23.771 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:11:24.447 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:11:31.196 SlewToAltAzAsync INFO Slewed to within 149:51:53.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -18:11:31.210 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 -18:11:31.251 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:11:32.060 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:11:32.121 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:11:32.814 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:11:56.494 SyncToTarget INFO Slewed to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:11:56.509 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -18:11:59.005 SyncToTarget INFO Synced to sync position within 55.1 arc seconds of expected RA: 02:17:18.67, actual RA: 02:17:15.00 -18:11:59.019 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -18:12:22.398 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:12:22.416 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:12:24.739 SyncToTarget INFO Synced to reversed sync position within 55.1 arc seconds of expected RA: 02:25:18.67, actual RA: 02:25:15.00 -18:12:24.754 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -18:12:46.438 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:12:46.452 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:12:46.491 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:12:46.643 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:12:46.702 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:12:46.884 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:12:47.702 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected - -SideOfPier Model Tests -18:12:47.769 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read - -Post-run Checks -18:12:47.862 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. - -Conformance test complete - -No errors, warnings or issues found: your driver passes ASCOM validation!! - -Driver Hash Value: 0C55C8535B9B3A4048581454F9D6A263EFD16E20AEC783762006739F671F586B64F1D8DD3E1E613C27A5B24838AEB8656C2A19BD1EE69177ECF2619599C0DA3C diff --git a/ASCOM.MeadeGeneric.Telescope.Validation.txt b/ASCOM.MeadeGeneric.Telescope.Validation.txt new file mode 100644 index 0000000..bb3467c --- /dev/null +++ b/ASCOM.MeadeGeneric.Telescope.Validation.txt @@ -0,0 +1,269 @@ +Conform Report Hash (V1): D69EDCF187DF1AC5C724D181E8851014862252A6F96F5BD9DDE1C8AF96CB36F7E019D48BA6EF49E5B0990934E09B5898888AF1D957D11C05084347222405B5F1 + + +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: ASCOM.MeadeGeneric.Telescope + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040401 +Error number for "Invalid Value 2" is: 80040405 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +23:26:10.548 Driver Access Checks OK +23:26:11.194 AccessChecks OK Successfully created driver using late binding +23:26:11.406 AccessChecks OK Successfully connected using late binding +23:26:11.412 AccessChecks INFO The driver is a .NET object +23:26:11.417 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Telescope, ASCOM.Meade.net.Telescope, Version=6.4.0.0, Cultu +23:26:11.422 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +23:26:12.127 AccessChecks INFO Device does not expose interface ITelescopeV2 +23:26:12.921 AccessChecks INFO Device exposes interface ITelescopeV3 +23:26:14.237 AccessChecks OK Successfully created driver using driver access toolkit +23:26:14.396 AccessChecks OK Successfully connected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object +23:26:15.721 ConformanceCheck OK Driver instance created successfully +23:26:15.918 ConformanceCheck OK Connected OK + +Common Driver Methods +23:26:15.957 InterfaceVersion OK 3 +23:26:15.986 Connected OK True +23:26:16.014 Description OK Meade Generic +23:26:16.042 DriverInfo OK Information about the driver itself. Version: 6.4 +23:26:16.071 DriverVersion OK 6.4 +23:26:16.099 Name OK Meade Generic +23:26:16.127 CommandString INFO Conform cannot test the CommandString method +23:26:16.133 CommandBlind INFO Conform cannot test the CommandBlind method +23:26:16.140 CommandBool INFO Conform cannot test the CommandBool method +23:26:16.146 Action INFO Conform cannot test the Action method +23:26:16.153 SupportedActions OK Driver returned an empty action list + +Can Properties +23:26:16.220 CanFindHome OK False +23:26:16.227 CanPark OK True +23:26:16.235 CanPulseGuide OK True +23:26:16.242 CanSetDeclinationRate OK False +23:26:16.250 CanSetGuideRates OK False +23:26:16.259 CanSetPark OK False +23:26:16.268 CanSetPierSide OK False +23:26:16.315 CanSetRightAscensionRate OK False +23:26:16.323 CanSetTracking OK True +23:26:16.331 CanSlew OK True +23:26:16.338 CanSlewltAz OK True +23:26:16.347 CanSlewAltAzAsync OK True +23:26:16.355 CanSlewAsync OK True +23:26:16.364 CanSync OK True +23:26:16.372 CanSyncAltAz OK False +23:26:16.381 CanUnPark OK False + +Pre-run Checks +23:26:16.430 Mount Safety INFO Scope is not parked, continuing testing +23:26:16.461 Mount Safety INFO Scope tracking has been enabled +23:26:16.493 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +23:26:16.501 TimeCheck INFO PC UTCDate: 16-May-2019 22:26:16.501 +23:26:20.497 TimeCheck INFO Mount UTCDate: 02-May-2019 20:48:03.000 + +Properties +23:26:20.700 AlignmentMode OK algPolar +23:26:21.594 Altitude WARNING Altitude is <0.0 degrees: -0.69166667 +23:26:21.628 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +23:26:21.662 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +23:26:21.694 AtHome OK False +23:26:21.726 AtPark OK False +23:26:22.439 Azimuth OK 104.84 +23:26:23.342 Declination OK 00:41:30.00 +23:26:23.374 DeclinationRate Read OK 0.00 +23:26:23.406 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +23:26:23.440 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:23.474 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:23.507 EquatorialSystem OK equLocalTopocentric +23:26:23.539 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +23:26:23.590 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:23.601 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +23:26:23.634 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:23.645 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +23:26:23.679 IsPulseGuiding OK False +23:26:24.386 RightAscension OK 09:40:57.00 +23:26:24.420 RightAscensionRate Read OK 0.00 +23:26:24.455 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +23:26:24.488 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:24.523 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:24.534 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:24.545 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:25.089 SiteLatitude Read OK 00:00:00.00 +23:26:25.126 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +23:26:25.137 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +23:26:27.021 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully +23:26:27.875 SiteLongitude Read OK -53:48:00.00 +23:26:27.911 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +23:26:27.924 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +23:26:29.326 SiteLongitude Write OK Legal value -53:48:00.00 degrees written successfully +23:26:29.945 Slewing OK False +23:26:29.983 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:30.019 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:30.037 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +23:26:30.072 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +23:26:30.839 SiderealTime OK 10:27:03.72 +23:26:30.851 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:27:03.72, ASCOM: 10:28:41.54 +23:26:30.888 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +23:26:30.923 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +23:26:30.936 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +23:26:30.975 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +23:26:30.988 Tracking Read OK True +23:26:32.051 Tracking Write OK False +23:26:33.116 TrackingRates Found drive rate: driveSidereal +23:26:33.129 TrackingRates Found drive rate: driveLunar +23:26:33.141 TrackingRates OK Drive rates read OK +23:26:33.154 TrackingRates OK Disposed tracking rates OK +23:26:33.189 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +23:26:33.205 TrackingRate Read OK driveSidereal +23:26:33.244 TrackingRate Write OK Successfully set drive rate: driveSidereal +23:26:33.281 TrackingRate Write OK Successfully set drive rate: driveLunar +23:26:37.575 UTCDate Read OK 02-May-2019 20:48:20.000 +23:26:43.750 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:48:20 + +Methods +23:26:50.522 CanMoveAxis:Primary OK CanMoveAxis:Primary True +23:26:50.560 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +23:26:50.597 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +23:26:50.634 Park/Unpark INFO Tests skipped +23:26:50.653 AbortSlew OK AbortSlew OK when not slewing +23:26:50.718 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +23:26:50.731 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +23:26:50.743 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +23:26:50.755 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +23:26:50.767 AxisRate:Primary OK No overlapping axis rates found +23:26:50.781 AxisRate:Primary OK No duplicate axis rates found +23:26:50.795 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +23:26:50.809 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +23:26:50.823 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +23:26:50.836 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +23:26:50.848 AxisRate:Primary OK Disposed axis rates OK +23:26:50.862 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +23:26:50.875 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +23:26:50.888 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +23:26:50.901 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +23:26:50.913 AxisRate:Secondary OK No overlapping axis rates found +23:26:50.926 AxisRate:Secondary OK No duplicate axis rates found +23:26:50.939 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +23:26:50.951 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +23:26:50.964 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +23:26:50.977 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +23:26:50.991 AxisRate:Secondary OK Disposed axis rates OK +23:26:51.006 AxisRate:Tertiary OK Empty axis rate returned +23:26:51.020 AxisRate:Tertiary OK Disposed axis rates OK +23:26:51.037 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +23:26:51.087 MoveAxis Primary OK Can successfully set a movement rate of zero +23:26:51.104 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +23:26:51.141 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +23:26:55.308 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +23:27:01.632 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +23:27:05.847 MoveAxis Primary OK Tracking state correctly retained for both tracking states +23:27:05.863 MoveAxis Primary OK AxisRates object successfully disposed +23:27:05.923 MoveAxis Secondary OK Can successfully set a movement rate of zero +23:27:05.939 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +23:27:05.976 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +23:27:10.149 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +23:27:16.454 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +23:27:20.626 MoveAxis Secondary OK Tracking state correctly retained for both tracking states +23:27:20.641 MoveAxis Secondary OK AxisRates object successfully disposed +23:27:20.701 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +23:27:22.740 PulseGuide OK Synchronous pulse guide found OK +23:27:53.262 SlewToCoordinates OK Slewed OK. RA: 09:27:56.59 +23:27:53.280 SlewToCoordinates INFO Slewed within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +23:27:53.295 SlewToCoordinates OK The TargetRightAscension property 09:27:56.59 matches the expected RA OK. +23:27:53.309 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +23:27:53.356 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +23:27:57.509 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +23:27:57.569 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +23:28:01.565 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +23:28:33.449 SlewToCoordinatesAsync INFO Slewed within 52.6 arc seconds of expected RA: 08:28:35.51, actual RA: 08:28:32.00 +23:28:33.463 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 +23:28:33.479 SlewToCoordinatesAsync OK The TargetRightAscension property 08:28:35.51 matches the expected RA OK. +23:28:33.496 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +23:28:33.539 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +23:28:37.553 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +23:28:37.614 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +23:28:41.477 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +23:29:15.070 SyncToCoordinates INFO Slewed to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 +23:29:15.084 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 +23:29:22.898 SyncToCoordinates INFO Synced to sync position within 33.3 arc seconds of expected RA: 07:25:17.22, actual RA: 07:25:15.00 +23:29:22.912 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +23:29:22.928 SyncToCoordinates OK The TargetRightAscension property 07:25:17.22 matches the expected RA OK. +23:29:22.942 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. +23:29:51.132 SyncToCoordinates INFO Slewed back to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 +23:29:51.146 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +23:30:01.039 SyncToCoordinates INFO Synced to reversed sync position within 18.3 arc seconds of expected RA: 07:33:17.22, actual RA: 07:33:16.00 +23:30:01.052 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +23:30:31.303 SyncToCoordinates INFO Slewed back to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 +23:30:31.317 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 +23:30:31.357 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +23:30:35.078 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +23:30:35.139 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +23:30:39.202 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +23:30:39.261 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +23:30:39.277 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +23:30:43.319 TargetRightAscension Write OK Legal value 06:31:13.60 HH:MM:SS written successfully +23:30:43.356 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +23:30:43.372 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +23:30:46.838 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +23:31:17.315 SlewToTarget INFO Slewed within 18.1 arc seconds of expected RA: 07:31:21.21, actual RA: 07:31:20.00 +23:31:17.331 SlewToTarget INFO Slewed within 21597.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:57.00 +23:31:17.350 SlewToTarget OK The TargetRightAscension property 07:31:21.21 matches the expected RA OK. +23:31:17.379 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +23:31:17.421 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +23:31:18.143 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +23:31:18.205 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +23:31:18.847 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +23:31:51.318 SlewToTargetAsync INFO Slewed within 19.9 arc seconds of expected RA: 06:31:53.33, actual RA: 06:31:52.00 +23:31:51.332 SlewToTargetAsync INFO Slewed within 28799.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:59.00 +23:31:51.347 SlewToTargetAsync OK The TargetRightAscension property 06:31:53.33 matches the expected RA OK. +23:31:51.361 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +23:31:51.402 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +23:31:52.156 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +23:31:52.221 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +23:31:52.868 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +23:31:52.927 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +23:32:02.721 SlewToAltAz INFO Slewed to within 93:51:10.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +23:32:02.735 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 +23:32:02.775 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +23:32:06.306 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +23:32:06.368 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +23:32:09.947 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +23:32:24.096 SlewToAltAzAsync INFO Slewed to within 98:56:32.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +23:32:24.110 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 +23:32:24.154 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +23:32:27.733 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +23:32:27.793 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +23:32:31.369 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +23:33:05.205 SyncToTarget INFO Slewed to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 +23:33:05.220 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 +23:33:15.238 SyncToTarget INFO Synced to sync position within 71.0 arc seconds of expected RA: 07:29:07.73, actual RA: 07:29:03.00 +23:33:15.252 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 +23:33:45.180 SyncToTarget INFO Slewed back to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 +23:33:45.195 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +23:33:55.078 SyncToTarget INFO Synced to reversed sync position within 71.0 arc seconds of expected RA: 07:37:07.73, actual RA: 07:37:03.00 +23:33:55.093 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 +23:34:25.167 SyncToTarget INFO Slewed back to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 +23:34:25.192 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 +23:34:25.232 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +23:34:25.975 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +23:34:26.037 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +23:34:26.840 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +23:34:30.138 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected + +SideOfPier Model Tests +23:34:30.213 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read + +Post-run Checks +23:34:30.305 Mount Safety OK Tracking stopped to protect your mount. + +Conformance test complete + +Your driver had 0 errors, 1 warning and 0 issue + +Driver Hash Value: E1CEF5959BFC13BA7F63F73CE38558054C95A93AFE504B722E7EBCDB7DC403E36016216B81EE41CCFE368BC213DDAA8F952A53B3DC88D294D73445C25125D33D diff --git a/ASCOM.MeadeGeneric.focuser.Validation.txt b/ASCOM.MeadeGeneric.focuser.Validation.txt new file mode 100644 index 0000000..d263ba5 --- /dev/null +++ b/ASCOM.MeadeGeneric.focuser.Validation.txt @@ -0,0 +1,69 @@ +Conform Report Hash (V1): 67092198F82F435D10580E3B3E3E460EC0B5E438532A7B5D83C09425222F097CA9A23C883D4238654F217FCA9801E46720811B7CDB982868C68843CCDA33E7FB + + +ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 +ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 + +ConformanceCheck Driver ProgID: ASCOM.MeadeGeneric.focuser + +Error handling +Error number for "Not Implemented" is: 80040400 +Error number for "Invalid Value 1" is: 80040404 +Error number for "Value Not Set 1" is: 80040402 +Error number for "Value Not Set 2" is: 80040403 +Error messages will not be interpreted to infer state. + +23:25:52.259 Driver Access Checks OK +23:25:52.911 AccessChecks OK Successfully created driver using late binding +23:25:53.126 AccessChecks OK Successfully connected using late binding +23:25:53.131 AccessChecks INFO The driver is a .NET object +23:25:53.137 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Focuser, ASCOM.Meade.net.Focuser, Version=6.4.0.0, Culture=n +23:25:53.142 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +23:25:53.793 AccessChecks INFO Device does not expose IFocuser interface +23:25:53.855 AccessChecks INFO Device does not expose IFocuserV2 interface +23:25:54.068 AccessChecks INFO Device exposes IFocuserV3 interface +23:25:54.190 AccessChecks OK Successfully created driver using driver access toolkit +23:25:54.344 AccessChecks OK Successfully connected using driver access toolkit +23:25:54.407 AccessChecks OK Successfully disconnected using driver access toolkit + +Conform is using ASCOM.DriverAccess.Focuser to get a Focuser object +23:25:54.480 ConformanceCheck OK Driver instance created successfully +23:25:54.679 ConformanceCheck OK Connected OK + +Common Driver Methods +23:25:54.721 InterfaceVersion OK 3 +23:25:54.750 Connected OK True +23:25:54.779 Description OK Meade Generic +23:25:54.808 DriverInfo OK Information about the driver itself. Version: 6.4 +23:25:54.837 DriverVersion OK 6.4 +23:25:54.866 Name OK Meade Generic +23:25:54.895 CommandString INFO Conform cannot test the CommandString method +23:25:54.901 CommandBlind INFO Conform cannot test the CommandBlind method +23:25:54.908 CommandBool INFO Conform cannot test the CommandBool method +23:25:54.916 Action INFO Conform cannot test the Action method +23:25:54.924 SupportedActions OK Driver returned an empty action list + +Properties +23:25:55.035 Absolute OK False +23:25:55.043 IsMoving OK False +23:25:55.051 MaxStep OK 7000 +23:25:55.059 MaxIncrement OK 7000 +23:25:55.073 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected +23:25:55.084 StepSize OK Optional member threw a PropertyNotImplementedException exception. +23:25:55.091 TempCompAvailable OK False +23:25:55.100 TempComp Read OK False +23:25:55.108 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected +23:25:55.120 Temperature OK Optional member threw a PropertyNotImplementedException exception. + +Methods +23:25:55.170 Halt OK Focuser halted OK +23:25:55.183 Move - TempComp False Moving by: 700 +23:25:55.895 Move - TempComp False Asynchronous move found +23:25:55.904 Move - TempComp False OK Relative move OK +23:25:55.915 Move - TempComp False INFO Returning to original position: 0 + +Conformance test complete + +No errors, warnings or issues found: your driver passes ASCOM validation!! + +Driver Hash Value: DE237CD97B3A95A514A5D7FD9B265F5F98174E67A28B44FF5CA2FC9A1CF355DA2C4DFB9416F3C40A8056334CC5339F0D8F8A39026A4BB5E3AE1FFC2BD8F55FBD diff --git a/ConformanceResult.txt b/ConformanceResult.txt deleted file mode 100644 index beecf54..0000000 --- a/ConformanceResult.txt +++ /dev/null @@ -1,272 +0,0 @@ -Start-up ASCOM Device Conformance Checker - 64bit mode -Start-up ASCOM Platform 6.4 SP1 6.4.1.2695 - - -ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 -ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 - -ConformanceCheck Driver ProgID: ASCOM.MeadeAutostar497.Telescope - -Error handling -Error number for "Not Implemented" is: 80040400 -Error number for "Invalid Value 1" is: 80040401 -Error number for "Invalid Value 2" is: 80040405 -Error number for "Value Not Set 1" is: 80040402 -Error number for "Value Not Set 2" is: 80040403 -Error messages will not be interpreted to infer state. - -18:07:45.625 Driver Access Checks OK -18:07:46.272 AccessChecks OK Successfully created driver using late binding -18:07:46.685 AccessChecks OK Successfully connected using late binding -18:07:46.689 AccessChecks INFO The driver is a .NET object -18:07:46.693 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.MeadeAutostar497.Telescope, ASCOM.MeadeAutostar497.Telescope, Version= -18:07:46.697 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -18:07:46.701 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 -18:07:47.416 AccessChecks INFO Device does not expose interface ITelescopeV2 -18:07:48.387 AccessChecks INFO Device exposes interface ITelescopeV3 -18:07:49.708 AccessChecks OK Successfully created driver using driver access toolkit -18:07:50.029 AccessChecks OK Successfully connected using driver access toolkit - -Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -18:07:51.351 ConformanceCheck OK Driver instance created successfully -18:07:51.775 ConformanceCheck OK Connected OK - -Common Driver Methods -18:07:51.817 InterfaceVersion OK 3 -18:07:51.845 Connected OK True -18:07:51.874 Description OK Meade Autostar 497 .net -18:07:51.903 DriverInfo OK Information about the driver itself. Version: 0.0 -18:07:51.932 DriverVersion OK 0.0 -18:07:51.961 Name OK Meade Autostar 497 .net -18:07:51.990 CommandString INFO Conform cannot test the CommandString method -18:07:51.996 CommandBlind INFO Conform cannot test the CommandBlind method -18:07:52.002 CommandBool INFO Conform cannot test the CommandBool method -18:07:52.008 Action INFO Conform cannot test the Action method -18:07:52.015 SupportedActions OK Driver returned an empty action list - -Can Properties -18:07:52.082 CanFindHome OK False -18:07:52.089 CanPark OK True -18:07:52.096 CanPulseGuide OK True -18:07:52.102 CanSetDeclinationRate OK False -18:07:52.109 CanSetGuideRates OK False -18:07:52.117 CanSetPark OK False -18:07:52.125 CanSetPierSide OK False -18:07:52.177 CanSetRightAscensionRate OK False -18:07:52.185 CanSetTracking OK False -18:07:52.193 CanSlew OK True -18:07:52.200 CanSlewltAz OK True -18:07:52.208 CanSlewAltAzAsync OK True -18:07:52.216 CanSlewAsync OK True -18:07:52.224 CanSync OK True -18:07:52.231 CanSyncAltAz OK False -18:07:52.239 CanUnPark OK False - -Pre-run Checks -18:07:52.286 Mount Safety INFO Scope is not parked, continuing testing -18:07:52.339 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -18:07:52.348 TimeCheck INFO PC UTCDate: 08-May-2019 17:07:52.347 -18:07:53.254 TimeCheck INFO Mount UTCDate: 02-May-2019 19:33:55.000 - -Properties -18:07:53.358 AlignmentMode OK algPolar -18:07:53.515 Altitude OK 1.00 -18:07:53.555 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -18:07:53.591 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -18:07:53.622 AtHome OK False -18:07:53.654 AtPark OK False -18:07:53.847 Azimuth OK 45.67 -18:07:54.028 Declination OK -01:00:01.00 -18:07:54.060 DeclinationRate Read OK 0.00 -18:07:54.093 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.126 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.159 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.193 EquatorialSystem OK equLocalTopocentric -18:07:54.227 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.260 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.270 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.303 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.314 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.347 IsPulseGuiding OK False -18:07:54.541 RightAscension OK 03:59:09.00 -18:07:54.575 RightAscensionRate Read OK 0.00 -18:07:54.609 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -18:07:54.644 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.678 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.691 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.703 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:54.861 SiteLatitude Read OK 00:00:00.00 -18:07:54.900 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -18:07:54.912 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -18:07:55.315 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -18:07:55.455 SiteLongitude Read OK -42:12:00.00 -18:07:55.490 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -18:07:55.502 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -18:07:56.090 SiteLongitude Write OK Legal value -42:12:00.00 degrees written successfully -18:07:56.246 Slewing OK False -18:07:56.280 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.315 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.328 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.363 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -18:07:56.578 SiderealTime OK 05:17:41.24 -18:07:56.590 SiderealTime INFO Scope and ASCOM sidereal times are up to 0.5 hour different, Scope: 05:17:41.24, ASCOM: 05:24:06.50 -18:07:56.626 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -18:07:56.661 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:07:56.673 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -18:07:56.708 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -18:07:56.720 Tracking Read OK True -18:07:56.756 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -18:07:56.797 TrackingRates Found drive rate: driveSidereal -18:07:56.809 TrackingRates OK Drive rates read OK -18:07:56.822 TrackingRates OK Disposed tracking rates OK -18:07:56.858 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -18:07:57.039 TrackingRate Read OK driveLunar -18:07:57.075 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:57.088 TrackingRate Write OK Optional member threw a PropertyNotImplementedException exception. -18:07:57.624 UTCDate Read OK 02-May-2019 19:33:59.000 -18:07:58.626 UTCDate Write OK New UTCDate written successfully: 02/05/2019 20:33:59 - -Methods -18:07:59.997 CanMoveAxis:Primary OK CanMoveAxis:Primary True -18:08:00.035 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -18:08:00.072 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -18:08:00.108 Park/Unpark INFO Tests skipped -18:08:00.131 AbortSlew OK AbortSlew OK when not slewing -18:08:00.199 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:08:00.211 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:08:00.225 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:08:00.239 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:08:00.253 AxisRate:Primary OK No overlapping axis rates found -18:08:00.266 AxisRate:Primary OK No duplicate axis rates found -18:08:00.279 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -18:08:00.295 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -18:08:00.310 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -18:08:00.322 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -18:08:00.336 AxisRate:Primary OK Disposed axis rates OK -18:08:00.350 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -18:08:00.362 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -18:08:00.375 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -18:08:00.387 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -18:08:00.400 AxisRate:Secondary OK No overlapping axis rates found -18:08:00.414 AxisRate:Secondary OK No duplicate axis rates found -18:08:00.445 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -18:08:00.458 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -18:08:00.472 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -18:08:00.487 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -18:08:00.501 AxisRate:Secondary OK Disposed axis rates OK -18:08:00.517 AxisRate:Tertiary OK Empty axis rate returned -18:08:00.531 AxisRate:Tertiary OK Disposed axis rates OK -18:08:00.550 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -18:08:00.606 MoveAxis Primary OK Can successfully set a movement rate of zero -18:08:00.622 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:08:00.659 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -18:08:04.867 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -18:08:09.770 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -18:08:13.981 MoveAxis Primary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:08:13.998 MoveAxis Primary OK AxisRates object successfully disposed -18:08:14.057 MoveAxis Secondary OK Can successfully set a movement rate of zero -18:08:14.072 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -18:08:14.107 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -18:08:18.317 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -18:08:23.262 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -18:08:27.473 MoveAxis Secondary OK Tracking state correctly restored after MoveAxis when CanSetTracking is false -18:08:27.492 MoveAxis Secondary OK AxisRates object successfully disposed -18:08:27.551 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -18:08:29.592 PulseGuide OK Synchronous pulse guide found OK -18:08:54.449 SlewToCoordinates INFO Slewed within 39.2 arc seconds of expected RA: 04:18:14.61, actual RA: 04:18:12.00 -18:08:54.463 SlewToCoordinates INFO Slewed within 7199.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -00:59:59.00 -18:08:54.478 SlewToCoordinates OK The TargetRightAscension property 04:18:14.61 matches the expected RA OK. -18:08:54.492 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -18:08:54.548 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:08:55.301 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:08:55.360 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:08:56.199 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:09:20.477 SlewToCoordinatesAsync INFO Slewed within 19.3 arc seconds of expected RA: 03:18:41.28, actual RA: 03:18:40.00 -18:09:20.490 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 -18:09:20.503 SlewToCoordinatesAsync OK The TargetRightAscension property 03:18:41.28 matches the expected RA OK. -18:09:20.516 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -18:09:20.558 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:09:21.381 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:09:21.442 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:09:22.292 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:09:44.520 SyncToCoordinates INFO Slewed to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:09:44.534 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -18:09:47.045 SyncToCoordinates INFO Synced to sync position within 71.8 arc seconds of expected RA: 02:15:07.79, actual RA: 02:15:03.00 -18:09:47.058 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -18:09:47.071 SyncToCoordinates OK The TargetRightAscension property 02:15:07.79 matches the expected RA OK. -18:09:47.085 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. -18:10:08.444 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:10:08.458 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:10:10.791 SyncToCoordinates INFO Synced to reversed sync position within 71.8 arc seconds of expected RA: 02:23:07.79, actual RA: 02:23:03.00 -18:10:10.806 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -18:10:32.484 SyncToCoordinates INFO Slewed back to start position within 56.8 arc seconds of expected RA: 02:19:07.79, actual RA: 02:19:04.00 -18:10:32.498 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -18:10:32.537 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -18:10:33.329 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -18:10:33.389 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -18:10:34.242 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -18:10:34.301 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -18:10:34.315 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -18:10:34.979 TargetRightAscension Write OK Legal value 01:20:19.62 HH:MM:SS written successfully -18:10:35.016 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:10:35.032 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -18:10:35.652 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -18:10:56.417 SlewToTarget INFO Slewed within 14.8 arc seconds of expected RA: 02:20:20.99, actual RA: 02:20:20.00 -18:10:56.434 SlewToTarget INFO Slewed within 21596.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:56.00 -18:10:56.449 SlewToTarget OK The TargetRightAscension property 02:20:20.99 matches the expected RA OK. -18:10:56.463 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -18:10:56.504 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:10:56.676 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:10:56.736 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:10:56.915 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:11:20.512 SlewToTargetAsync INFO Slewed within 35.1 arc seconds of expected RA: 01:20:42.34, actual RA: 01:20:40.00 -18:11:20.526 SlewToTargetAsync INFO Slewed within 28797.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:57.00 -18:11:20.539 SlewToTargetAsync OK The TargetRightAscension property 01:20:42.34 matches the expected RA OK. -18:11:20.553 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -18:11:20.593 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:11:20.774 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:11:20.833 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:11:21.032 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:11:21.091 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -18:11:22.864 SlewToAltAz INFO Slewed to within 144:49:47.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -18:11:22.880 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 -18:11:22.920 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:11:23.710 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:11:23.771 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:11:24.447 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:11:31.196 SlewToAltAzAsync INFO Slewed to within 149:51:53.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -18:11:31.210 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 -18:11:31.251 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -18:11:32.060 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -18:11:32.121 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -18:11:32.814 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -18:11:56.494 SyncToTarget INFO Slewed to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:11:56.509 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -18:11:59.005 SyncToTarget INFO Synced to sync position within 55.1 arc seconds of expected RA: 02:17:18.67, actual RA: 02:17:15.00 -18:11:59.019 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -18:12:22.398 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:12:22.416 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:12:24.739 SyncToTarget INFO Synced to reversed sync position within 55.1 arc seconds of expected RA: 02:25:18.67, actual RA: 02:25:15.00 -18:12:24.754 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -18:12:46.438 SyncToTarget INFO Slewed back to start position within 40.1 arc seconds of expected RA: 02:21:18.67, actual RA: 02:21:16.00 -18:12:46.452 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -18:12:46.491 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -18:12:46.643 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -18:12:46.702 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -18:12:46.884 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -18:12:47.702 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected - -SideOfPier Model Tests -18:12:47.769 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read - -Post-run Checks -18:12:47.862 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. - -Conformance test complete - -No errors, warnings or issues found: your driver passes ASCOM validation!! - -Driver Hash Value: 0C55C8535B9B3A4048581454F9D6A263EFD16E20AEC783762006739F671F586B64F1D8DD3E1E613C27A5B24838AEB8656C2A19BD1EE69177ECF2619599C0DA3C -Report Hash Value: 671D83C15427DD14D9FA7F5A6C62D6B21372362C5173A2B95171D14D7442358DCF3950481797D63EB94E642D2563C3094C387C23D65466833FEA5E64CD045B46 - -The validation file is: C:\Users\colin\Documents\ASCOM\Logs 2019-05-08\ASCOM.MeadeAutostar497.Telescope.Validation.txt diff --git a/FocuserTestConsole/FocuserTestConsole.csproj b/FocuserTestConsole/FocuserTestConsole.csproj new file mode 100644 index 0000000..1067b3a --- /dev/null +++ b/FocuserTestConsole/FocuserTestConsole.csproj @@ -0,0 +1,64 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49} + Exe + Properties + ASCOM.MeadeGeneric + ASCOM.MeadeGeneric.Test + v4.7.1 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FocuserTestConsole/Program.cs b/FocuserTestConsole/Program.cs new file mode 100644 index 0000000..af644c8 --- /dev/null +++ b/FocuserTestConsole/Program.cs @@ -0,0 +1,55 @@ +// This implements a console application that can be used to test an ASCOM driver +// + +// This is used to define code in the template that is specific to one class implementation +// unused code can be deleted and this definition removed. + +#define Telescope +// remove this to bypass the code that uses the chooser to select the driver +#define UseChooser + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using ASCOM.DriverAccess; + +namespace ASCOM +{ + class Program + { + static void Main(string[] args) + { + // Uncomment the code that's required +#if UseChooser + // choose the device + string id = ASCOM.DriverAccess.Focuser.Choose("ASCOM.MeadeGeneric.Focuser"); + if (string.IsNullOrEmpty(id)) + return; + // create this device + ASCOM.DriverAccess.Focuser device = new ASCOM.DriverAccess.Focuser(id); +#else + // this can be replaced by this code, it avoids the chooser and creates the driver class directly. + ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.MeadeGeneric.Telescope"); +#endif + // now run some tests, adding code to your driver so that the tests will pass. + // these first tests are common to all drivers. + Console.WriteLine("name " + device.Name); + Console.WriteLine("description " + device.Description); + Console.WriteLine("DriverInfo " + device.DriverInfo); + Console.WriteLine("driverVersion " + device.DriverVersion); + + // TODO add more code to test the driver. + device.Connected = true; + + device.Move(2000); + Thread.Sleep(2000); + device.Move(-2000); + + device.Connected = false; + Console.WriteLine("Press Enter to finish"); + Console.ReadLine(); + } + } +} diff --git a/MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs b/FocuserTestConsole/Properties/AssemblyInfo.cs similarity index 68% rename from MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs rename to FocuserTestConsole/Properties/AssemblyInfo.cs index ef108f2..5100d4b 100644 --- a/MeadeAutostar497.UnitTests/Properties/AssemblyInfo.cs +++ b/FocuserTestConsole/Properties/AssemblyInfo.cs @@ -2,35 +2,35 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("MeadeAutostar497.UnitTests")] +[assembly: AssemblyTitle("MeadeGeneric Test Application")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MeadeAutostar497.UnitTests")] -[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyCompany("ASCOM Initiative")] +[assembly: AssemblyProduct("MeadeGeneric")] +[assembly: AssemblyCopyright("Copyright © ASCOM Initiative 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9638da27-77c7-4b30-a730-6e7159a4a09f")] +[assembly: Guid("c7008f94-e3b9-4481-b720-3b56557860c6")] // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: AssemblyVersion("6.4.0.0")] +[assembly: AssemblyFileVersion("6.4.0.0")] diff --git a/TestConsole/app.config b/FocuserTestConsole/app.config similarity index 71% rename from TestConsole/app.config rename to FocuserTestConsole/app.config index 8935d57..70dcdba 100644 --- a/TestConsole/app.config +++ b/FocuserTestConsole/app.config @@ -1,3 +1,3 @@ - + diff --git a/MeadeAutostar497/ASCOM.ico b/Meade.net.Telescope/ASCOM.ico similarity index 100% rename from MeadeAutostar497/ASCOM.ico rename to Meade.net.Telescope/ASCOM.ico diff --git a/MeadeAutostar497/ASCOM.png b/Meade.net.Telescope/ASCOM.png similarity index 100% rename from MeadeAutostar497/ASCOM.png rename to Meade.net.Telescope/ASCOM.png diff --git a/MeadeAutostar497/ASCOMDriverTemplate.snk b/Meade.net.Telescope/ASCOMDriverTemplate.snk similarity index 100% rename from MeadeAutostar497/ASCOMDriverTemplate.snk rename to Meade.net.Telescope/ASCOMDriverTemplate.snk diff --git a/MeadeAutostar497/MeadeAutostar497.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj similarity index 81% rename from MeadeAutostar497/MeadeAutostar497.csproj rename to Meade.net.Telescope/Meade.net.Telescope.csproj index fe89ffa..dbf6b21 100644 --- a/MeadeAutostar497/MeadeAutostar497.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -8,14 +8,14 @@ {64308775-BD4A-469C-BCAB-3ED830B811AF} Library Properties - ASCOM.MeadeAutostar497 - ASCOM.MeadeAutostar497.Telescope + ASCOM.Meade.net + ASCOM.Meade.net.Telescope 3.5 - v4.6.2 + v4.7.1 ASCOM.ico true ASCOMDriverTemplate.snk @@ -41,18 +41,18 @@ true full false - bin\Debug\ + ..\bin\Debug\ DEBUG;TRACE prompt 4 true - AnyCPU + x86 false pdbonly true - bin\Release\ + ..\bin\Release\ TRACE prompt 4 @@ -69,7 +69,6 @@ - @@ -78,23 +77,12 @@ - - - - - - - - - - - - + True @@ -106,13 +94,7 @@ True Settings.settings - - - Form - - - SetupDialogForm.cs - + @@ -120,10 +102,6 @@ ResXFileCodeGenerator Resources.Designer.cs - - SetupDialogForm.cs - Designer - @@ -154,7 +132,12 @@ true - + + + {3689a2cb-94c5-4012-a5cf-7e7d1dd27143} + Meade.net + + diff --git a/MeadeAutostar497/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs similarity index 75% rename from MeadeAutostar497/Properties/AssemblyInfo.cs rename to Meade.net.Telescope/Properties/AssemblyInfo.cs index 495f3d8..e395e18 100644 --- a/MeadeAutostar497/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -7,11 +7,11 @@ using System.Runtime.InteropServices; // associated with an assembly. // // TODO - Add your authorship information here -[assembly: AssemblyTitle("ASCOM.MeadeAutostar497.Telescope")] -[assembly: AssemblyDescription("ASCOM MeadeAutostar497 .net")] +[assembly: AssemblyTitle("ASCOM.Meade.net.Telescope")] +[assembly: AssemblyDescription("ASCOM Telescope driver for Meade.net")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Cjdawson.com")] -[assembly: AssemblyProduct("ASCOM Telescope driver for MeadeAutostar497")] +[assembly: AssemblyCompany("cjdawson.com")] +[assembly: AssemblyProduct("ASCOM Telescope driver for Meade.net")] [assembly: AssemblyCopyright("Copyright © 2019 cjdawson.com")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -22,7 +22,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(true)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("55d0f255-cb49-4e6b-bc32-4f8fb874734d")] +[assembly: Guid("8b9fccb9-87ae-42f7-90af-079e13de6efb")] // Version information for an assembly consists of the following four values: // @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.2.0.0")] -[assembly: AssemblyFileVersion("0.2.0.0")] +[assembly: AssemblyVersion("0.4.0.0")] +[assembly: AssemblyFileVersion("0.4.0.0")] diff --git a/MeadeAutostar497/Properties/Resources.Designer.cs b/Meade.net.Telescope/Properties/Resources.Designer.cs similarity index 95% rename from MeadeAutostar497/Properties/Resources.Designer.cs rename to Meade.net.Telescope/Properties/Resources.Designer.cs index 9d71803..67f90ec 100644 --- a/MeadeAutostar497/Properties/Resources.Designer.cs +++ b/Meade.net.Telescope/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace ASCOM.MeadeAutostar497.Properties { +namespace ASCOM.Meade.net.Properties { using System; @@ -39,7 +39,7 @@ namespace ASCOM.MeadeAutostar497.Properties { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.MeadeAutostar497.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.Meade.net.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/MeadeAutostar497/Properties/Resources.resx b/Meade.net.Telescope/Properties/Resources.resx similarity index 100% rename from MeadeAutostar497/Properties/Resources.resx rename to Meade.net.Telescope/Properties/Resources.resx diff --git a/MeadeAutostar497/Properties/Settings.Designer.cs b/Meade.net.Telescope/Properties/Settings.Designer.cs similarity index 95% rename from MeadeAutostar497/Properties/Settings.Designer.cs rename to Meade.net.Telescope/Properties/Settings.Designer.cs index a2bb372..f1cc444 100644 --- a/MeadeAutostar497/Properties/Settings.Designer.cs +++ b/Meade.net.Telescope/Properties/Settings.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace ASCOM.MeadeAutostar497.Properties { +namespace ASCOM.Meade.net.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] diff --git a/MeadeAutostar497/Properties/Settings.settings b/Meade.net.Telescope/Properties/Settings.settings similarity index 100% rename from MeadeAutostar497/Properties/Settings.settings rename to Meade.net.Telescope/Properties/Settings.settings diff --git a/MeadeAutostar497/AscomClasses/Rates.cs b/Meade.net.Telescope/Rates.cs similarity index 93% rename from MeadeAutostar497/AscomClasses/Rates.cs rename to Meade.net.Telescope/Rates.cs index bd29429..2230bf7 100644 --- a/MeadeAutostar497/AscomClasses/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -7,18 +7,18 @@ using ASCOM.DeviceInterface; using System.Collections; using System.Threading; -namespace ASCOM.MeadeAutostar497 +namespace ASCOM.Meade.net { #region Rate class // // The Rate class implements IRate, and is used to hold values // for AxisRates. You do not need to change this class. // - // The Guid attribute sets the CLSID for ASCOM.MeadeAutostar497.Rate + // The Guid attribute sets the CLSID for ASCOM.Meade.net.Rate // The ClassInterface/None addribute prevents an empty interface called // _Rate from being created and used as the [default] interface // - [Guid("20c14d35-a61b-4c6a-a6ab-cb9f27997c45")] + [Guid("288838d1-bbf9-4ce0-9ee1-86ecf38b45c9")] [ClassInterface(ClassInterfaceType.None)] [ComVisible(true)] public class Rate : ASCOM.DeviceInterface.IRate @@ -65,11 +65,11 @@ namespace ASCOM.MeadeAutostar497 // both COM and .NET. The IAxisRates and IEnumerable interfaces provide // this polymorphism. // - // The Guid attribute sets the CLSID for ASCOM.MeadeAutostar497.AxisRates + // The Guid attribute sets the CLSID for ASCOM.Meade.net.AxisRates // The ClassInterface/None addribute prevents an empty interface called // _AxisRates from being created and used as the [default] interface // - [Guid("ac703603-bcfc-4d98-9de3-c2b9a165756f")] + [Guid("436de2dd-a77a-41ad-8a9e-14c3695f18f2")] [ClassInterface(ClassInterfaceType.None)] [ComVisible(true)] public class AxisRates : IAxisRates, IEnumerable @@ -100,7 +100,7 @@ namespace ASCOM.MeadeAutostar497 // TODO Initialize this array with any Primary axis rates that your driver may provide // Example: m_Rates = new Rate[] { new Rate(10.5, 30.2), new Rate(54.0, 43.6) } //this.rates = new Rate[0]; - this.rates = new Rate[] {new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4)}; + this.rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisSecondary: // TODO Initialize this array with any Secondary axis rates that your driver may provide @@ -146,7 +146,7 @@ namespace ASCOM.MeadeAutostar497 // both COM and .NET. The ITrackingRates and IEnumerable interfaces provide // this polymorphism. // - // The Guid attribute sets the CLSID for ASCOM.MeadeAutostar497.TrackingRates + // The Guid attribute sets the CLSID for ASCOM.Meade.net.TrackingRates // The ClassInterface/None addribute prevents an empty interface called // _TrackingRates from being created and used as the [default] interface // @@ -154,7 +154,7 @@ namespace ASCOM.MeadeAutostar497 // will work with this .NET 4.0 object. Changes to this have proved to be challenging // and it is strongly suggested that it isn't changed. // - [Guid("cb732953-8e5a-4bf0-b3b7-451edb74b5d5")] + [Guid("8e9aa30e-ab24-4a20-8af3-4a057defb1ff")] [ClassInterface(ClassInterfaceType.None)] [ComVisible(true)] public class TrackingRates : ITrackingRates, IEnumerable, IEnumerator @@ -176,7 +176,7 @@ namespace ASCOM.MeadeAutostar497 // the tracking rates supported by your telescope. The one value // (tracking rate) that MUST be supported is driveSidereal! // - this.trackingRates = new[] { DriveRates.driveSidereal }; + this.trackingRates = new[] { DriveRates.driveSidereal, DriveRates.driveLunar }; // TODO Initialize this array with any additional tracking rates that your driver may provide } diff --git a/MeadeAutostar497/ReadMe.htm b/Meade.net.Telescope/ReadMe.htm similarity index 100% rename from MeadeAutostar497/ReadMe.htm rename to Meade.net.Telescope/ReadMe.htm diff --git a/MeadeAutostar497/Resources/ASCOM.bmp b/Meade.net.Telescope/Resources/ASCOM.bmp similarity index 100% rename from MeadeAutostar497/Resources/ASCOM.bmp rename to Meade.net.Telescope/Resources/ASCOM.bmp diff --git a/MeadeAutostar497/StringExtensions.cs b/Meade.net.Telescope/StringExtensions.cs similarity index 51% rename from MeadeAutostar497/StringExtensions.cs rename to Meade.net.Telescope/StringExtensions.cs index e6a2cd1..85341c5 100644 --- a/MeadeAutostar497/StringExtensions.cs +++ b/Meade.net.Telescope/StringExtensions.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ASCOM.MeadeAutostar497 +namespace ASCOM.Meade.net { public static class StringExtensions { @@ -13,4 +7,4 @@ namespace ASCOM.MeadeAutostar497 return int.Parse(str); } } -} +} \ No newline at end of file diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs new file mode 100644 index 0000000..f16ff1b --- /dev/null +++ b/Meade.net.Telescope/Telescope.cs @@ -0,0 +1,1672 @@ +//tabs=4 +// -------------------------------------------------------------------------------- +// TODO fill in this information for your driver, then remove this line! +// +// ASCOM Telescope driver for Meade.net +// +// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam +// erat, sed diam voluptua. At vero eos et accusam et justo duo +// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata +// sanctus est Lorem ipsum dolor sit amet. +// +// Implements: ASCOM Telescope interface version: +// Author: (XXX) Your N. Here +// +// Edit Log: +// +// Date Who Vers Description +// ----------- --- ----- ------------------------------------------------------- +// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template +// -------------------------------------------------------------------------------- +// + + +// This is used to define code in the template that is specific to one class implementation +// unused code canbe deleted and this definition removed. +#define Telescope + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; + +using ASCOM; +using ASCOM.Astrometry; +using ASCOM.Astrometry.AstroUtils; +using ASCOM.Utilities; +using ASCOM.DeviceInterface; +using System.Globalization; +using System.Collections; +using System.Reflection; + +namespace ASCOM.Meade.net +{ + // + // Your driver's DeviceID is ASCOM.Meade.net.Telescope + // + // The Guid attribute sets the CLSID for ASCOM.Meade.net.Telescope + // The ClassInterface/None addribute prevents an empty interface called + // _Meade.net from being created and used as the [default] interface + // + // TODO Replace the not implemented exceptions with code to implement the function or + // throw the appropriate ASCOM exception. + // + + /// + /// ASCOM Telescope Driver for Meade.net. + /// + [Guid("d9fd4b3e-c4f1-48ac-a16f-d02eef30d86f")] + [ProgId("ASCOM.MeadeGeneric.Telescope")] + [ServedClassName("Meade.net Telescope")] + [ClassInterface(ClassInterfaceType.None)] + public class Telescope : ReferenceCountedObjectBase, ITelescopeV3 + { + /// + /// ASCOM DeviceID (COM ProgID) for this driver. + /// The DeviceID is used by ASCOM applications to load the driver at runtime. + /// + //internal static string driverID = "ASCOM.Meade.net.Telescope"; + internal static string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + + // TODO Change the descriptive string for your driver then remove this line + /// + /// Driver description that displays in the ASCOM Chooser. + /// + private static string driverDescription = "Meade Generic"; + + internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence + internal static string comPortDefault = "COM1"; + internal static string traceStateProfileName = "Trace Level"; + internal static string traceStateDefault = "false"; + + internal static string comPort; // Variables to hold the currrent device configuration + + /// + /// Private variable to hold the connected state + /// + private bool connectedState; + + /// + /// Private variable to hold an ASCOM Utilities object + /// + private Util utilities; + + /// + /// Private variable to hold an ASCOM AstroUtilities object to provide the Range method + /// + private AstroUtils astroUtilities; + + /// + /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) + /// + internal static TraceLogger tl; + + /// + /// Initializes a new instance of the class. + /// Must be public for COM registration. + /// + public Telescope() + { + tl = new TraceLogger("", "Meade.net"); + ReadProfile(); // Read device configuration from the ASCOM Profile store + + tl.LogMessage("Telescope", "Starting initialisation"); + + connectedState = false; // Initialise connected to false + utilities = new Util(); //Initialise util object + astroUtilities = new AstroUtils(); // Initialise astro utilities object + //TODO: Implement your additional construction here + + tl.LogMessage("Telescope", "Completed initialisation"); + } + + + // + // PUBLIC COM INTERFACE ITelescopeV3 IMPLEMENTATION + // + + #region Common properties and methods. + + /// + /// Displays the Setup Dialog form. + /// If the user clicks the OK button to dismiss the form, then + /// the new settings are saved, otherwise the old values are reloaded. + /// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED! + /// + public void SetupDialog() + { + SharedResources.SetupDialog(); + ReadProfile(); + //// consider only showing the setup dialog if not connected + //// or call a different dialog if connected + //if (IsConnected) + // System.Windows.Forms.MessageBox.Show("Already connected, just press OK"); + + //using (SetupDialogForm F = new SetupDialogForm()) + //{ + // var result = F.ShowDialog(); + // if (result == System.Windows.Forms.DialogResult.OK) + // { + // WriteProfile(); // Persist device configuration values to the ASCOM Profile store + // } + //} + } + + public ArrayList SupportedActions + { + get + { + tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); + return new ArrayList(); + } + } + + public string Action(string actionName, string actionParameters) + { + LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); + throw new ASCOM.ActionNotImplementedException("Action " + actionName + + " is not implemented by this driver"); + } + + public void CommandBlind(string command, bool raw) + { + CheckConnected("CommandBlind"); + // Call CommandString and return as soon as it finishes + //this.CommandString(command, raw); + SharedResources.SendBlind(command); + // or + //throw new ASCOM.MethodNotImplementedException("CommandBlind"); + // DO NOT have both these sections! One or the other + } + + public bool CommandBool(string command, bool raw) + { + CheckConnected("CommandBool"); + //string ret = CommandString(command, raw); + // TODO decode the return string and return true or false + // or + throw new ASCOM.MethodNotImplementedException("CommandBool"); + // DO NOT have both these sections! One or the other + } + + public string CommandString(string command, bool raw) + { + CheckConnected("CommandString"); + // it's a good idea to put all the low level communication with the device here, + // then all communication calls this function + // you need something to ensure that only one command is in progress at a time + return SharedResources.SendString(command); + //throw new ASCOM.MethodNotImplementedException("CommandString"); + } + + public void Dispose() + { + // Clean up the tracelogger and util objects + tl.Enabled = false; + tl.Dispose(); + tl = null; + utilities.Dispose(); + utilities = null; + astroUtilities.Dispose(); + astroUtilities = null; + } + + public bool Connected + { + get + { + LogMessage("Connected", "Get {0}", IsConnected); + return IsConnected; + } + set + { + tl.LogMessage("Connected", "Set {0}", value); + if (value == IsConnected) + return; + + if (value) + { + LogMessage("Connected Set", "Connecting to port {0}", comPort); + SharedResources.Connect("Serial"); + connectedState = true; + } + else + { + LogMessage("Connected Set", "Disconnecting from port {0}", comPort); + SharedResources.Disconnect("Serial"); + connectedState = false; + } + } + } + + public string Description + { + // TODO customise this device description + get + { + tl.LogMessage("Description Get", driverDescription); + return driverDescription; + } + } + + public string DriverInfo + { + get + { + Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + // TODO customise this driver description + string driverInfo = "Information about the driver itself. Version: " + + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, + version.Minor); + tl.LogMessage("DriverInfo Get", driverInfo); + return driverInfo; + } + } + + public string DriverVersion + { + get + { + Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + string driverVersion = + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); + tl.LogMessage("DriverVersion Get", driverVersion); + return driverVersion; + } + } + + public short InterfaceVersion + { + // set by the driver wizard + get + { + LogMessage("InterfaceVersion Get", "3"); + return Convert.ToInt16("3"); + } + } + + public string Name + { + get + { + //string name = "Short driver name - please customise"; + + //var telescopeProduceName = SharedResources.SendString(":GVP#"); + ////:GVP# Get Telescope Product Name + ////Returns: # + + //var firmwareVersion = SharedResources.SendString(":GVN#"); + ////:GVN# Get Telescope Firmware Number + ////Returns: dd.d# + + //string name = $"{telescopeProduceName} - {firmwareVersion}"; + string name = driverDescription; + tl.LogMessage("Name Get", name); + return name; + } + } + + #endregion + + #region ITelescope Implementation + + public void AbortSlew() + { + tl.LogMessage("AbortSlew", "Aborting slew"); + SharedResources.SendBlind(":Q#"); + } + + public AlignmentModes AlignmentMode + { + get + { + tl.LogMessage("AlignmentMode Get", "Getting alignmode"); + + const char ack = (char) 6; + + var alignmentString = SharedResources.SendChar(ack.ToString()); + + //todo implement GW Command + //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + //:GW# Get Scope Alignment Status + //Returns: # + // where: + //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial + //tracking: T - tracking, N - not tracking + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + + AlignmentModes alignmentMode; + switch (alignmentString) + { + case "A": + alignmentMode = AlignmentModes.algAltAz; + break; + case "P": + alignmentMode = AlignmentModes.algPolar; + break; + case "G": + alignmentMode = AlignmentModes.algGermanPolar; + break; + default: + throw new InvalidValueException( + $"unknown alignment returned from telescope: {alignmentString}"); + } + + tl.LogMessage("AlignmentMode Get", $"alignmode = {alignmentMode}"); + return alignmentMode; + } + set + { + switch (value) + { + case AlignmentModes.algAltAz: + SharedResources.SendBlind(":AA#"); + //:AA# Sets telescope the AltAz alignment mode + //Returns: nothing + break; + case AlignmentModes.algPolar: + case AlignmentModes.algGermanPolar: + SharedResources.SendBlind(":AP#"); + //:AP# Sets telescope to Polar alignment mode + //Returns: nothing + break; + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + + //:AL# Sets telescope to Land alignment mode + //Returns: nothing + } + } + + public double Altitude + { + get + { + //todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! + //var result = SharedResources.SendString(":GA#"); + ////:GA# Get Telescope Altitude + ////Returns: sDD* MM# or sDD*MM’SS# + ////The current scope altitude. The returned format depending on the current precision setting. + + //var alt = utilities.DMSToDegrees(result); + //tl.LogMessage("Altitude", $"{alt}"); + //return alt; + + tl.LogMessage("Altitude Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("Altitude", false); + } + } + + public double ApertureArea + { + get + { + tl.LogMessage("ApertureArea Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("ApertureArea", false); + } + } + + public double ApertureDiameter + { + get + { + tl.LogMessage("ApertureDiameter Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("ApertureDiameter", false); + } + } + + public bool AtHome + { + get + { + tl.LogMessage("AtHome", "Get - " + false.ToString()); + return false; + } + } + + private bool _atPark = false; + + public bool AtPark + { + get + { + tl.LogMessage("AtPark", "Get - " + _atPark); + return _atPark; + } + private set { _atPark = value; } + } + + public IAxisRates AxisRates(TelescopeAxes Axis) + { + tl.LogMessage("AxisRates", "Get - " + Axis.ToString()); + return new AxisRates(Axis); + } + + public double Azimuth + { + get + { + var result = SharedResources.SendString(":GZ#"); + //:GZ# Get telescope azimuth + //Returns: DDD*MM#T or DDD*MM’SS# + //The current telescope Azimuth depending on the selected precision. + + double az = utilities.DMSToDegrees(result); + + tl.LogMessage("Azimuth Get", $"{az}"); + return az; + } + } + + public bool CanFindHome + { + get + { + tl.LogMessage("CanFindHome", "Get - " + false.ToString()); + return false; + } + } + + public bool CanMoveAxis(TelescopeAxes Axis) + { + tl.LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); + switch (Axis) + { + case TelescopeAxes.axisPrimary: return true; //RA or AZ + case TelescopeAxes.axisSecondary: return true; //Dev or Alt + case TelescopeAxes.axisTertiary: return false; //rotator / derotator + default: throw new InvalidValueException("CanMoveAxis", Axis.ToString(), "0 to 2"); + } + } + + public bool CanPark + { + get + { + tl.LogMessage("CanPark", "Get - " + true.ToString()); + return true; + } + } + + public bool CanPulseGuide + { + get + { + tl.LogMessage("CanPulseGuide", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSetDeclinationRate + { + get + { + tl.LogMessage("CanSetDeclinationRate", "Get - " + false.ToString()); + return false; + } + } + + public bool CanSetGuideRates + { + get + { + tl.LogMessage("CanSetGuideRates", "Get - " + false.ToString()); + return false; + } + } + + public bool CanSetPark + { + get + { + tl.LogMessage("CanSetPark", "Get - " + false.ToString()); + return false; + } + } + + public bool CanSetPierSide + { + get + { + tl.LogMessage("CanSetPierSide", "Get - " + false.ToString()); + return false; + } + } + + public bool CanSetRightAscensionRate + { + get + { + tl.LogMessage("CanSetRightAscensionRate", "Get - " + false.ToString()); + return false; + } + } + + public bool CanSetTracking + { + get + { + tl.LogMessage("CanSetTracking", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSlew + { + get + { + tl.LogMessage("CanSlew", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSlewAltAz + { + get + { + tl.LogMessage("CanSlewAltAz", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSlewAltAzAsync + { + get + { + tl.LogMessage("CanSlewAltAzAsync", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSlewAsync + { + get + { + tl.LogMessage("CanSlewAsync", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSync + { + get + { + tl.LogMessage("CanSync", "Get - " + true.ToString()); + return true; + } + } + + public bool CanSyncAltAz + { + get + { + tl.LogMessage("CanSyncAltAz", "Get - " + false.ToString()); + return false; + } + } + + public bool CanUnpark + { + get + { + tl.LogMessage("CanUnpark", "Get - " + false.ToString()); + return false; + } + } + + public double Declination + { + get + { + var result = SharedResources.SendString(":GD#"); + //:GD# Get Telescope Declination. + //Returns: sDD* MM# or sDD*MM’SS# + //Depending upon the current precision setting for the telescope. + + double declination = utilities.DMSToDegrees(result); + + tl.LogMessage("Declination", "Get - " + utilities.DegreesToDMS(declination, ":", ":")); + return declination; + } + } + + public double DeclinationRate + { + get + { + double declination = 0.0; + tl.LogMessage("DeclinationRate", "Get - " + declination.ToString()); + return declination; + } + set + { + tl.LogMessage("DeclinationRate Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("DeclinationRate", true); + } + } + + public PierSide DestinationSideOfPier(double rightAscension, double declination) + { + tl.LogMessage("DestinationSideOfPier Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("DestinationSideOfPier", false); + } + + public bool DoesRefraction + { + get + { + tl.LogMessage("DoesRefraction Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("DoesRefraction", false); + } + set + { + tl.LogMessage("DoesRefraction Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("DoesRefraction", true); + } + } + + public EquatorialCoordinateType EquatorialSystem + { + get + { + EquatorialCoordinateType equatorialSystem = EquatorialCoordinateType.equTopocentric; + tl.LogMessage("DeclinationRate", "Get - " + equatorialSystem.ToString()); + return equatorialSystem; + } + } + + public void FindHome() + { + tl.LogMessage("FindHome", "Not implemented"); + throw new ASCOM.MethodNotImplementedException("FindHome"); + } + + public double FocalLength + { + get + { + tl.LogMessage("FocalLength Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("FocalLength", false); + } + } + + public double GuideRateDeclination + { + get + { + tl.LogMessage("GuideRateDeclination Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", false); + } + set + { + tl.LogMessage("GuideRateDeclination Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", true); + } + } + + public double GuideRateRightAscension + { + get + { + tl.LogMessage("GuideRateRightAscension Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", false); + } + set + { + tl.LogMessage("GuideRateRightAscension Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", true); + } + } + + public bool IsPulseGuiding + { + get + { + tl.LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); + //throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); + return false; + } + } + + private bool _movingPrimary; + private bool _movingSecondary; + + public void MoveAxis(TelescopeAxes axis, double rate) + { + tl.LogMessage("MoveAxis", $"Axis={axis} rate={rate}"); + + var absRate = Math.Abs(rate); + + switch (absRate) + { + case 0: + //do nothing, it's ok this time as we're halting the slew. + break; + case 1: + SharedResources.SendBlind(":RG#"); + //:RG# Set Slew rate to Guiding Rate (slowest) + //Returns: Nothing + break; + case 2: + SharedResources.SendBlind(":RC#"); + //:RC# Set Slew rate to Centering rate (2nd slowest) + //Returns: Nothing + break; + case 3: + SharedResources.SendBlind(":RM#"); + //:RM# Set Slew rate to Find Rate (2nd Fastest) + //Returns: Nothing + break; + case 4: + SharedResources.SendBlind(":RS#"); + //:RS# Set Slew rate to max (fastest) + //Returns: Nothing + break; + default: + throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); + } + + switch (axis) + { + case TelescopeAxes.axisPrimary: + if (rate == 0) + { + _movingPrimary = false; + SharedResources.SendBlind(":Qe#"); + //:Qe# Halt eastward Slews + //Returns: Nothing + SharedResources.SendBlind(":Qw#"); + //:Qw# Halt westward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SharedResources.SendBlind(":Me#"); + //:Me# Move Telescope East at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + else + { + SharedResources.SendBlind(":Mw#"); + //:Mw# Move Telescope West at current slew rate + //Returns: Nothing + _movingPrimary = true; + } + + break; + case TelescopeAxes.axisSecondary: + if (rate == 0) + { + _movingSecondary = false; + SharedResources.SendBlind(":Qn#"); + //:Qn# Halt northward Slews + //Returns: Nothing + SharedResources.SendBlind(":Qs#"); + //:Qs# Halt southward Slews + //Returns: Nothing + } + else if (rate > 0) + { + SharedResources.SendBlind(":Mn#"); + //:Mn# Move Telescope North at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + else + { + SharedResources.SendBlind(":Ms#"); + //:Ms# Move Telescope South at current slew rate + //Returns: Nothing + _movingSecondary = true; + } + + break; + default: + throw new ASCOM.MethodNotImplementedException("Can not move this axis."); + } + } + + public void Park() + { + tl.LogMessage("Park", "Parking telescope"); + + if (AtPark) + return; + + SharedResources.SendBlind(":hP#"); + AtPark = true; + } + + private readonly bool + _userNewerPulseGuiding = true; //todo make this a device setting based on firmware revision + + public void PulseGuide(GuideDirections direction, int duration) + { + tl.LogMessage("PulseGuide", $"pulse guide direction {direction} duration {duration}"); + string d = string.Empty; + switch (direction) + { + case GuideDirections.guideEast: + d = "e"; + break; + case GuideDirections.guideNorth: + d = "n"; + break; + case GuideDirections.guideSouth: + d = "s"; + break; + case GuideDirections.guideWest: + d = "w"; + break; + } + + if (_userNewerPulseGuiding) + { + SharedResources.SendBlind($":Mg{d}{duration:0000}#"); + utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed + } + else + { + SharedResources.Lock(() => + { + SharedResources.SendBlind(":RG#"); //Make sure we are at guide rate + SharedResources.SendBlind($":M{d}#"); + utilities.WaitForMilliseconds(duration); + SharedResources.SendBlind($":Q{d}#"); + }); + } + } + + public double RightAscension + { + get + { + var result = SharedResources.SendString(":GR#"); + //:GR# Get Telescope RA + //Returns: HH: MM.T# or HH:MM:SS# + //Depending which precision is set for the telescope + + double rightAscension = utilities.HMSToHours(result); + + tl.LogMessage("RightAscension", "Get - " + utilities.HoursToHMS(rightAscension)); + return rightAscension; + } + } + + public double RightAscensionRate + { + get + { + double rightAscensionRate = 0.0; + tl.LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString()); + return rightAscensionRate; + } + set + { + tl.LogMessage("RightAscensionRate Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("RightAscensionRate", true); + } + } + + public void SetPark() + { + tl.LogMessage("SetPark", "Not implemented"); + throw new ASCOM.MethodNotImplementedException("SetPark"); + } + + public PierSide SideOfPier + { + get + { + tl.LogMessage("SideOfPier Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SideOfPier", false); + } + set + { + tl.LogMessage("SideOfPier Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SideOfPier", true); + } + } + + public double SiderealTime + { + get + { + // Now using NOVAS 3.1 + double siderealTime = 0.0; + using (var novas = new ASCOM.Astrometry.NOVAS.NOVAS31()) + { + var jd = utilities.DateUTCToJulian(DateTime.UtcNow); + novas.SiderealTime(jd, 0, novas.DeltaT(jd), + ASCOM.Astrometry.GstType.GreenwichApparentSiderealTime, + ASCOM.Astrometry.Method.EquinoxBased, + ASCOM.Astrometry.Accuracy.Reduced, ref siderealTime); + } + + // Allow for the longitude + siderealTime += SiteLongitude / 360.0 * 24.0; + + // Reduce to the range 0 to 24 hours + siderealTime = astroUtilities.ConditionRA(siderealTime); + + tl.LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); + return siderealTime; + } + } + + public double SiteElevation + { + get + { + tl.LogMessage("SiteElevation Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SiteElevation", false); + } + set + { + tl.LogMessage("SiteElevation Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SiteElevation", true); + } + } + + public double SiteLatitude + { + get + { + var latitude = SharedResources.SendString(":Gt#"); + + var siteLatitude = utilities.DMSToDegrees(latitude); + tl.LogMessage("SiteLatitude Get", $"{utilities.DegreesToDMS(siteLatitude)}"); + return siteLatitude; + } + set + { + tl.LogMessage("SiteLatitude Set", $"{utilities.DegreesToDMS(value)}"); + + if (value > 90) + throw new InvalidValueException("Latitude cannot be greater than 90 degrees."); + + if (value < -90) + throw new InvalidValueException("Latitude cannot be less than -90 degrees."); + + int d = Convert.ToInt32(Math.Floor(value)); + int m = Convert.ToInt32(60 * (value - d)); + + var result = SharedResources.SendChar($":Sts{d:00}*{m:00}#"); + if (result != "1") + throw new InvalidOperationException("Failed to set site latitude."); + } + } + + public double SiteLongitude + { + get + { + var longitude = SharedResources.SendString(":Gg#"); + double siteLongitude = utilities.DMSToDegrees(longitude); + + if (siteLongitude > 180) + siteLongitude = siteLongitude - 360; + + tl.LogMessage("SiteLongitude Get", $"{utilities.DegreesToDMS(siteLongitude)}"); + return siteLongitude; + } + set + { + tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(value)}"); + if (value > 180) + throw new InvalidValueException("Longitude cannot be greater than 180 degrees."); + + if (value < -180) + throw new InvalidValueException("Longitude cannot be lower than -180 degrees."); + + int d = Convert.ToInt32(Math.Floor(value)); + int m = Convert.ToInt32(60 * (value - d)); + + var result = SharedResources.SendChar($":Sg{d:000}*{m:00}#"); + if (result != "1") + throw new InvalidOperationException("Failed to set site longitude."); + } + } + + public short SlewSettleTime + { + get + { + tl.LogMessage("SlewSettleTime Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", false); + } + set + { + tl.LogMessage("SlewSettleTime Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", true); + } + } + + public void SlewToAltAz(double azimuth, double altitude) + { + tl.LogMessage("SlewToAltAz", $"Az=~{azimuth} Alt={altitude}"); + + SlewToAltAzAsync(azimuth, altitude); + + while (Slewing) //wait for slew to complete + { + utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); + } + } + + private double TargetAltitude + { + set + { + if (value > 90) + throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); + + if (value < 0) + throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + + + var dms = utilities.DegreesToDMS(value, "*", "'", ".", 2); + var s = value < 0 ? '-' : '+'; + + var result = SharedResources.SendChar($":Sa{s}{dms}#"); + //:SasDD*MM# + //Set target object altitude to sDD*MM# or sDD*MM’SS# [LX 16”, Autostar, Autostar II] + //Returns: + //1 Object within slew range + //0 Object out of slew range + + if (result == "0") + throw new ASCOM.InvalidOperationException("Target altitude out of slew range"); + } + } + + private double TargetAzimuth + { + set + { + if (value >= 360) + throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); + + if (value < 0) + throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + + var dms = utilities.DegreesToDM(value, "*", ":", 2); + + var result = SharedResources.SendChar($":Sd{dms}#"); + //:SzDDD*MM# + //Sets the target Object Azimuth[LX 16” and Autostar II only] + //Returns: + //0 – Invalid + //1 - Valid + + if (result == "0") + throw new ASCOM.InvalidOperationException("Target Azimuth out of slew range"); + + } + } + + public void SlewToAltAzAsync(double azimuth, double altitude) + { + tl.LogMessage("SlewToAltAzAsync", $"Az=~{azimuth} Alt={altitude}"); + + SharedResources.Lock(() => + { + TargetAltitude = altitude; + TargetAzimuth = azimuth; + + DoSlewAsync(false); + }); + } + + private void DoSlewAsync(bool polar) + { + SharedResources.Lock(() => + { + switch (polar) + { + case true: + var response = SharedResources.SendChar(":MS#"); + //:MS# Slew to Target Object + //Returns: + //0 Slew is Possible + //1# Object Below Horizon w/string message + //2# Object Below Higher w/string message + + switch (response) + { + case "0": + //We're slewing everything should be working just fine. + break; + case "1": + //Below Horizon + string belowHorizonMessage = SharedResources.ReadTerminated(); + throw new ASCOM.InvalidOperationException(belowHorizonMessage); + case "2": + //Below Horizon + string belowMinimumElevationMessage = SharedResources.ReadTerminated(); + throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); + default: + throw new ASCOM.DriverException("This error should not happen"); + + } + + break; + case false: + var maResponse = SharedResources.SendChar(":MA#"); + //:MA# Autostar, LX 16”, Autostar II – Slew to target Alt and Az + //Returns: + //0 - No fault + //1 – Fault + // LX200 – Not supported + + if (maResponse == "1") + { + throw new ASCOM.InvalidOperationException("fault"); + } + + break; + } + }); + } + + public void SlewToCoordinates(double rightAscension, double declination) + { + tl.LogMessage("SlewToCoordinates", $"Ra={rightAscension}, Dec={declination}"); + SlewToCoordinatesAsync(rightAscension, declination); + + while (Slewing) //wait for slew to complete + { + utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); + } + } + + public void SlewToCoordinatesAsync(double rightAscension, double declination) + { + tl.LogMessage("SlewToCoordinatesAsync", $"Ra={rightAscension}, Dec={declination}"); + + SharedResources.Lock(() => + { + TargetRightAscension = rightAscension; + TargetDeclination = declination; + + DoSlewAsync(true); + } + ); + } + + public void SlewToTarget() + { + tl.LogMessage("SlewToTarget", "Executing"); + SlewToTargetAsync(); + + while (Slewing) + { + utilities.WaitForMilliseconds(200); + } + } + + private const double INVALID_PARAMETER = -1000; + + public void SlewToTargetAsync() + { + if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER) + throw new ASCOM.InvalidOperationException("No target selected to slew to."); + + DoSlewAsync(true); + } + + private bool movingAxis() + { + return _movingPrimary || _movingSecondary; + } + + public bool Slewing + { + get + { + if (!Connected) return false; + + + if (movingAxis()) + return true; + + var result = SharedResources.SendString(":D#"); + bool isSlewing = result != string.Empty; + + tl.LogMessage("Slewing Get", $"Result = {isSlewing}"); + return isSlewing; + } + } + + public void SyncToAltAz(double azimuth, double altitude) + { + tl.LogMessage("SyncToAltAz", "Not implemented"); + throw new ASCOM.MethodNotImplementedException("SyncToAltAz"); + } + + public void SyncToCoordinates(double rightAscension, double declination) + { + tl.LogMessage("SyncToCoordinates", $"RA={rightAscension} Dec={declination}"); + + SharedResources.Lock(() => + { + TargetRightAscension = rightAscension; + TargetDeclination = declination; + + SyncToTarget(); + }); + } + + public void SyncToTarget() + { + tl.LogMessage("SyncToTarget", "Executing"); + var result = SharedResources.SendString(":CM#"); + //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. + //Returns: + //LX200's - a "#" terminated string with the name of the object that was synced. + // Autostars & Autostar II - At static string: " M31 EX GAL MAG 3.5 SZ178.0'#" + + if (result == string.Empty) + throw new ASCOM.InvalidOperationException("Unable to perform sync"); + } + + private double _targetDeclination = INVALID_PARAMETER; + public double TargetDeclination + { + get + { + if (_targetDeclination == INVALID_PARAMETER) + throw new ASCOM.InvalidOperationException("Target not set"); + + //var result = SerialPort.CommandTerminated(":Gd#", "#"); + ////:Gd# Get Currently Selected Object/Target Declination + ////Returns: sDD* MM# or sDD*MM’SS# + ////Depending upon the current precision setting for the telescope. + + //double targetDec = DmsToDouble(result); + + //return targetDec; + + tl.LogMessage("TargetDeclination Get", $"{_targetDeclination}"); + return _targetDeclination; + } + set + { + tl.LogMessage("TargetDeclination Set", $"{value}"); + + //todo implement low precision version of this. + if (value > 90) + throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); + + if (value < -90) + throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); + + + var dms = utilities.DegreesToDMS(value, "*", ":", ":", 2); + var s = value < 0 ? '-' : '+'; + + var result = SharedResources.SendChar($":Sd{s}{dms}#"); + //:SdsDD*MM# + //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting + //Returns: + //1 - Dec Accepted + //0 – Dec invalid + + if (result == "0") + { + throw new ASCOM.InvalidOperationException("Target declination invalid"); + } + + _targetDeclination = value; + } + } + + private double _targetRightAscension = INVALID_PARAMETER; + public double TargetRightAscension + { + get + { + if (_targetRightAscension == INVALID_PARAMETER) + throw new ASCOM.InvalidOperationException("Target not set"); + + //var result = SerialPort.CommandTerminated(":Gr#", "#"); + ////:Gr# Get current/target object RA + ////Returns: HH: MM.T# or HH:MM:SS + ////Depending upon which precision is set for the telescope + + //double targetRa = HmsToDouble(result); + //return targetRa; + + tl.LogMessage("TargetRightAscension Get", $"{_targetRightAscension}"); + return _targetRightAscension; + } + set + { + tl.LogMessage("TargetRightAscension Set", $"{value}"); + + if (value < 0) + throw new InvalidValueException("Right ascension value cannot be below 0"); + + if (value >= 24) + throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); + + + //todo implement the low precision version + + var hms = utilities.HoursToHMS(value, ":", ":", ":", 2); + var response = SharedResources.SendChar($":Sr{hms}#"); + //:SrHH:MM.T# + //:SrHH:MM:SS# + //Set target object RA to HH:MM.T or HH: MM: SS depending on the current precision setting. + // Returns: + //0 – Invalid + //1 - Valid + + if (response == "0") + throw new InvalidOperationException("Failed to set TargetRightAscension."); + + _targetRightAscension = value; + } + } + + private bool _tracking = true; + public bool Tracking + { + get + { + tl.LogMessage("Tracking", $"Get - {_tracking}"); + return _tracking; + } + set + { + tl.LogMessage($"Tracking Set", $"{value}"); + _tracking = value; + } + } + + private DriveRates _trackingRate = DriveRates.driveSidereal; + public DriveRates TrackingRate + { + get + { + //todo implement this with the GW command + //var result = SerialPort.CommandTerminated(":GT#", "#"); + + //double rate = double.Parse(result); + + + //if (rate == 60.1) + // return DriveRates.driveLunar; + //else if (rate == 60.1) + // return DriveRates.driveSidereal; + + //return DriveRates.driveKing; + tl.LogMessage("TrackingRate Get", $"{_trackingRate}"); + return _trackingRate; + } + set + { + tl.LogMessage("TrackingRate Set", $"{value}"); + + switch (value) + { + case DriveRates.driveSidereal: + SharedResources.SendBlind(":TQ#"); + //:TQ# Selects sidereal tracking rate + //Returns: Nothing + break; + case DriveRates.driveLunar: + SharedResources.SendBlind(":TL#"); + //:TL# Set Lunar Tracking Rage + //Returns: Nothing + break; + //case DriveRates.driveSolar: + // SerialPort.Command(":TS#"); + // //:TS# Select Solar tracking rate. [LS Only] + // //Returns: Nothing + // break; + //case DriveRates.driveKing: + //:TM# Select custom tracking rate [ no-op in Autostar II] + //Returns: Nothing + // break; + default: + throw new ArgumentOutOfRangeException(nameof(value), value, null); + } + + _trackingRate = value; + } + } + + public ITrackingRates TrackingRates + { + get + { + ITrackingRates trackingRates = new TrackingRates(); + tl.LogMessage("TrackingRates", "Get - "); + foreach (DriveRates driveRate in trackingRates) + { + tl.LogMessage("TrackingRates", "Get - " + driveRate.ToString()); + } + return trackingRates; + } + } + + private TimeSpan GetUtcCorrection() + { + string utcOffSet = SharedResources.SendString(":GG#"); + double utcOffsetHours = double.Parse(utcOffSet); + TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); + return utcCorrection; + } + + private class TelescopeDateDetails + { + public string telescopeDate { get; set; } + public string telescopeTime { get; set; } + public TimeSpan utcCorrection { get; set; } + } + + public DateTime UTCDate + { + get + { + tl.LogMessage("UTCDate", "Get started"); + + TelescopeDateDetails telescopeDateDetails = SharedResources.Lock(() => + { + TelescopeDateDetails tdd = new TelescopeDateDetails(); + tdd.telescopeDate = SharedResources.SendString(":GC#"); + tdd.telescopeTime = SharedResources.SendString(":GL#"); + tdd.utcCorrection = GetUtcCorrection(); + + return tdd; + }); + + int month = telescopeDateDetails.telescopeDate.Substring(0, 2).ToInteger(); + int day = telescopeDateDetails.telescopeDate.Substring(3, 2).ToInteger(); + int year = telescopeDateDetails.telescopeDate.Substring(6, 2).ToInteger(); + + if (year < 2000) //todo fix this hack that will create a Y2K100 bug + { + year = year + 2000; + } + + int hour = telescopeDateDetails.telescopeTime.Substring(0, 2).ToInteger(); + int minute = telescopeDateDetails.telescopeTime.Substring(3, 2).ToInteger(); + int second = telescopeDateDetails.telescopeTime.Substring(6, 2).ToInteger(); + + //Todo is this telescope local time, or real utc? + var utcDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + + telescopeDateDetails.utcCorrection; + + tl.LogMessage("UTCDate", "Get - " + utcDate.ToString("MM/dd/yy HH:mm:ss")); + + return utcDate; + } + set + { + tl.LogMessage("UTCDate", "Set - " + value.ToString("MM/dd/yy HH:mm:ss")); + + SharedResources.Lock(() => + { + var utcCorrection = GetUtcCorrection(); + var localDateTime = value - utcCorrection; + + //Todo is this telescope local time, or real utc? + var timeResult = SharedResources.SendChar($":SL{localDateTime:HH:mm:ss}#"); + if (timeResult != "1") + { + throw new InvalidOperationException("Failed to set local time"); + } + + var dateResult = SharedResources.SendChar($":SC{localDateTime:MM/dd/yy}#"); + if (dateResult != "1") + { + throw new InvalidOperationException("Failed to set local date"); + } + + //throwing away these two strings which represent + SharedResources.ReadTerminated(); //Updating Planetary Data# + SharedResources.ReadTerminated(); // # + }); + } + } + + public void Unpark() + { + tl.LogMessage("Unpark", "Not implemented"); + throw new ASCOM.MethodNotImplementedException("Unpark"); + } + + #endregion + + #region Private properties and methods + // here are some useful properties and methods that can be used as required + // to help with driver development + + #region ASCOM Registration + + // Register or unregister driver for ASCOM. This is harmless if already + // registered or unregistered. + // + /// + /// Register or unregister the driver with the ASCOM Platform. + /// This is harmless if the driver is already registered/unregistered. + /// + /// If true, registers the driver, otherwise unregisters it. + private static void RegUnregASCOM(bool bRegister) + { + using (var P = new ASCOM.Utilities.Profile()) + { + P.DeviceType = "Telescope"; + if (bRegister) + { + P.Register(driverID, driverDescription); + } + else + { + P.Unregister(driverID); + } + } + } + + /// + /// This function registers the driver with the ASCOM Chooser and + /// is called automatically whenever this class is registered for COM Interop. + /// + /// Type of the class being registered, not used. + /// + /// This method typically runs in two distinct situations: + /// + /// + /// In Visual Studio, when the project is successfully built. + /// For this to work correctly, the option Register for COM Interop + /// must be enabled in the project settings. + /// + /// During setup, when the installer registers the assembly for COM Interop. + /// + /// This technique should mean that it is never necessary to manually register a driver with ASCOM. + /// + [ComRegisterFunction] + public static void RegisterASCOM(Type t) + { + RegUnregASCOM(true); + } + + /// + /// This function unregisters the driver from the ASCOM Chooser and + /// is called automatically whenever this class is unregistered from COM Interop. + /// + /// Type of the class being registered, not used. + /// + /// This method typically runs in two distinct situations: + /// + /// + /// In Visual Studio, when the project is cleaned or prior to rebuilding. + /// For this to work correctly, the option Register for COM Interop + /// must be enabled in the project settings. + /// + /// During uninstall, when the installer unregisters the assembly from COM Interop. + /// + /// This technique should mean that it is never necessary to manually unregister a driver from ASCOM. + /// + [ComUnregisterFunction] + public static void UnregisterASCOM(Type t) + { + RegUnregASCOM(false); + } + + #endregion + + /// + /// Returns true if there is a valid connection to the driver hardware + /// + private bool IsConnected + { + get + { + // TODO check that the driver hardware connection exists and is connected to the hardware + return connectedState; + } + } + + /// + /// Use this function to throw an exception if we aren't connected to the hardware + /// + /// + private void CheckConnected(string message) + { + if (!IsConnected) + { + throw new ASCOM.NotConnectedException(message); + } + } + + /// + /// Read the device configuration from the ASCOM Profile store + /// + internal void ReadProfile() + { + var profileProperties = SharedResources.ReadProfile(); + tl.Enabled = profileProperties.TraceLogger; + comPort = profileProperties.ComPort; + } + + /// + /// Log helper function that takes formatted strings and arguments + /// + /// + /// + /// + internal static void LogMessage(string identifier, string message, params object[] args) + { + var msg = string.Format(message, args); + tl.LogMessage(identifier, msg); + } + #endregion + } +} diff --git a/MeadeAutostar497/app.config b/Meade.net.Telescope/app.config similarity index 93% rename from MeadeAutostar497/app.config rename to Meade.net.Telescope/app.config index dd30df1..56895a9 100644 --- a/MeadeAutostar497/app.config +++ b/Meade.net.Telescope/app.config @@ -5,4 +5,4 @@
    - + diff --git a/Meade.net.focuser/ASCOM.ico b/Meade.net.focuser/ASCOM.ico new file mode 100644 index 0000000000000000000000000000000000000000..9bf8f4110f20bfdde720ab5e04def9b01b414268 GIT binary patch literal 125783 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 literal 0 HcmV?d00001 diff --git a/Meade.net.focuser/ASCOMDriverTemplate.snk b/Meade.net.focuser/ASCOMDriverTemplate.snk new file mode 100644 index 0000000000000000000000000000000000000000..5ab294522d027053efbc99370de86ab44f7d999f GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50096o@;lSCg(u0Cs*BuyKR9r^P7mA>i6=N| z*}>a~-mZ)Ls%FAV}Sq^{wX`Ye#nGu3i15cdI?<@%KFXx_Qu1Q zN>O%rp3WAnZ)@;RL`$uw-03doE|FK(K%8USc|TsTgk^<-c1|7cI%~?31LIyTy58J< z(taLe4Y_8Nh}Or>g|R?a+P~+Jr3m-}1VHV}8MG@t3cStINbjmS^i<3>k4h+hz~GNt z!8WZr{qM3aNd*4ISiND;`zskEKm-${7citI0lHIW8_tw=H7N}rUVoSh@Z0OAZLl6E zg4N4tVSk`gTDSF;w7bcn&{MOEFqqy=Ox~K)dzZP}jp0K6s4Gh^sqMDcqM}~JxMG*P z5rI=Fs#&gf4uxH-ATi-cxXakgqSr>inHh9jdLju(8XosCtg!90t5C7nYMaYhglwJV z1mep!noQ3{J9amy(`{qn2B&nJ#uy{GMKAhs)#Zvf}wC>k)weHP-6 z7D;L&Jk#(ossUu=V0_*yfJFz4$gnsHpzT~Y)$N?L)gSilWU%u5(kvc4y5ee=$CX^9 zq+$TozA{2;O}JYE11w~)ND9yKepmrn_1VTcdv35sO)b%cS3!i<;&LB(eJ&j~^ktgh i2?jBBQqyjQmCuueJbfE~HZ)z<*Si*L2C5Qx(CwX1izKQ5 literal 0 HcmV?d00001 diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs new file mode 100644 index 0000000..aa50a5a --- /dev/null +++ b/Meade.net.focuser/Focuser.cs @@ -0,0 +1,570 @@ +//tabs=4 +// -------------------------------------------------------------------------------- +// TODO fill in this information for your driver, then remove this line! +// +// ASCOM Focuser driver for Meade.net +// +// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam +// erat, sed diam voluptua. At vero eos et accusam et justo duo +// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata +// sanctus est Lorem ipsum dolor sit amet. +// +// Implements: ASCOM Focuser interface version: +// Author: (XXX) Your N. Here +// +// Edit Log: +// +// Date Who Vers Description +// ----------- --- ----- ------------------------------------------------------- +// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template +// -------------------------------------------------------------------------------- +// + + +// This is used to define code in the template that is specific to one class implementation +// unused code canbe deleted and this definition removed. +#define Focuser + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; + +using ASCOM; +using ASCOM.Astrometry; +using ASCOM.Astrometry.AstroUtils; +using ASCOM.Utilities; +using ASCOM.DeviceInterface; +using System.Globalization; +using System.Collections; +using System.Reflection; +using ASCOM.Utilities.Interfaces; + +namespace ASCOM.Meade.net +{ + // + // Your driver's DeviceID is ASCOM.Meade.net.Focuser + // + // The Guid attribute sets the CLSID for ASCOM.Meade.net.Focuser + // The ClassInterface/None addribute prevents an empty interface called + // _Meade.net from being created and used as the [default] interface + // + // TODO Replace the not implemented exceptions with code to implement the function or + // throw the appropriate ASCOM exception. + // + + /// + /// ASCOM Focuser Driver for Meade.net. + /// + [Guid("a32ac647-bf0f-42f9-8ab0-d166fa5884ad")] + [ProgId("ASCOM.MeadeGeneric.focuser")] + [ServedClassName("Meade.net Focuser")] + [ClassInterface(ClassInterfaceType.None)] + public class Focuser : ReferenceCountedObjectBase, IFocuserV3 + { + /// + /// ASCOM DeviceID (COM ProgID) for this driver. + /// The DeviceID is used by ASCOM applications to load the driver at runtime. + /// + //internal static string driverID = "ASCOM.Meade.net.Focuser"; + internal static string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + // TODO Change the descriptive string for your driver then remove this line + /// + /// Driver description that displays in the ASCOM Chooser. + /// + private static string driverDescription = "Meade Generic"; + + internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence + internal static string comPortDefault = "COM1"; + internal static string traceStateProfileName = "Trace Level"; + internal static string traceStateDefault = "false"; + + internal static string comPort; // Variables to hold the currrent device configuration + + /// + /// Private variable to hold the connected state + /// + private bool connectedState; + + /// + /// Private variable to hold an ASCOM Utilities object + /// + private Util utilities; + + /// + /// Private variable to hold an ASCOM AstroUtilities object to provide the Range method + /// + private AstroUtils astroUtilities; + + /// + /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) + /// + internal static TraceLogger tl; + + /// + /// Initializes a new instance of the class. + /// Must be public for COM registration. + /// + public Focuser() + { + tl = new TraceLogger("", "Meade.net"); + ReadProfile(); // Read device configuration from the ASCOM Profile store + + tl.LogMessage("Focuser", "Starting initialisation"); + + connectedState = false; // Initialise connected to false + utilities = new Util(); //Initialise util object + astroUtilities = new AstroUtils(); // Initialise astro utilities object + + tl.LogMessage("Focuser", "Completed initialisation"); + } + + + // + // PUBLIC COM INTERFACE IFocuserV3 IMPLEMENTATION + // + + #region Common properties and methods. + + /// + /// Displays the Setup Dialog form. + /// If the user clicks the OK button to dismiss the form, then + /// the new settings are saved, otherwise the old values are reloaded. + /// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED! + /// + public void SetupDialog() + { + SharedResources.SetupDialog(); + ReadProfile(); + } + + public ArrayList SupportedActions + { + get + { + tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); + return new ArrayList(); + } + } + + public string Action(string actionName, string actionParameters) + { + LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); + throw new ASCOM.ActionNotImplementedException("Action " + actionName + " is not implemented by this driver"); + } + + public void CommandBlind(string command, bool raw) + { + CheckConnected("CommandBlind"); + // Call CommandString and return as soon as it finishes + //this.CommandString(command, raw); + SharedResources.SendBlind(command); + // or + //throw new ASCOM.MethodNotImplementedException("CommandBlind"); + // DO NOT have both these sections! One or the other + } + + public bool CommandBool(string command, bool raw) + { + CheckConnected("CommandBool"); + //string ret = CommandString(command, raw); + // TODO decode the return string and return true or false + // or + throw new ASCOM.MethodNotImplementedException("CommandBool"); + // DO NOT have both these sections! One or the other + } + + public string CommandString(string command, bool raw) + { + CheckConnected("CommandString"); + // it's a good idea to put all the low level communication with the device here, + // then all communication calls this function + // you need something to ensure that only one command is in progress at a time + return SharedResources.SendString(command); + + throw new ASCOM.MethodNotImplementedException("CommandString"); + } + + public void Dispose() + { + // Clean up the tracelogger and util objects + tl.Enabled = false; + tl.Dispose(); + tl = null; + utilities.Dispose(); + utilities = null; + astroUtilities.Dispose(); + astroUtilities = null; + } + + public bool Connected + { + get + { + LogMessage("Connected", "Get {0}", IsConnected); + return IsConnected; + } + set + { + tl.LogMessage("Connected", "Set {0}", value); + if (value == IsConnected) + return; + + if (value) + { + LogMessage("Connected Set", "Connecting to port {0}", comPort); + SharedResources.Connect("Serial"); + connectedState = true; + } + else + { + LogMessage("Connected Set", "Disconnecting from port {0}", comPort); + SharedResources.Disconnect("Serial"); + connectedState = false; + } + } + } + + public string Description + { + // TODO customise this device description + get + { + tl.LogMessage("Description Get", driverDescription); + return driverDescription; + } + } + + public string DriverInfo + { + get + { + Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + // TODO customise this driver description + string driverInfo = "Information about the driver itself. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); + tl.LogMessage("DriverInfo Get", driverInfo); + return driverInfo; + } + } + + public string DriverVersion + { + get + { + Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + string driverVersion = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); + tl.LogMessage("DriverVersion Get", driverVersion); + return driverVersion; + } + } + + public short InterfaceVersion + { + // set by the driver wizard + get + { + LogMessage("InterfaceVersion Get", "3"); + return Convert.ToInt16("3"); + } + } + + public string Name + { + get + { + //string name = "Short driver name - please customise"; + string name = driverDescription; + tl.LogMessage("Name Get", name); + return name; + } + } + + #endregion + + #region IFocuser Implementation + + public bool Absolute + { + get + { + tl.LogMessage("Absolute Get", false.ToString()); + return false; // This is a relative focuser + } + } + + public void Halt() + { + tl.LogMessage("Halt", "Halting"); + SharedResources.SendBlind(":FQ#"); + //:FQ# Halt Focuser Motion + //Returns: Nothing + } + + public bool IsMoving + { + get + { + tl.LogMessage("IsMoving Get", false.ToString()); + return false; // This focuser always moves instantaneously so no need for IsMoving ever to be True + } + } + + public bool Link + { + get + { + tl.LogMessage("Link Get", this.Connected.ToString()); + return this.Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility + } + set + { + tl.LogMessage("Link Set", value.ToString()); + this.Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility + } + } + + private readonly int _maxIncrement = 7000; + public int MaxIncrement + { + get + { + tl.LogMessage("MaxIncrement Get", _maxIncrement.ToString()); + return _maxIncrement; // Maximum change in one move + } + } + + private readonly int _maxStep = 7000; + public int MaxStep + { + get + { + tl.LogMessage("MaxStep Get", _maxStep.ToString()); + return _maxStep; + } + } + + public void Move(int Position) + { + tl.LogMessage("Move", Position.ToString()); + + //todo implement backlash compensation + //todo implement direction reverse + //todo implement dynamic braking + + if (Position < -MaxIncrement || Position > MaxIncrement) + { + throw new ASCOM.InvalidValueException($"position out of range {-MaxIncrement} < {Position} < {MaxIncrement}"); + } + + if (Position == 0) + return; + + if (Position > 0) + { + //desired move direction is out + MoveFocuser(true, Math.Abs(Position)); + } + else + { + //desired move direction is in + MoveFocuser(false, Math.Abs(Position)); + } + } + + private void MoveFocuser(bool directionOut, int steps) + { + SharedResources.Lock(() => + { + SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#"); + //:F+# Start Focuser moving inward (toward objective) + //Returns: None + + //:F-# Start Focuser moving outward (away from objective) + //Returns: None + + utilities.WaitForMilliseconds(steps); + + Halt(); + }); + } + + public int Position + { + get + { + throw new ASCOM.PropertyNotImplementedException("Position", false); + //return focuserPosition; // Return the focuser position + } + } + + public double StepSize + { + get + { + tl.LogMessage("StepSize Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("StepSize", false); + } + } + + public bool TempComp + { + get + { + tl.LogMessage("TempComp Get", false.ToString()); + return false; + } + set + { + tl.LogMessage("TempComp Set", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("TempComp", false); + } + } + + public bool TempCompAvailable + { + get + { + tl.LogMessage("TempCompAvailable Get", false.ToString()); + return false; // Temperature compensation is not available in this driver + } + } + + public double Temperature + { + get + { + tl.LogMessage("Temperature Get", "Not implemented"); + throw new ASCOM.PropertyNotImplementedException("Temperature", false); + } + } + + #endregion + + #region Private properties and methods + // here are some useful properties and methods that can be used as required + // to help with driver development + + #region ASCOM Registration + + // Register or unregister driver for ASCOM. This is harmless if already + // registered or unregistered. + // + /// + /// Register or unregister the driver with the ASCOM Platform. + /// This is harmless if the driver is already registered/unregistered. + /// + /// If true, registers the driver, otherwise unregisters it. + private static void RegUnregASCOM(bool bRegister) + { + using (var P = new ASCOM.Utilities.Profile()) + { + P.DeviceType = "Focuser"; + if (bRegister) + { + P.Register(driverID, driverDescription); + } + else + { + P.Unregister(driverID); + } + } + } + + /// + /// This function registers the driver with the ASCOM Chooser and + /// is called automatically whenever this class is registered for COM Interop. + /// + /// Type of the class being registered, not used. + /// + /// This method typically runs in two distinct situations: + /// + /// + /// In Visual Studio, when the project is successfully built. + /// For this to work correctly, the option Register for COM Interop + /// must be enabled in the project settings. + /// + /// During setup, when the installer registers the assembly for COM Interop. + /// + /// This technique should mean that it is never necessary to manually register a driver with ASCOM. + /// + [ComRegisterFunction] + public static void RegisterASCOM(Type t) + { + RegUnregASCOM(true); + } + + /// + /// This function unregisters the driver from the ASCOM Chooser and + /// is called automatically whenever this class is unregistered from COM Interop. + /// + /// Type of the class being registered, not used. + /// + /// This method typically runs in two distinct situations: + /// + /// + /// In Visual Studio, when the project is cleaned or prior to rebuilding. + /// For this to work correctly, the option Register for COM Interop + /// must be enabled in the project settings. + /// + /// During uninstall, when the installer unregisters the assembly from COM Interop. + /// + /// This technique should mean that it is never necessary to manually unregister a driver from ASCOM. + /// + [ComUnregisterFunction] + public static void UnregisterASCOM(Type t) + { + RegUnregASCOM(false); + } + + #endregion + + /// + /// Returns true if there is a valid connection to the driver hardware + /// + private bool IsConnected + { + get + { + // TODO check that the driver hardware connection exists and is connected to the hardware + return connectedState; + } + } + + /// + /// Use this function to throw an exception if we aren't connected to the hardware + /// + /// + private void CheckConnected(string message) + { + if (!IsConnected) + { + throw new ASCOM.NotConnectedException(message); + } + } + + /// + /// Read the device configuration from the ASCOM Profile store + /// + internal void ReadProfile() + { + var profileProperties = SharedResources.ReadProfile(); + tl.Enabled = profileProperties.TraceLogger; + comPort = profileProperties.ComPort; + } + + /// + /// Log helper function that takes formatted strings and arguments + /// + /// + /// + /// + internal static void LogMessage(string identifier, string message, params object[] args) + { + var msg = string.Format(message, args); + tl.LogMessage(identifier, msg); + } + #endregion + } +} diff --git a/Meade.net.focuser/Meade.net.focuser.csproj b/Meade.net.focuser/Meade.net.focuser.csproj new file mode 100644 index 0000000..a082801 --- /dev/null +++ b/Meade.net.focuser/Meade.net.focuser.csproj @@ -0,0 +1,151 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A97E3AEC-F11D-49DA-B259-DE99DA813A86} + Library + Properties + ASCOM.Meade.net + ASCOM.Meade.net.Focuser + + + + + 3.5 + v4.7.1 + ASCOM.ico + true + ASCOMDriverTemplate.snk + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + x86 + false + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + AnyCPU + false + false + + + + + + + + + + + + + + + 3.5 + + + + + + + + + + + True + True + Resources.resx + + + True + True + Settings.settings + + + + + Designer + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + {3689a2cb-94c5-4012-a5cf-7e7d1dd27143} + Meade.net + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0fce7a9 --- /dev/null +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +// TODO - Add your authorship information here +[assembly: AssemblyTitle("ASCOM.Meade.net.Focuser")] +[assembly: AssemblyDescription("ASCOM Focuser driver for Meade.net")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("cjdawson.com")] +[assembly: AssemblyProduct("ASCOM Focuser driver for Meade.net")] +[assembly: AssemblyCopyright("Copyright © 2019 cjdawson.com")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(true)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4ad7a6d4-6d54-4a9a-bbf3-895353e318f8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +// +// TODO - Set your driver's version here +[assembly: AssemblyVersion("0.4.0.0")] +[assembly: AssemblyFileVersion("0.4.0.0")] diff --git a/Meade.net.focuser/Properties/Resources.Designer.cs b/Meade.net.focuser/Properties/Resources.Designer.cs new file mode 100644 index 0000000..67f90ec --- /dev/null +++ b/Meade.net.focuser/Properties/Resources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ASCOM.Meade.net.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.Meade.net.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ASCOM { + get { + object obj = ResourceManager.GetObject("ASCOM", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon DefaultIcon { + get { + object obj = ResourceManager.GetObject("DefaultIcon", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/Meade.net.focuser/Properties/Resources.resx b/Meade.net.focuser/Properties/Resources.resx new file mode 100644 index 0000000..e522d9e --- /dev/null +++ b/Meade.net.focuser/Properties/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\ASCOM.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\ASCOM.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Meade.net.focuser/Properties/Settings.Designer.cs b/Meade.net.focuser/Properties/Settings.Designer.cs new file mode 100644 index 0000000..f1cc444 --- /dev/null +++ b/Meade.net.focuser/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ASCOM.Meade.net.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Meade.net.focuser/Properties/Settings.settings b/Meade.net.focuser/Properties/Settings.settings new file mode 100644 index 0000000..8e615f2 --- /dev/null +++ b/Meade.net.focuser/Properties/Settings.settings @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Meade.net.focuser/ReadMe.htm b/Meade.net.focuser/ReadMe.htm new file mode 100644 index 0000000..d0e812e --- /dev/null +++ b/Meade.net.focuser/ReadMe.htm @@ -0,0 +1,147 @@ + + + + + Untitled Document + + + + + + + + + + + +
    +

    ASCOM Focuser Driver (C#)

    +
    +



    +

    +

    You have just created the skeleton of an ASCOM +Focuser driver in C#. It produces an in-process +(assembly) based driver.

    +
    +
    +

    You must do the following in order to complete +your implementation:

    +
      +
    1. Switch to the Debug configuration + and build the template now. It should build without errors. +

      +
    2. Add a test project to the + solution. There are templates that can be used to add either a + console or a Windows Forms application:

      +
    +
      +
    • Select the ASCOM + Test Forms App (CS) or ASCOM + Test Console App (CS) template.

      +
    • Set a name for the test + application and click on OK.

      +
    • In the Wizard: set the same device + type and model name as for the driver and select Create to build the + test project.

      +
    • Set the Test Application to Run at + Startup.

      +
    • Click on Debug and the test + application should run. You should be able to select your + application in the chooser. Selecting Properties should show the + default setup dialog for your driver.

      +
    • Trying to continue will generate + errors because the additional properties have not been implemented.

      +
    +
      +
    1. Go through the Driver.cs file and + replace the System.NotImplemented exceptions with code to implement + your driver's functionality. See the ASCOM IFocuserV3 + spec. If a property or method is not implemented in your driver the + System.NotImplemented exception must be replaced by an + ASCOM.PropertyNotImplemented or ASCOM.MethodNotImplemented + exception.

      +
    2. Customize the Setup Dialog (SetupDialogForm) to provide the + settings and other controls for your driver. You can bind settings + directly to controls on your dialog form, there's no need to manage + settings manually. A custom Settings class takes care of managing + your settings behind the scenes. +

      +
    +

    Notes:

    +
      +
    • Successfully building the driver, + as well as using regasm + on the assembly, registers it for both COM and ASCOM (the Chooser). + See the code in the ASCOM Registration region of Driver.vb. +

      +
    • Doing a Clean for the project, as + well doing a regasm + -u on the assembly, unregisters it for both COM and ASCOM + (the Chooser). +

      +
    • Place a breakpoint in your driver class constructor, then + start debugging (go, F5). Your breakpoint will be hit when the test + application creates an instance of your driver (after selecting it + in the Chooser). You can now single step, examine variables, etc. + Please review the test application and make changes and additions to + activate various parts of your driver during debugging.

      +
    • The project's Debug configuration is already configured (The + test application creates an instance of your driver (after selecting + it in the Chooser). You can now single step, examine variables, etc. + Please review the test application and feel free to make changes and + additions to activate various parts of your driver during debugging. +

      +
    +
    + + + + + + + +
    + + + + + +
    +

    ASCOM Initiative

    +
    +
    +



    +

    +
    +

    The ASCOM Initiative consists of a group of astronomy software + developers and instrument vendors whose goals are to promote the + driver/client model and scripting automation. +

    +

    See the ASCOM + web site for more information. Please participate in the + ASCOM-Talk + Yahoo Group. +

    +
    +
    +



    +

    +

    +

    + + \ No newline at end of file diff --git a/Meade.net.focuser/Resources/ASCOM.bmp b/Meade.net.focuser/Resources/ASCOM.bmp new file mode 100644 index 0000000000000000000000000000000000000000..55516c7aaa3591604865d4cd18379f8f650c3104 GIT binary patch literal 3382 zcmeIwA#&YN425B3CLjUbgJ57$uqM1+gO+lZkut%6E<(#F6wORPc)-i=r?4!c_Vwp; zZ3Fx2>gm_x54#?Zw`LE_etx;JyM1xL@%<_@PLnpcGPUluKQDjn-|L&12NJySLSxLr z;9wF7q0kt!G&lm>q)=$g*LR%^B!og^%$Qm^0tune7=F^=2qc6;W6U^h9D#&TXpDvN zo8~x1LMSw5m*!3e5<;OdyXkPr%u*^;D_frLmI06Zw(3st}a59h(3XRzqWFR3F8nf*xCj$wg(3oxIax#z*3XRz|Zzlr@q3r$RV$Z*g8j2NO iuBTlt#|(_)(Q$tsX9dm*oE11La8}@~z*&L+tOB3FDm>c& literal 0 HcmV?d00001 diff --git a/Meade.net.focuser/app.config b/Meade.net.focuser/app.config new file mode 100644 index 0000000..56895a9 --- /dev/null +++ b/Meade.net.focuser/app.config @@ -0,0 +1,8 @@ + + + + +
    + + + diff --git a/Meade.net.sln b/Meade.net.sln new file mode 100644 index 0000000..4ca39e2 --- /dev/null +++ b/Meade.net.sln @@ -0,0 +1,73 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.136 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meade.net", "Meade.net\Meade.net.csproj", "{3689A2CB-94C5-4012-A5CF-7E7D1DD27143}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meade.net.Telescope", "Meade.net.Telescope\Meade.net.Telescope.csproj", "{64308775-BD4A-469C-BCAB-3ED830B811AF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meade.net.focuser", "Meade.net.focuser\Meade.net.focuser.csproj", "{A97E3AEC-F11D-49DA-B259-DE99DA813A86}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelescopeTestConsole", "TelescopeTestConsole\TelescopeTestConsole.csproj", "{D5207217-61C7-4E94-8097-91DBACE57D2A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FocuserTestConsole", "FocuserTestConsole\FocuserTestConsole.csproj", "{AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestConsoles", "TestConsoles", "{BF650D97-AF98-4638-9C55-21311C6D88DA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.ActiveCfg = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.Build.0 = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.Build.0 = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.ActiveCfg = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.Build.0 = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.ActiveCfg = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.Build.0 = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.Build.0 = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.ActiveCfg = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.Build.0 = Release|Any CPU + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.ActiveCfg = Release|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.ActiveCfg = Debug|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.Build.0 = Debug|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|Any CPU.ActiveCfg = Release|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.ActiveCfg = Release|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D5207217-61C7-4E94-8097-91DBACE57D2A} = {BF650D97-AF98-4638-9C55-21311C6D88DA} + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49} = {BF650D97-AF98-4638-9C55-21311C6D88DA} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3C0509DC-C7F5-48DC-920D-DCFD9C879BD2} + EndGlobalSection +EndGlobal diff --git a/Meade.net/ASCOM.ico b/Meade.net/ASCOM.ico new file mode 100644 index 0000000000000000000000000000000000000000..9bf8f4110f20bfdde720ab5e04def9b01b414268 GIT binary patch literal 125783 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 literal 0 HcmV?d00001 diff --git a/Meade.net/ClassFactory.cs b/Meade.net/ClassFactory.cs new file mode 100644 index 0000000..1626f5c --- /dev/null +++ b/Meade.net/ClassFactory.cs @@ -0,0 +1,244 @@ +using System; +using System.Runtime.InteropServices; +using System.Collections; + +namespace ASCOM.Meade.net +{ + + #region C# Definition of IClassFactory + // + // Provide a definition of theCOM IClassFactory interface. + // + [ + ComImport, // This interface originated from COM. + ComVisible(false), // Must not be exposed to COM!!! + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), // Indicate that this interface is not IDispatch-based. + Guid("00000001-0000-0000-C000-000000000046") // This GUID is the actual GUID of IClassFactory. + ] + public interface IClassFactory + { + void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject); + void LockServer(bool fLock); + } + #endregion + + // + // Universal ClassFactory. Given a type as a parameter of the + // constructor, it implements IClassFactory for any interface + // that the class implements. Magic!!! + // + public class ClassFactory : IClassFactory + { + + #region Access to ole32.dll functions for class factories + + // Define two common GUID objects for public usage. + public static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); + public static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); + + [Flags] + enum CLSCTX : uint + { + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_RESERVED1 = 0x40, + CLSCTX_RESERVED2 = 0x80, + CLSCTX_RESERVED3 = 0x100, + CLSCTX_RESERVED4 = 0x200, + CLSCTX_NO_CODE_DOWNLOAD = 0x400, + CLSCTX_RESERVED5 = 0x800, + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, + CLSCTX_NO_FAILURE_LOG = 0x4000, + CLSCTX_DISABLE_AAA = 0x8000, + CLSCTX_ENABLE_AAA = 0x10000, + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, + CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, + CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER + } + + [Flags] + enum REGCLS : uint + { + REGCLS_SINGLEUSE = 0, + REGCLS_MULTIPLEUSE = 1, + REGCLS_MULTI_SEPARATE = 2, + REGCLS_SUSPENDED = 4, + REGCLS_SURROGATE = 8 + } + // + // CoRegisterClassObject() is used to register a Class Factory + // into COM's internal table of Class Factories. + // + [DllImport("ole32.dll")] + static extern int CoRegisterClassObject( + [In] ref Guid rclsid, + [MarshalAs(UnmanagedType.IUnknown)] object pUnk, + uint dwClsContext, + uint flags, + out uint lpdwRegister); + // + // Called by a COM EXE Server that can register multiple class objects + // to inform COM about all registered classes, and permits activation + // requests for those class objects. + // This function causes OLE to inform the SCM about all the registered + // classes, and begins letting activation requests into the server process. + // + [DllImport("ole32.dll")] + static extern int CoResumeClassObjects(); + // + // Prevents any new activation requests from the SCM on all class objects + // registered within the process. Even though a process may call this API, + // the process still must call CoRevokeClassObject for each CLSID it has + // registered, in the apartment it registered in. + // + [DllImport("ole32.dll")] + static extern int CoSuspendClassObjects(); + // + // CoRevokeClassObject() is used to unregister a Class Factory + // from COM's internal table of Class Factories. + // + [DllImport("ole32.dll")] + static extern int CoRevokeClassObject(uint dwRegister); + #endregion + + #region Constructor and Private ClassFactory Data + + protected Type m_ClassType; + protected Guid m_ClassId; + protected ArrayList m_InterfaceTypes; + protected uint m_ClassContext; + protected uint m_Flags; + protected UInt32 m_locked = 0; + protected uint m_Cookie; + protected string m_progid; + + public ClassFactory(Type type) + { + if (type == null) + throw new ArgumentNullException("type"); + m_ClassType = type; + + //PWGS Get the ProgID from the MetaData + m_progid = Marshal.GenerateProgIdForType(type); + m_ClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)] + m_ClassContext = (uint)CLSCTX.CLSCTX_LOCAL_SERVER; // Default + m_Flags = (uint)REGCLS.REGCLS_MULTIPLEUSE | // Default + (uint)REGCLS.REGCLS_SUSPENDED; + m_InterfaceTypes = new ArrayList(); + foreach (Type T in type.GetInterfaces()) // Save all of the implemented interfaces + m_InterfaceTypes.Add(T); + } + + #endregion + + #region Common ClassFactory Methods + public uint ClassContext + { + get { return m_ClassContext; } + set { m_ClassContext = value; } + } + + public Guid ClassId + { + get { return m_ClassId; } + set { m_ClassId = value; } + } + + public uint Flags + { + get { return m_Flags; } + set { m_Flags = value; } + } + + public bool RegisterClassObject() + { + // Register the class factory + int i = CoRegisterClassObject + ( + ref m_ClassId, + this, + m_ClassContext, + m_Flags, + out m_Cookie + ); + return (i == 0); + } + + public bool RevokeClassObject() + { + int i = CoRevokeClassObject(m_Cookie); + return (i == 0); + } + + public static bool ResumeClassObjects() + { + int i = CoResumeClassObjects(); + return (i == 0); + } + + public static bool SuspendClassObjects() + { + int i = CoSuspendClassObjects(); + return (i == 0); + } + #endregion + + #region IClassFactory Implementations + // + // Implement creation of the type and interface. + // + void IClassFactory.CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject) + { + IntPtr nullPtr = new IntPtr(0); + ppvObject = nullPtr; + + // + // Handle specific requests for implemented interfaces + // + foreach (Type iType in m_InterfaceTypes) + { + if (riid == Marshal.GenerateGuidForType(iType)) + { + ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(m_ClassType), iType); + return; + } + } + // + // Handle requests for IDispatch or IUnknown on the class + // + if (riid == IID_IDispatch) + { + ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(m_ClassType)); + return; + } + else if (riid == IID_IUnknown) + { + ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(m_ClassType)); + } + else + { + // + // Oops, some interface that the class doesn't implement + // + throw new COMException("No interface", unchecked((int)0x80004002)); + } + } + + void IClassFactory.LockServer(bool bLock) + { + if (bLock) + Server.CountLock(); + else + Server.UncountLock(); + // Always attempt to see if we need to shutdown this server application. + Server.ExitIf(); + } + #endregion + } +} diff --git a/Meade.net/GarbageCollection.cs b/Meade.net/GarbageCollection.cs new file mode 100644 index 0000000..99aba52 --- /dev/null +++ b/Meade.net/GarbageCollection.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; + +namespace ASCOM.Meade.net +{ + /// + /// Summary description for GarbageCollection. + /// + class GarbageCollection + { + protected bool m_bContinueThread; + protected bool m_GCWatchStopped; + protected int m_iInterval; + protected ManualResetEvent m_EventThreadEnded; + + public GarbageCollection(int iInterval) + { + m_bContinueThread = true; + m_GCWatchStopped = false; + m_iInterval = iInterval; + m_EventThreadEnded = new ManualResetEvent(false); + } + + public void GCWatch() + { + // Pause for a moment to provide a delay to make threads more apparent. + while (ContinueThread()) + { + GC.Collect(); + Thread.Sleep(m_iInterval); + } + m_EventThreadEnded.Set(); + } + + protected bool ContinueThread() + { + lock (this) + { + return m_bContinueThread; + } + } + + public void StopThread() + { + lock (this) + { + m_bContinueThread = false; + } + } + + public void WaitForThreadToStop() + { + m_EventThreadEnded.WaitOne(); + m_EventThreadEnded.Reset(); + } + } +} diff --git a/Meade.net/LocalServer.cs b/Meade.net/LocalServer.cs new file mode 100644 index 0000000..a4fc2c2 --- /dev/null +++ b/Meade.net/LocalServer.cs @@ -0,0 +1,642 @@ +// +// ASCOM.Meade.net Local COM Server +// +// This is the core of a managed COM Local Server, capable of serving +// multiple instances of multiple interfaces, within a single +// executable. This implementes the equivalent functionality of VB6 +// which has been extensively used in ASCOM for drivers that provide +// multiple interfaces to multiple clients (e.g. Meade Telescope +// and Focuser) as well as hubs (e.g., POTH). +// +// Written by: Robert B. Denny (Version 1.0.1, 29-May-2007) +// Modified by Chris Rowland and Peter Simpson to allow use with multiple devices of the same type March 2011 +// +// +using System; +using System.IO; +using System.Windows.Forms; +using System.Drawing; +using System.Collections; +using System.Runtime.InteropServices; +using System.Reflection; +using ASCOM.Utilities; +using Microsoft.Win32; +using System.Text; +using System.Threading; +using System.Security.Principal; +using System.Diagnostics; +using ASCOM; + +namespace ASCOM.Meade.net +{ + public static class Server + { + + #region Access to kernel32.dll, user32.dll, and ole32.dll functions + [Flags] + enum CLSCTX : uint + { + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_RESERVED1 = 0x40, + CLSCTX_RESERVED2 = 0x80, + CLSCTX_RESERVED3 = 0x100, + CLSCTX_RESERVED4 = 0x200, + CLSCTX_NO_CODE_DOWNLOAD = 0x400, + CLSCTX_RESERVED5 = 0x800, + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, + CLSCTX_NO_FAILURE_LOG = 0x4000, + CLSCTX_DISABLE_AAA = 0x8000, + CLSCTX_ENABLE_AAA = 0x10000, + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, + CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, + CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER + } + + [Flags] + enum COINIT : uint + { + /// Initializes the thread for multi-threaded object concurrency. + COINIT_MULTITHREADED = 0x0, + /// Initializes the thread for apartment-threaded object concurrency. + COINIT_APARTMENTTHREADED = 0x2, + /// Disables DDE for Ole1 support. + COINIT_DISABLE_OLE1DDE = 0x4, + /// Trades memory for speed. + COINIT_SPEED_OVER_MEMORY = 0x8 + } + + [Flags] + enum REGCLS : uint + { + REGCLS_SINGLEUSE = 0, + REGCLS_MULTIPLEUSE = 1, + REGCLS_MULTI_SEPARATE = 2, + REGCLS_SUSPENDED = 4, + REGCLS_SURROGATE = 8 + } + + + // CoInitializeEx() can be used to set the apartment model + // of individual threads. + [DllImport("ole32.dll")] + static extern int CoInitializeEx(IntPtr pvReserved, uint dwCoInit); + + // CoUninitialize() is used to uninitialize a COM thread. + [DllImport("ole32.dll")] + static extern void CoUninitialize(); + + // PostThreadMessage() allows us to post a Windows Message to + // a specific thread (identified by its thread id). + // We will need this API to post a WM_QUIT message to the main + // thread in order to terminate this application. + [DllImport("user32.dll")] + static extern bool PostThreadMessage(uint idThread, uint Msg, UIntPtr wParam, + IntPtr lParam); + + // GetCurrentThreadId() allows us to obtain the thread id of the + // calling thread. This allows us to post the WM_QUIT message to + // the main thread. + [DllImport("kernel32.dll")] + static extern uint GetCurrentThreadId(); + #endregion + + #region Private Data + private static int objsInUse; // Keeps a count on the total number of objects alive. + private static int serverLocks; // Keeps a lock count on this application. + private static frmMain s_MainForm = null; // Reference to our main form + private static ArrayList s_ComObjectAssys; // Dynamically loaded assemblies containing served COM objects + private static ArrayList s_ComObjectTypes; // Served COM object types + private static ArrayList s_ClassFactories; // Served COM object class factories + private static string s_appId = "{4e68ec46-5ffc-49e7-b298-38a548df0bfd}"; // Our AppId + private static readonly Object lockObject = new object(); + #endregion + + // This property returns the main thread's id. + public static uint MainThreadId { get; private set; } // Stores the main thread's thread id. + + // Used to tell if started by COM or manually + public static bool StartedByCOM { get; private set; } // True if server started by COM (-embedding) + + + #region Server Lock, Object Counting, and AutoQuit on COM startup + // Returns the total number of objects alive currently. + public static int ObjectsCount + { + get + { + lock (lockObject) + { + return objsInUse; + } + } + } + + // This method performs a thread-safe incrementation of the objects count. + public static int CountObject() + { + // Increment the global count of objects. + return Interlocked.Increment(ref objsInUse); + } + + // This method performs a thread-safe decrementation the objects count. + public static int UncountObject() + { + // Decrement the global count of objects. + return Interlocked.Decrement(ref objsInUse); + } + + // Returns the current server lock count. + public static int ServerLockCount + { + get + { + lock (lockObject) + { + return serverLocks; + } + } + } + + // This method performs a thread-safe incrementation the + // server lock count. + public static int CountLock() + { + // Increment the global lock count of this server. + return Interlocked.Increment(ref serverLocks); + } + + // This method performs a thread-safe decrementation the + // server lock count. + public static int UncountLock() + { + // Decrement the global lock count of this server. + return Interlocked.Decrement(ref serverLocks); + } + + // AttemptToTerminateServer() will check to see if the objects count and the server + // lock count have both dropped to zero. + // + // If so, and if we were started by COM, we post a WM_QUIT message to the main thread's + // message loop. This will cause the message loop to exit and hence the termination + // of this application. If hand-started, then just trace that it WOULD exit now. + // + public static void ExitIf() + { + lock (lockObject) + { + if ((ObjectsCount <= 0) && (ServerLockCount <= 0)) + { + if (StartedByCOM) + { + UIntPtr wParam = new UIntPtr(0); + IntPtr lParam = new IntPtr(0); + PostThreadMessage(MainThreadId, 0x0012, wParam, lParam); + } + } + } + } + #endregion + + // ----------------- + // PRIVATE FUNCTIONS + // ----------------- + + #region Dynamic Driver Assembly Loader + // + // Load the assemblies that contain the classes that we will serve + // via COM. These will be located in the same folder as + // our executable. + // + private static bool LoadComObjectAssemblies() + { + s_ComObjectAssys = new ArrayList(); + s_ComObjectTypes = new ArrayList(); + + // put everything into one folder, the same as the server. + string assyPath = Assembly.GetEntryAssembly().Location; + assyPath = Path.GetDirectoryName(assyPath); + + DirectoryInfo d = new DirectoryInfo(assyPath); + foreach (FileInfo fi in d.GetFiles("*.dll")) + { + string aPath = fi.FullName; + // + // First try to load the assembly and get the types for + // the class and the class factory. If this doesn't work ???? + // + try + { + Assembly so = Assembly.LoadFrom(aPath); + //PWGS Get the types in the assembly + Type[] types = so.GetTypes(); + foreach (Type type in types) + { + // PWGS Now checks the type rather than the assembly + // Check to see if the type has the ServedClassName attribute, only use it if it does. + MemberInfo info = type; + + object[] attrbutes = info.GetCustomAttributes(typeof(ServedClassNameAttribute), false); + if (attrbutes.Length > 0) + { + //MessageBox.Show("Adding Type: " + type.Name + " " + type.FullName); + s_ComObjectTypes.Add(type); //PWGS - much simpler + s_ComObjectAssys.Add(so); + } + } + } + catch (BadImageFormatException) + { + // Probably an attempt to load a Win32 DLL (i.e. not a .net assembly) + // Just swallow the exception and continue to the next item. + continue; + } + catch (Exception e) + { + MessageBox.Show("Failed to load served COM class assembly " + fi.Name + " - " + e.Message, + "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Stop); + return false; + } + + } + return true; + } + #endregion + + #region COM Registration and Unregistration + // + // Test if running elevated + // + private static bool IsAdministrator + { + get + { + WindowsIdentity i = WindowsIdentity.GetCurrent(); + WindowsPrincipal p = new WindowsPrincipal(i); + return p.IsInRole(WindowsBuiltInRole.Administrator); + } + } + + // + // Elevate by re-running ourselves with elevation dialog + // + private static void ElevateSelf(string arg) + { + ProcessStartInfo si = new ProcessStartInfo(); + si.Arguments = arg; + si.WorkingDirectory = Environment.CurrentDirectory; + si.FileName = Application.ExecutablePath; + si.Verb = "runas"; + try { Process.Start(si); } + catch (System.ComponentModel.Win32Exception) + { + MessageBox.Show("The Meade.net was not " + (arg == "/register" ? "registered" : "unregistered") + + " because you did not allow it.", "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString(), "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Stop); + } + return; + } + + // + // Do everything to register this for COM. Never use REGASM on + // this exe assembly! It would create InProcServer32 entries + // which would prevent proper activation! + // + // Using the list of COM object types generated during dynamic + // assembly loading, it registers each one for COM as served by our + // exe/local server, as well as registering it for ASCOM. It also + // adds DCOM info for the local server itself, so it can be activated + // via an outboiud connection from TheSky. + // + private static void RegisterObjects() + { + if (!IsAdministrator) + { + ElevateSelf("/register"); + return; + } + // + // If reached here, we're running elevated + // + + Assembly assy = Assembly.GetExecutingAssembly(); + Attribute attr = Attribute.GetCustomAttribute(assy, typeof(AssemblyTitleAttribute)); + string assyTitle = ((AssemblyTitleAttribute)attr).Title; + attr = Attribute.GetCustomAttribute(assy, typeof(AssemblyDescriptionAttribute)); + string assyDescription = ((AssemblyDescriptionAttribute)attr).Description; + + // + // Local server's DCOM/AppID information + // + try + { + // + // HKCR\APPID\appid + // + using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("APPID\\" + s_appId)) + { + key.SetValue(null, assyDescription); + key.SetValue("AppID", s_appId); + key.SetValue("AuthenticationLevel", 1, RegistryValueKind.DWord); + } + // + // HKCR\APPID\exename.ext + // + using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("APPID\\{0}", + Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1)))) + { + key.SetValue("AppID", s_appId); + } + } + catch (Exception ex) + { + MessageBox.Show("Error while registering the server:\n" + ex.ToString(), + "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Stop); + return; + } + finally + { + } + + // + // For each of the driver assemblies + // + foreach (Type type in s_ComObjectTypes) + { + bool bFail = false; + try + { + // + // HKCR\CLSID\clsid + // + string clsid = Marshal.GenerateGuidForType(type).ToString("B"); + string progid = Marshal.GenerateProgIdForType(type); + //PWGS Generate device type from the Class name + string deviceType = type.Name; + + using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("CLSID\\{0}", clsid))) + { + key.SetValue(null, progid); // Could be assyTitle/Desc??, but .NET components show ProgId here + key.SetValue("AppId", s_appId); + using (RegistryKey key2 = key.CreateSubKey("Implemented Categories")) + { + key2.CreateSubKey("{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"); + } + using (RegistryKey key2 = key.CreateSubKey("ProgId")) + { + key2.SetValue(null, progid); + } + key.CreateSubKey("Programmable"); + using (RegistryKey key2 = key.CreateSubKey("LocalServer32")) + { + key2.SetValue(null, Application.ExecutablePath); + } + } + // + // HKCR\CLSID\progid + // + using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progid)) + { + key.SetValue(null, assyTitle); + using (RegistryKey key2 = key.CreateSubKey("CLSID")) + { + key2.SetValue(null, clsid); + } + } + // + // ASCOM + // + assy = type.Assembly; + + // Pull the display name from the ServedClassName attribute. + attr = Attribute.GetCustomAttribute(type, typeof(ServedClassNameAttribute)); //PWGS Changed to search type for attribute rather than assembly + string chooserName = ((ServedClassNameAttribute)attr).DisplayName ?? "MultiServer"; + using (var P = new ASCOM.Utilities.Profile()) + { + P.DeviceType = deviceType; + P.Register(progid, chooserName); + } + } + catch (Exception ex) + { + MessageBox.Show("Error while registering the server:\n" + ex.ToString(), + "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Stop); + bFail = true; + } + finally + { + } + if (bFail) break; + } + } + + // + // Remove all traces of this from the registry. + // + // **TODO** If the above does AppID/DCOM stuff, this would have + // to remove that stuff too. + // + private static void UnregisterObjects() + { + if (!IsAdministrator) + { + ElevateSelf("/unregister"); + return; + } + + // + // Local server's DCOM/AppID information + // + Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", s_appId), false); + Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", + Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1)), false); + + // + // For each of the driver assemblies + // + foreach (Type type in s_ComObjectTypes) + { + string clsid = Marshal.GenerateGuidForType(type).ToString("B"); + string progid = Marshal.GenerateProgIdForType(type); + string deviceType = type.Name; + // + // Best efforts + // + // + // HKCR\progid + // + Registry.ClassesRoot.DeleteSubKey(String.Format("{0}\\CLSID", progid), false); + Registry.ClassesRoot.DeleteSubKey(progid, false); + // + // HKCR\CLSID\clsid + // + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Implemented Categories\\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}}", clsid), false); + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Implemented Categories", clsid), false); + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\ProgId", clsid), false); + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\LocalServer32", clsid), false); + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Programmable", clsid), false); + Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}", clsid), false); + try + { + // + // ASCOM + // + using (var P = new ASCOM.Utilities.Profile()) + { + P.DeviceType = deviceType; + P.Unregister(progid); + } + } + catch (Exception) { } + } + } + #endregion + + #region Class Factory Support + // + // On startup, we register the class factories of the COM objects + // that we serve. This requires the class facgtory name to be + // equal to the served class name + "ClassFactory". + // + private static bool RegisterClassFactories() + { + s_ClassFactories = new ArrayList(); + foreach (Type type in s_ComObjectTypes) + { + ClassFactory factory = new ClassFactory(type); // Use default context & flags + s_ClassFactories.Add(factory); + if (!factory.RegisterClassObject()) + { + MessageBox.Show("Failed to register class factory for " + type.Name, + "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Stop); + return false; + } + } + ClassFactory.ResumeClassObjects(); // Served objects now go live + return true; + } + + private static void RevokeClassFactories() + { + ClassFactory.SuspendClassObjects(); // Prevent race conditions + foreach (ClassFactory factory in s_ClassFactories) + factory.RevokeClassObject(); + } + #endregion + + #region Command Line Arguments + // + // ProcessArguments() will process the command-line arguments + // If the return value is true, we carry on and start this application. + // If the return value is false, we terminate this application immediately. + // + private static bool ProcessArguments(string[] args) + { + bool bRet = true; + + // + //**TODO** -Embedding is "ActiveX start". Prohibit non_AX starting? + // + if (args.Length > 0) + { + + switch (args[0].ToLower()) + { + case "-embedding": + StartedByCOM = true; // Indicate COM started us + break; + + case "-register": + case @"/register": + case "-regserver": // Emulate VB6 + case @"/regserver": + RegisterObjects(); // Register each served object + bRet = false; + break; + + case "-unregister": + case @"/unregister": + case "-unregserver": // Emulate VB6 + case @"/unregserver": + UnregisterObjects(); //Unregister each served object + bRet = false; + break; + + default: + MessageBox.Show("Unknown argument: " + args[0] + "\nValid are : -register, -unregister and -embedding", + "Meade.net", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + break; + } + } + else + StartedByCOM = false; + + return bRet; + } + #endregion + + #region SERVER ENTRY POINT (main) + // + // ================== + // SERVER ENTRY POINT + // ================== + // + [STAThread] + static void Main(string[] args) + { + if (!LoadComObjectAssemblies()) return; // Load served COM class assemblies, get types + + if (!ProcessArguments(args)) return; // Register/Unregister + + // Initialize critical member variables. + objsInUse = 0; + serverLocks = 0; + MainThreadId = GetCurrentThreadId(); + Thread.CurrentThread.Name = "Main Thread"; + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + s_MainForm = new frmMain(); + if (StartedByCOM) s_MainForm.WindowState = FormWindowState.Minimized; + + // Register the class factories of the served objects + RegisterClassFactories(); + + // Start up the garbage collection thread. + GarbageCollection GarbageCollector = new GarbageCollection(1000); + Thread GCThread = new Thread(new ThreadStart(GarbageCollector.GCWatch)); + GCThread.Name = "Garbage Collection Thread"; + GCThread.Start(); + + // + // Start the message loop. This serializes incoming calls to our + // served COM objects, making this act like the VB6 equivalent! + // + try + { + Application.Run(s_MainForm); + } + finally + { + // Revoke the class factories immediately. + // Don't wait until the thread has stopped before + // we perform revocation!!! + RevokeClassFactories(); + + // Now stop the Garbage Collector thread. + GarbageCollector.StopThread(); + GarbageCollector.WaitForThreadToStop(); + } + } + #endregion + } +} diff --git a/Meade.net/LocalServer.snk b/Meade.net/LocalServer.snk new file mode 100644 index 0000000000000000000000000000000000000000..97e44064e7bc6d608913a5a8542b39243e53f825 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097L4}G28oM$F0^<%6-cFiYYwSe?a7L$A- zPjs7(CKo#X44$udl=V0HdhSa|Y66!|Ee(v)u)x;tmy;IRJq0+T?30Vq3#N+7qYfU@ z9O=aZq`Jd&LLfG^7Q=v6%;?I7R*Ob~BNWW>wU0h|lZxR5RjYCU5hT%23xHk!l7y{w*Esa?cjU<{J?8%BZ&RTmS$T{Q8GL(z0_4No`a@f>bwzY>oTIZ?KKmt1 z%!cfuHpE9Qu{Tgt^*7ThFAo9E_{`1u)ALOuR?3|Kk%^P@5fo{=p-yZy|a-1WwMiN94P<1|k z=QFJxPSyMkCSL)@b@w(o(6~ALWpYG_snMlk_o;5nI$DnQ*Tg`u@w*iH%R;7PGk#FC z<^Xcp`x#c7`sRstdut^$U+rB}H21X-*C+yMr+P&V#vP~GM$sJiz;Q!T#JQl9p%jDV zE9>eGU#kLv8q?h#9EtW9Y@0W@DvTwt;ax~FLk2K^;9_V;6Y(tQxcBNk$F{w_mnD!8 zyu%keSLp3=yW&LBho=(UyK%1d3#C|3h%I1j_nvwvd6bwG@H`nK?OC-O5be;t(wl3c i#j%9ZS$2MI$Iv1T + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143} + WinExe + Properties + ASCOM.Meade.net + ASCOM.Meade.net.Server + v4.7.1 + + + 2.0 + + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + MinimumRecommendedRules.ruleset + false + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + x86 + false + + + true + + + LocalServer.snk + + + ASCOM.ico + + + + + + + + + + + + + + Form + + + frmMain.cs + + + + + + Designer + frmMain.cs + + + True + True + Resources.resx + + + + Form + + + SetupDialogForm.cs + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SetupDialogForm.cs + Designer + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..af3da5d --- /dev/null +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ASCOM Meade.net server")] +[assembly: AssemblyDescription("ASCOM multi-interface server for Meade.net")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("cjdawson.com")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Copyright © 2019 cjdawson.com")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.4.0.0")] +[assembly: AssemblyFileVersion("0.4.0.0")] + +[assembly: ComVisibleAttribute(false)] diff --git a/Meade.net/Properties/Resources.Designer.cs b/Meade.net/Properties/Resources.Designer.cs new file mode 100644 index 0000000..0255290 --- /dev/null +++ b/Meade.net/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ASCOM.Meade.net.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.Meade.net.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ASCOM { + get { + object obj = ResourceManager.GetObject("ASCOM", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Meade.net/Properties/Resources.resx b/Meade.net/Properties/Resources.resx new file mode 100644 index 0000000..f4cef88 --- /dev/null +++ b/Meade.net/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\ASCOM.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Meade.net/ReadMe.htm b/Meade.net/ReadMe.htm new file mode 100644 index 0000000..0a8dc80 --- /dev/null +++ b/Meade.net/ReadMe.htm @@ -0,0 +1,666 @@ + + + + + Untitled Document + + + + + + + + + + + + +
    +

    + ASCOM LocalServer (singleton) Host +

    +
    +

    +
    +
    + +

    +

    + You have just created a local server (singleton) host for one or + more ASCOM driver classes. +

    +
    +

    + This project implements an ASCOM host server for one or more + driver classes in a single-instance executable. It can be used to + serve multiple instances of a single driver class (hub), provide + driver services for multiple devices (e.g., Telescope and Focuser) to + multiple applications and allow multiple devices of the same type to + be connected. In the latter scenario, the multiple driver classes + will often share one or more resources such as the serial connection + and a microcontroller in the combined device. From the client's + perspective, using the drivers served by the local server is exactly + the same as if the drivers are loaded into the client's process space + (in-proc servers). +

    +

    + + NOTE: + + + Unless you are prepared to handle all of the timing issues that arise + when multiple clients are accessing the properties and methods of + your driver(s), stop now. Just because the local server serializes + the calls to your driver(s)' properties and methods does not mean + that there will be no timing or concurrency issues.
    +  
    For + example, suppose the hub serves instances of a Telescope driver. One + client sets the TargetRightAscension property, then another sets + TargetRightAscension to a different value, then the first client sets + TargetDeclination, then the first client calls SlewToTarget() + followed by the second client calling SlewToTarget(). Besides the + first client's slew command sending the scope to the wrong (and + possibly dangerous) coordinates, there is the problem of the second + client trying to slew a slewing scope. Local server drivers are + tricky to get right. There is no such thing as "ignorance is + bliss" here. + +
    +

    +

    + + This implementation has changed + from what was defined for Platform 5.5 as follows: + +

    +

    + + The drivers are now installed in + the same folder as the local server executable. This makes deployment + cleaner because the whole driver can exist in a single folder + independently of other drivers. + +

    +

    + + The ProgId and friendly name as + displayed by the Chooser are defined using attributes. This allows + driver dlls to be identified clearly and so avoids confusion with + other dlls that may be required such as interop dlls. + +

    +

    + + Some changes have been made that + will facilitate generating multiple drivers of the same type. + +

    +

    + + I've put some additional advice and + comments in the notes below in italics. + +

    +

    + You're probably anxious to get going, but you really should read + through the Theory of Operation and + Detailed + Use and Deployment + below. +

    +

    You must do the following in order to complete your local server:

    +
      +
    1. +

      + In the local server's project + properties, Application tab, change BOTH the AssemblyName and the + default assembly name to ASCOM.xxx (e.g., ASCOM.SuperScope). + This + may be done by default now. + +

      +
    2. +
    3. +

      + Add one or more driver skeleton + projects using the in-proc templates. You may use either the C# or + VB templates. Project name is not important (not used in ProgID) + choose something like TelescopeDriver. You will be changing the + substituted project name in these projects below. If you ensure that + the LocalServer and all the driver projects have the same NameSpace + e.g. ASCOM.SuperScope the renaming in section 6a will not be + required. +

      +
    4. +
    5. +

      + Develop and debug these driver + projects as normal in-process assemblies. This will be much simpler + because the driver and test code can be debugged in the same + process. +

      +
    6. +
    7. +

      + Build the LocalServer. +

      +
    8. +
    9. +

      + Set a reference to the local + server project in each of the driver skeleton + projects. +

      +
    10. +
    11. +

      In each skeleton driver project:

      +
        +
      1. +

        + Do a Find In Files for the + project name of the skeleton driver (e.g., TelescopeDriver) and + change it to match the project name of your local server (e.g. + SuperScope). You don't have to do this in the ReadMe.html file. + Everywhere else, however, is IMPORTANT. This sets the correct + namespace, progID, etc. If you're a bit more brave, you can use + Replace in Files. + This may not be needed if the correct + namespace and naming conventions have been followed when the + drivers and local server were generated. + +

        +
      2. +
      3. +

        + In project properties, + Application tab, change the assembly name to + ASCOM.localserverprojectname.drivertype, + (e.g., ASCOM.SuperScope.Telescope). +

        +
      4. +
      5. +

        + In project properties, + Application tab, click Assembly Information... +

        +
          +
        • +

          + Assure that Make assembly COM + visible is on (it should already be on). +

          +
        • +
        • +

          + Edit the Product Name to be the + "friendly name" of your driver as will be shown in the + Chooser. + Not used now, use the ServedClassName attribute + instead. + +

          +
        • +
        +
      6. +
      7. +

        + In project properties, Build tab, + turn off Register for COM Interop. +

        +
      8. +
      9. +

        + Modify the driver class declaration to inherit from + ReferenceCountedObjectBase. Examples:
        C#: +

        +
        +              public class Telescope :
        +              ReferenceCountedObjectBase,
        +              ITelescope
        +            
        +

        + VB: +

        +
        +              Public Class Telescope
        +              '==================================
        +              Inherits ReferenceCountedObjectBase
        +              Implements ITelescope
        +              '==================================
        +            
        +
      10. +
      11. +

        + In driver.cs/driver.vb, remove + the entire ASCOM Registration region +

        +
      12. +
      13. +

        + In driver.cs/driver.vb, remove + the private strings for driver ID and driver description. + They + may be needed internally, and if so should be set from the + associated attributes, ServedClassName for the description and + ProgId for the driver Id. + +

        +
      14. +
      15. +

        + Modify the class attributes by + adding the ServedClassName and ProgID attributes. The + ServedClassName attribute must be the friendly name shown as the + device name in the Chooser and the ProgId the progid of the driver + e.g. ASCOM.SuperScope.Telescope. The class header should look like + this: +

        +

        C#:

        +
        +              
        +                [Guid("0AE8B38D-10A1-4A8D-A5B7-1B050F74B48B")]  // set by the template
        +                [ProgId("ASCOM.SuperScope.Telescope")]
        +                [ServedClassName ("Super Scope Telescope")]
        +                [ClassInterface(ClassInterfaceType.None)]
        +                public class Telescope : ReferenceCountedObjectBase , ITelescope
        +              
        +            
        +
      16. +
      +
    12. +
    +

    +
    +

    +
      +
        +

        VB:

        +
        +          
        +            <Guid(“0AE8B38D-10A1-4A8D-A5B7-1B050F74B48B”)>
        +            <ProgId(“ASCOM.SuperScope.Telescope”)>
        +            <ServedClassName(“Super Scope Telescope”)>
        +            Public Class Telescope
        +            '==================================
        +            Inherits ReferenceCountedObjectBase
        +            Implements ITelescope
        +            '==================================
        +          
        +        
        +
      +
    +

    + Add the following line to the driver + constructor, this sets the driver ID using the ProgId Attribute: +

    +
      +
        +

        C#

        +
        +          
        +            s_csDriverID = Marshal.GenerateProgIdForType(this.GetType());
        +          
        +        
        +

        VB:

        +
        +          
        +            s_csDriverID = Marshal.GenerateProgIdForType(Me.GetType())
        +          
        +        
        +
      +
    1. +

      + Unless you're writing a + single-driver hub, you will have two or more driver types (e.g. + Telescope and Focuser) and thus two or more driver assembly projects + added. Presumably, these drivers need to share some resources (e.g. + a single COM port via Helper.Serial). + Put shared resources into + the SharedResources class provided + . There are some examples that + should give a clue, modify and delete these as required. +

      +
    2. +
    3. +

      + A shared serial port is already + provided (see SharedResources.cs) as SharedResources.SharedSerial + and it is an ASCOM Helper Serial object. You may wish to define + additional shared resources in static member variables with public + static accessor properties as is already done for SharedSerial. + Unfortunately, if you are a Visual Basic programmer, you will have + to make these additions in C#. +

      +
    4. +
    5. +

      + If you are writing a hub and don't + need the serial port, in SharedResources.cs you can remove the + public static SharedSerial property, the m_SharedSerial member in + the private data region, and the line in main that initializes it. + If you don't need any other shared resources for your hub, then you + can remove the SharedResources.cs file completely. +

      +
    6. +
    7. +

      + If you modified the LocalServer, + build it again now. This will refresh the stuff that's visible to + the drivers. +

      +
    8. +
    9. +

      + Build the driver skeletons to + verify that you got all of the namespace and other variable changes. +

      +
    10. +
    11. +

      + The local server dynamically loads the driver assemblies from + the same folder as the local server executable.
      +
      During + development, you'll need to add a post-build task to each of your + driver assembly projects which puts a copy of the driver assembly + into the local server executable folder. Here is an example: +

      +
          copy "$(TargetPath)" "$(SolutionDir)\SuperScope\$(OutDir)\$(TargetFileName)"
      +

      + This assumes that the server project is called “SuperScope”, + and handles using the debug or release build.
      + Note the quotes for + possible path elements with spaces in them. + An alternative is to + set the build path to the required destination instead of the + default path. + +

      +
    12. +
    13. +

      + + Make sure the drivers are + registered through the local server by running it with the /register + parameter, see below for details. + +

      +
    14. +
    15. +

      + IMPORTANT: + With a local server based driver (or hub) it is possible for + multiple clients to control the device(s). It is up to you to + safeguard against abuse. + The sort of thing that's needed is to + have a counter of the number of connections to a device, the + connection is only fully broken when the number of connections is + zero. You may also need code to prevent several drivers from talking + to the hardware at the same time, the lock pattern is useful for + that. + +

      +
    16. +
    17. +

      + You may want to add controls and/or status information to the + main form frmMain of the local server. Please resist the temptation + to turn the local server's main form into a graphical device control + panel. Instead, make a separate application that uses the served + driver(s). A driver is not a program! +

      +
    18. +
    +

    Notes

    +
      +
    • +

      + The local server handles all of + the registration and unregistration for each of its served driver + classes, including the ASCOM Chooser info and the DCOM/AppID info + needed for activation from TheSky. By running the server from a + command line and giving /register or /unregister as the command line + option, it will register or unregister all served classes + (respectively). + Never use REGASM + on the local server executable! + + This can be done in the + Visual Studio IDE by setting the server project to run as startup + and setting the command line argument to /register in Debug – + Start Options. + +

      +
    • +
    • +

      + When you make the installer for + your local server based driver/hub, do not let it register the + executable for COM. Instead, have it activate the installed local + server with the /register option. +

      +
    • +
    • +

      + The ASCOM registration uses the ServedClassName attribute as + the friendly name that will show in the chooser and the ProgId + attribute as the driver Id. +

      +
    • +
    • +

      + The best deployment way is to install all the files in a + folder that's a sub folder of the main driver, so the SuperScope + driver files will be in the folder ...\ASCOM\Telescope\SuperScope. + This can be done in the Inno script by changing the DefaultDirName + like this:
      + DefaultDirName="{cf}\ASCOM\Telescope\SuperScope"
      then + the files can all be installed with DestDir: {app}; +

      +
    • +
    +

    + Theory of Operation +

    +

    + The local server is an executable which can provide multiple + instances of multiple drivers to multiple clients. This capability is + needed for two applications: +

    +
      +
    • +

      + A hub, which allows multiple + clients to share a single device +

      +
    • +
    • +

      + A device which provides multiple services, such as a + telescope which has a focuser built-in where both the telescope and + focuser are controlled by the same serial connection and different + client programs need to control to the focuser and telescope. +

      +
    • +
    +

    + By simply dropping suitably developed driver assemblies into the + same folder as the local server executable, the local server will + find them and register them for COM and ASCOM and serve any number of + instances of the drivers' interfaces to any number of client + programs. It does this by locating and loading the driver assemblies, + analysing them to detect their classes and interfaces, and + implementing a class factory that can create instances of them for + clients. +

    +

    + A driver is an assembly which contains a class that implements + one of the ASCOM standard driver interfaces and inherits the + ReferenceCountedObjectBase class of the local server. Apart from + that, driver assemblies are identical to those that are used + in-process (DLL-type). The instructions above detail the steps needed + to convert an in-process driver into one that can be served by the + local server. +

    +

    + The name of the local server is important, so we provide it as a + template from which you can create a local server for your + produce. To make this clear, let's assume that your company AlphaTech + produces a telescope system which contains a microcontroller that is + able to control not only the telescope mount, but also a focuser and + a camera rotator. The mount, focuser, and rotator are all controlled + via commands sent through a common serial line connecting the + computer to the microcontroller, so you need a local server. In + ASCOM, then, you probably want your system to appear as + AlphaTech.Telescope, AlphaTech.Focuser, and AlphaTech.Rotator. Then + you would name the local server AlphaTech. Be sure to give this due + consideration before creating the template, the project name is the + name of your local server. + Is this still correct? I get the + impression that ASCOM.AlphaTech.Server would be OK. + +

    +

    + The fact that driver classes inherit from the local server's + ReferenceCountedObjectBase class allows the local server to maintain + a reference count on the driver class. If a client creates an + instance of a served driver, the local server automatically starts up + and provides an instance of the class to the client. Once started the + local server can provide additional instances of any of its served + driver classes. If the reference count of all served classes drops to + zero as a result of clients releasing their instances, the local + server will automatically exit. +

    +

    + Registration services provided include not only the basic COM + class registration, but also DCOM/AppID info needed to use the served + classes from outbound connections from Software Bisque's TheSky. It + also registers the served classes for the ASCOM Chooser. The + "friendly" name of each served driver that appears in the + chooser comes from the driver's ServedClassName attribute. This also + used to identify a driver so that non driver dlls, such as Interop + dlls can be ignored. The COM ProgID for each served driver is + specified in the ProgId attribute - ASCOM.localservername.drivertype, + for example, ASCOM.AlphaTech.Telescope, where AlphaTech is the local + server name and Telescope is the type of the driver. Unregistering + removes all of this information from the system. Specifying the + ProgId as an attribute allows multiple driver assemblies to be + generated using the same source and namespace. This is used to + provide multiple instances of the same driver, each with a different + ProgId and so able to be registered separately. +

    +

    + Driver DLLs are identified for registering/unregistering because + they contain a type with the ServedClassName attribute. Only these + will be registered for Com and ASCOM. This has changed; in Platform + 5 there was no attribute and the local server attempted to register + all dlls. The new behaviour allows support dlls such as interop dlls + to be included without them being registered incorrectly. There was + also an interim version where the ServedClassName attribute was on + the assembly, not the class. + All these previous versions, and the + new drivers will operate together with Platform 6, the changes are + local to the individual drivers. + +

    +

    + Detailed Use and Deployment +

    +

    + Once you have built your local server and the served driver class + assemblies, here's how to use it. To register the served classes, + activate the local server from a shell command line with the option + /register (or /regserver, for VB6 compatibility): +

    +
    +      C:\xxx> localserver.exe /register
    +    
    +

    + To unregister the local server and its drivers, activate the local + server from a shell command line with the option /unregister (or + /unregserver for VB6 compatibility): +

    +
    +      C:\xxx> localserver.exe /unregister
    +    
    +

    + When the operating system starts the local server in response to a + client creating one of it's served driver classes, the command option + /embedding is included. The local server's code detects this and sets + a variable that you can use. +

    +

    + When deploying a hub or set of drivers + with the local server, you'll have to arrange for the local server + and the driver assemblies to be placed together in a folder in the + ASCOM driver folder. Any support files, such as Interop DLLs can be + put in the same fiolder. That's all you need to do, the local server + will find them in the same folder as it is located in. +

    +
    + + + + + + + +
    + + + + + +
    +

    ASCOM Initiative

    +
    + +
    +

    +
    +
    + +

    +
    +

    + The ASCOM Initiative consists of a group of astronomy software + developers and instrument vendors whose goals are to promote the + driver/client model and scripting automation. +

    +

    + See the + ASCOM + web site + for more information. Please participate in the + + ASCOM-Talk + Yahoo Group + . +

    +
    +
    +

    +
    +
    + +

    +

    +
    +
    + +

    + + \ No newline at end of file diff --git a/Meade.net/ReferenceCountedObject.cs b/Meade.net/ReferenceCountedObject.cs new file mode 100644 index 0000000..7c7b7f2 --- /dev/null +++ b/Meade.net/ReferenceCountedObject.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace ASCOM.Meade.net +{ + [ComVisible(false)] + public class ReferenceCountedObjectBase + { + public ReferenceCountedObjectBase() + { + // We increment the global count of objects. + Server.CountObject(); + } + + ~ReferenceCountedObjectBase() + { + // We decrement the global count of objects. + Server.UncountObject(); + // We then immediately test to see if we the conditions + // are right to attempt to terminate this server application. + Server.ExitIf(); + } + } +} diff --git a/Meade.net/Resources/ASCOM.bmp b/Meade.net/Resources/ASCOM.bmp new file mode 100644 index 0000000000000000000000000000000000000000..55516c7aaa3591604865d4cd18379f8f650c3104 GIT binary patch literal 3382 zcmeIwA#&YN425B3CLjUbgJ57$uqM1+gO+lZkut%6E<(#F6wORPc)-i=r?4!c_Vwp; zZ3Fx2>gm_x54#?Zw`LE_etx;JyM1xL@%<_@PLnpcGPUluKQDjn-|L&12NJySLSxLr z;9wF7q0kt!G&lm>q)=$g*LR%^B!og^%$Qm^0tune7=F^=2qc6;W6U^h9D#&TXpDvN zo8~x1LMSw5m*!3e5<;OdyXkPr%u*^;D_frLmI06Zw(3st}a59h(3XRzqWFR3F8nf*xCj$wg(3oxIax#z*3XRz|Zzlr@q3r$RV$Z*g8j2NO iuBTlt#|(_)(Q$tsX9dm*oE11La8}@~z*&L+tOB3FDm>c& literal 0 HcmV?d00001 diff --git a/MeadeAutostar497/AscomClasses/SetupDialogForm.cs b/Meade.net/SetupDialogForm.cs similarity index 66% rename from MeadeAutostar497/AscomClasses/SetupDialogForm.cs rename to Meade.net/SetupDialogForm.cs index 5091c9a..79b1816 100644 --- a/MeadeAutostar497/AscomClasses/SetupDialogForm.cs +++ b/Meade.net/SetupDialogForm.cs @@ -6,9 +6,9 @@ using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using ASCOM.Utilities; -using ASCOM.MeadeAutostar497; +using ASCOM.Meade.net; -namespace ASCOM.MeadeAutostar497 +namespace ASCOM.Meade.net { [ComVisible(false)] // Form not registered for COM! public partial class SetupDialogForm : Form @@ -16,16 +16,6 @@ namespace ASCOM.MeadeAutostar497 public SetupDialogForm() { InitializeComponent(); - // Initialise current values of user settings from the ASCOM Profile - InitUI(); - } - - private void cmdOK_Click(object sender, EventArgs e) // OK button event handler - { - // Place any validation constraint checks here - // Update the state variables with results from the dialogue - Telescope.comPort = (string)comboBoxComPort.SelectedItem; - Telescope.tl.Enabled = chkTrace.Checked; } private void cmdCancel_Click(object sender, EventArgs e) // Cancel button event handler @@ -48,19 +38,30 @@ namespace ASCOM.MeadeAutostar497 { MessageBox.Show(other.Message); } - } + } - private void InitUI() + public void SetProfile(ProfileProperties profileProperties) { - chkTrace.Checked = Telescope.tl.Enabled; + chkTrace.Checked = profileProperties.TraceLogger; // set the list of com ports to those that are currently available comboBoxComPort.Items.Clear(); comboBoxComPort.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); // use System.IO because it's static // select the current port if possible - if (comboBoxComPort.Items.Contains(Telescope.comPort)) + if (comboBoxComPort.Items.Contains(profileProperties.ComPort)) { - comboBoxComPort.SelectedItem = Telescope.comPort; + comboBoxComPort.SelectedItem = profileProperties.ComPort; } } + + public ProfileProperties GetProfile() + { + var profileProperties = new ProfileProperties + { + TraceLogger = chkTrace.Checked, + ComPort = comboBoxComPort.SelectedItem.ToString() + }; + + return profileProperties; + } } } \ No newline at end of file diff --git a/MeadeAutostar497/AscomClasses/SetupDialogForm.designer.cs b/Meade.net/SetupDialogForm.designer.cs similarity index 96% rename from MeadeAutostar497/AscomClasses/SetupDialogForm.designer.cs rename to Meade.net/SetupDialogForm.designer.cs index 913fdc4..881dfcd 100644 --- a/MeadeAutostar497/AscomClasses/SetupDialogForm.designer.cs +++ b/Meade.net/SetupDialogForm.designer.cs @@ -1,4 +1,4 @@ -namespace ASCOM.MeadeAutostar497 +namespace ASCOM.Meade.net { partial class SetupDialogForm { @@ -48,7 +48,6 @@ namespace ASCOM.MeadeAutostar497 this.cmdOK.TabIndex = 0; this.cmdOK.Text = "OK"; this.cmdOK.UseVisualStyleBackColor = true; - this.cmdOK.Click += new System.EventHandler(this.cmdOK_Click); // // cmdCancel // @@ -74,7 +73,7 @@ namespace ASCOM.MeadeAutostar497 // this.picASCOM.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.picASCOM.Cursor = System.Windows.Forms.Cursors.Hand; - this.picASCOM.Image = global::ASCOM.MeadeAutostar497.Properties.Resources.ASCOM; + this.picASCOM.Image = global::ASCOM.Meade.net.Properties.Resources.ASCOM; this.picASCOM.Location = new System.Drawing.Point(292, 9); this.picASCOM.Name = "picASCOM"; this.picASCOM.Size = new System.Drawing.Size(48, 56); @@ -129,7 +128,7 @@ namespace ASCOM.MeadeAutostar497 this.Name = "SetupDialogForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "MeadeAutostar497 Setup"; + this.Text = "Meade.net Setup"; ((System.ComponentModel.ISupportInitialize)(this.picASCOM)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/MeadeAutostar497/AscomClasses/SetupDialogForm.resx b/Meade.net/SetupDialogForm.resx similarity index 100% rename from MeadeAutostar497/AscomClasses/SetupDialogForm.resx rename to Meade.net/SetupDialogForm.resx diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs new file mode 100644 index 0000000..342e56c --- /dev/null +++ b/Meade.net/SharedResources.cs @@ -0,0 +1,382 @@ +// +// ================ +// Shared Resources +// ================ +// +// This class is a container for all shared resources that may be needed +// by the drivers served by the Local Server. +// +// NOTES: +// +// * ALL DECLARATIONS MUST BE STATIC HERE!! INSTANCES OF THIS CLASS MUST NEVER BE CREATED! +// +// Written by: Bob Denny 29-May-2007 +// Modified by Chris Rowland and Peter Simpson to hamdle multiple hardware devices March 2011 +// +using System; +using System.Collections.Generic; +using System.Text; +using ASCOM; +using ASCOM.Utilities; + +namespace ASCOM.Meade.net +{ + public class ProfileProperties + { + // properies that are part of the profile + public string ComPort { get; set; } + public bool TraceLogger { get; set; } + } + + /// + /// The resources shared by all drivers and devices, in this example it's a serial port with a shared SendMessage method + /// an idea for locking the message and handling connecting is given. + /// In reality extensive changes will probably be needed. + /// Multiple drivers means that several applications connect to the same hardware device, aka a hub. + /// Multiple devices means that there are more than one instance of the hardware, such as two focusers. + /// In this case there needs to be multiple instances of the hardware connector, each with it's own connection count. + /// + public static class SharedResources + { + // object used for locking to prevent multiple drivers accessing common code at the same time + private static readonly object lockObject = new object(); + + // Shared serial port. This will allow multiple drivers to use one single serial port. + private static ASCOM.Utilities.Serial s_sharedSerial = new ASCOM.Utilities.Serial(); // Shared serial port + private static int s_z = 0; // counter for the number of connections to the serial port + + // + // Public access to shared resources + // + + #region single serial port connector + + // + // this region shows a way that a single serial port could be connected to by multiple + // drivers. + // + // Connected is used to handle the connections to the port. + // + // SendMessage is a way that messages could be sent to the hardware without + // conflicts between different drivers. + // + // All this is for a single connection, multiple connections would need multiple ports + // and a way to handle connecting and disconnection from them - see the + // multi driver handling section for ideas. + // + + /// + /// Shared serial port + /// + public static ASCOM.Utilities.Serial SharedSerial + { + get { return s_sharedSerial; } + } + + /// + /// number of connections to the shared serial port + /// + public static int connections + { + get { return s_z; } + set { s_z = value; } + } + + public static void SendBlind(string message) + { + lock (lockObject) + { + SharedSerial.ClearBuffers(); + SharedSerial.Transmit(message); + } + } + + public static bool SendBool(string message) + { + SharedSerial.ClearBuffers(); + return SendChar(message) == "1"; + } + + /// + /// Example of a shared SendMessage method, the lock + /// prevents different drivers tripping over one another. + /// It needs error handling and assumes that the message will be sent unchanged + /// and that the reply will always be terminated by a "#" character. + /// + /// + /// + public static string SendString(string message) + { + lock (lockObject) + { + SharedSerial.ClearBuffers(); + SharedSerial.Transmit(message); + return SharedSerial.ReceiveTerminated("#").TrimEnd('#'); + } + } + + public static string SendChar(string message) + { + lock (lockObject) + { + SharedSerial.ClearBuffers(); + SharedSerial.Transmit(message); + return SharedSerial.ReceiveCounted(1); + } + } + + public static string ReadTerminated() + { + lock (lockObject) + { + return SharedSerial.ReceiveTerminated("#"); + } + } + + /// + /// Example of handling connecting to and disconnection from the + /// shared serial port. + /// Needs error handling + /// the port name etc. needs to be set up first, this could be done by the driver + /// checking Connected and if it's false setting up the port before setting connected to true. + /// It could also be put here. + /// + public static bool Connected + { + set + { + lock (lockObject) + { + if (value) + { + if (s_z == 0) + SharedSerial.Connected = true; + s_z++; + } + else + { + s_z--; + if (s_z <= 0) + { + SharedSerial.Connected = false; + } + } + } + } + get { return SharedSerial.Connected; } + } + + #endregion + + #region Profile + + internal static string driverID = "ASCOM.MeadeGeneric.Telescope"; + + // Constants used for Profile persistence + internal static string comPortProfileName = "COM Port"; + internal static string traceStateProfileName = "Trace Level"; + + public static void WriteProfile(ProfileProperties profileProperties) + { + using (Profile driverProfile = new Profile()) + { + driverProfile.DeviceType = "Telescope"; + driverProfile.WriteValue(driverID, traceStateProfileName, profileProperties.TraceLogger.ToString()); + driverProfile.WriteValue(driverID, comPortProfileName, profileProperties.ComPort); + } + } + + private static readonly string comPortDefault = "COM1"; + internal static string traceStateDefault = "false"; + + public static ProfileProperties ReadProfile() + { + ProfileProperties profileProperties = new ProfileProperties(); + using (Profile driverProfile = new Profile()) + { + driverProfile.DeviceType = "Telescope"; + profileProperties.ComPort = + driverProfile.GetValue(driverID, comPortProfileName, string.Empty, comPortDefault); + profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(driverID, + traceStateProfileName, string.Empty, traceStateDefault)); + } + + return profileProperties; + } + + #endregion + + #region SetupDialog + + public static void SetupDialog() + { + // consider only showing the setup dialog if not connected + // or call a different dialog if connected + if (SharedSerial.Connected) + { + System.Windows.Forms.MessageBox.Show("Already connected, please disconnect before altering settings"); + return; + } + + var profileProperties = ReadProfile(); + + using (SetupDialogForm F = new SetupDialogForm()) + { + F.SetProfile(profileProperties); + + var result = F.ShowDialog(); + if (result == System.Windows.Forms.DialogResult.OK) + { + profileProperties = F.GetProfile(); + + WriteProfile(profileProperties); // Persist device configuration values to the ASCOM Profile store + } + } + } + + #endregion + + #region Multi Driver handling + + // this section illustrates how multiple drivers could be handled, + // it's for drivers where multiple connections to the hardware can be made and ensures that the + // hardware is only disconnected from when all the connected devices have disconnected. + + // It is NOT a complete solution! This is to give ideas of what can - or should be done. + // + // An alternative would be to move the hardware control here, handle connecting and disconnecting, + // and provide the device with a suitable connection to the hardware. + // + /// + /// dictionary carrying device connections. + /// The Key is the connection number that identifies the device, it could be the COM port name, + /// USB ID or IP Address, the Value is the DeviceHardware class + /// + private static Dictionary connectedDevices = new Dictionary(); + + /// + /// This is called in the driver Connect(true) property, + /// it add the device id to the list of devices if it's not there and increments the device count. + /// + /// + public static void Connect(string deviceId) + { + lock (lockObject) + { + if (!connectedDevices.ContainsKey(deviceId)) + connectedDevices.Add(deviceId, new DeviceHardware()); + connectedDevices[deviceId].count++; // increment the value + + if (deviceId == "Serial") + { + if (connectedDevices[deviceId].count == 1) + { + var profileProperties = ReadProfile(); + SharedResources.SharedSerial.PortName = profileProperties.ComPort; + SharedResources.SharedSerial.DTREnable = false; + SharedResources.SharedSerial.RTSEnable = false; + SharedResources.SharedSerial.DataBits = 8; + SharedResources.SharedSerial.StopBits = SerialStopBits.One; + SharedResources.SharedSerial.Parity = SerialParity.None; + SharedResources.SharedSerial.Speed = SerialSpeed.ps9600; + SharedResources.SharedSerial.Handshake = SerialHandshake.None; + SharedResources.SharedSerial.Connected = true; + + string firmware = SendString(":GVN#"); + } + } + } + } + + public static void Disconnect(string deviceId) + { + lock (lockObject) + { + if (connectedDevices.ContainsKey(deviceId)) + { + connectedDevices[deviceId].count--; + if (connectedDevices[deviceId].count <= 0) + { + connectedDevices.Remove(deviceId); + if (deviceId == "Serial") + { + SharedResources.SharedSerial.Connected = false; + } + } + } + } + } + + public static bool IsConnected(string deviceId) + { + if (connectedDevices.ContainsKey(deviceId)) + return (connectedDevices[deviceId].count > 0); + else + return false; + } + + #endregion + + public static void Lock(Action action) + { + lock (lockObject) + { + action(); + } + } + + public static T Lock(Func func) + { + lock (lockObject) + { + return func(); + } + } + + /// + /// Skeleton of a hardware class, all this does is hold a count of the connections, + /// in reality extra code will be needed to handle the hardware in some way + /// + public class DeviceHardware + { + private int _count; + + internal int count + { + set => _count = value; + get => _count; + } + + internal DeviceHardware() + { + count = 0; + } + } + + //#region ServedClassName attribute + ///// + ///// This is only needed if the driver is targeted at platform 5.5, it is included with Platform 6 + ///// + //[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + //public sealed class ServedClassNameAttribute : Attribute + //{ + // // See the attribute guidelines at + // // http://go.microsoft.com/fwlink/?LinkId=85236 + + // /// + // /// Gets or sets the 'friendly name' of the served class, as registered with the ASCOM Chooser. + // /// + // /// The 'friendly name' of the served class. + // public string DisplayName { get; private set; } + // /// + // /// Initializes a new instance of the class. + // /// + // /// The 'friendly name' of the served class. + // public ServedClassNameAttribute(string servedClassName) + // { + // DisplayName = servedClassName; + // } + //} + //#endregion + } +} \ No newline at end of file diff --git a/Meade.net/app.config b/Meade.net/app.config new file mode 100644 index 0000000..70dcdba --- /dev/null +++ b/Meade.net/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Meade.net/frmMain.Designer.cs b/Meade.net/frmMain.Designer.cs new file mode 100644 index 0000000..83c8dd1 --- /dev/null +++ b/Meade.net/frmMain.Designer.cs @@ -0,0 +1,63 @@ +using System; + +namespace ASCOM.Meade.net +{ + partial class frmMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Location = new System.Drawing.Point(12, 10); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(199, 33); + this.label1.TabIndex = 0; + this.label1.Text = "This is an ASCOM driver, not a program for you to use."; + // + // frmMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(233, 52); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "frmMain"; + this.Text = "Meade.net Driver Server"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + + } +} + diff --git a/Meade.net/frmMain.cs b/Meade.net/frmMain.cs new file mode 100644 index 0000000..92b3be7 --- /dev/null +++ b/Meade.net/frmMain.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ASCOM.Meade.net +{ + public partial class frmMain : Form + { + delegate void SetTextCallback(string text); + + public frmMain() + { + InitializeComponent(); + } + + } +} \ No newline at end of file diff --git a/Meade.net/frmMain.resx b/Meade.net/frmMain.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Meade.net/frmMain.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 b/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 deleted file mode 100644 index 213c64d..0000000 --- a/MeadeAutostar497.UnitTests/BootstrapAscomProfileStore.ps1 +++ /dev/null @@ -1,36 +0,0 @@ -<# -This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work -without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, -it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on -ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. - -NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. -#> - -$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node -if ($wow) - { - $root = "HKLM:\SOFTWARE\Wow6432Node" - } -else - { - $root = "HKLM:\SOFTWARE" - } -$ascomRoot = $root + "\ASCOM" - -if (Test-Path $ascomRoot) - { - <# Don't upset an already-existing ASCOM registry #> - exit - } - -<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> -New-Item -Path $root -Name ASCOM –Force -$ascomAcl = Get-Acl $ascomRoot -$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") -$ascomAcl.SetAccessRule($aclRule) -$ascomAcl | Set-Acl -Path $ascomRoot - -<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> -New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force -New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj b/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj deleted file mode 100644 index 47bf469..0000000 --- a/MeadeAutostar497.UnitTests/MeadeAutostar497.UnitTests.csproj +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - Debug - AnyCPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F} - Library - Properties - MeadeAutostar497.UnitTests - MeadeAutostar497.UnitTests - v4.6.2 - 512 - true - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - AnyCPU - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll - - - ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll - - - ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll - - - ..\packages\Moq.4.10.1\lib\net45\Moq.dll - - - ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll - - - - - - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll - - - - - ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - - - - - - - - - - - - - - - - - - {64308775-bd4a-469c-bcab-3ed830b811af} - MeadeAutostar497 - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs b/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs deleted file mode 100644 index 97f4fcf..0000000 --- a/MeadeAutostar497.UnitTests/TelescopeControllerUnitTests.cs +++ /dev/null @@ -1,556 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.IO.Ports; -using ASCOM; -using ASCOM.DeviceInterface; -using ASCOM.MeadeAutostar497.Controller; -using Moq; -using NUnit.Framework; - -namespace MeadeAutostar497.UnitTests -{ - [TestFixture] - public class TelescopeControllerUnitTests - { - private Mock serialMock; - - private readonly List _availableComPorts = new List { "COM1", "COM2", "COM3" }; - private TelescopeController _telescopeController; - - private string _stringToRecieve = string.Empty; - private bool _isConnected = false; - - [SetUp] - public void Setup() - { - _stringToRecieve = string.Empty; - _isConnected = false; - - serialMock = new Mock(); - serialMock.SetupAllProperties(); - serialMock.Setup(x => x.GetPortNames()).Returns(() => _availableComPorts.ToArray()); - serialMock.Setup(x => x.CommandTerminated(It.IsAny(), It.IsAny())) - .Returns(() => _stringToRecieve); - serialMock.Setup(x => x.IsOpen).Returns(() => _isConnected); - - //Todo inject the serialMock instead of using a singleton to increase code stability. - _telescopeController = TelescopeController.Instance; - _telescopeController.SerialPort = serialMock.Object; - } - - [TearDown] - public void TearDown() - { - _isConnected = false; - _telescopeController.Connected = false; - _telescopeController.Port = "COM1"; - } - - [Test] - public void ImplementsExpectedInterfaces() - { - Assert.That(_telescopeController, Is.Not.Null); - Assert.That(_telescopeController, Is.AssignableTo()); - } - - [Test] - public void NotConnectedByDefault() - { - Assert.That(_telescopeController.Connected, Is.False); - } - - [Test] - public void ConnectedCanBeSetTrue() - { - _stringToRecieve = "test#"; - _isConnected = true; - - _telescopeController.Connected = true; - Assert.That(_telescopeController.Connected, Is.True); - } - - [Test] - public void EnsureThatTheSerialCommunicationsAreSetCorrectly() - { - Assert.That(serialMock.Object.IsOpen, Is.False); - - _stringToRecieve = "test#"; - _telescopeController.Connected = true; - _isConnected = true; - Assert.That(_telescopeController.Connected, Is.True); - - serialMock.Verify(x => x.Open(), Times.Once); - - Assert.That(serialMock.Object.DtrEnable, Is.False); - Assert.That(serialMock.Object.RtsEnable, Is.False); - Assert.That(serialMock.Object.BaudRate, Is.EqualTo(9600)); - Assert.That(serialMock.Object.DataBits, Is.EqualTo(8)); - Assert.That(serialMock.Object.StopBits, Is.EqualTo(StopBits.One)); - Assert.That(serialMock.Object.Parity, Is.EqualTo(Parity.None)); - Assert.That(serialMock.Object.PortName, Is.EqualTo(_telescopeController.Port)); - Assert.That(serialMock.Object.IsOpen, Is.True); - - } - - [Test] - public void WhenOpensComPortToNonAutostarThrowException() - { - Assert.That(serialMock.Object.IsOpen, Is.False); - var exception = Assert.Throws(() => { _telescopeController.Connected = true; }); - - Assert.That(exception.Message, Is.EqualTo("Failed to communicate with telescope.")); - - Assert.That(_telescopeController.Connected, Is.False); - } - - [Test] - public void CannotChangeSerialPortObjectWhenConnected() - { - _stringToRecieve = "test#"; - _isConnected = true; - - _telescopeController.Connected = true; - - Mock newSerialMock = new Mock(); - - var exception = Assert.Throws( () => { _telescopeController.SerialPort = newSerialMock.Object; }); - - Assert.That(exception, Is.Not.Null); - Assert.That(exception.Message, Is.EqualTo("Please disconnect before changing the serial engine.")); - } - - [Test] - public void PortIsSetToCom1ByDefault() - { - Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); - } - - [Test] - public void SettingPortToValidPortAllowed() - { - _telescopeController.Port = "COM2"; - - Assert.That(_telescopeController.Port, Is.EqualTo("COM2")); - } - - [Test] - public void SettingPortToValidPortWhenConnectedFails() - { - _stringToRecieve = "test#"; - _isConnected = true; - - _telescopeController.Connected = true; - var exception = Assert.Throws( () => _telescopeController.Port = "COM2"); - - Assert.That(exception.Message, Is.EqualTo("Please disconnect from the scope before changing port.")); - - Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); //port hasn't changed - } - - [Test] - public void SettingPortToInvalidPortFails() - { - var exception = Assert.Throws(() => _telescopeController.Port = "COM5"); - - Assert.That(exception.Message, Is.EqualTo("Unable to select port COM5 as it does not exist.")); - - Assert.That(_telescopeController.Port, Is.EqualTo("COM1")); //port hasn't changed - } - - [Test] - public void AbortSlewWorks() - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.AbortSlew(); - - serialMock.Verify(x => x.Command("#:Q#"), Times.Once); - } - - [Test] - public void SlewingReturnTrueAsExpected() - { - _isConnected = true; - - _telescopeController.Connected = true; - - serialMock.Setup(x => x.CommandTerminated(":D#", "#")).Returns("|"); - - var slewing = _telescopeController.Slewing; - - Assert.That(slewing, Is.True); - } - - [Test] - public void SlewingReturnFalseAsExpected() - { - _isConnected = true; - - _telescopeController.Connected = true; - - serialMock.Setup(x => x.CommandTerminated(":D#", "#")).Returns(string.Empty); - - var slewing = _telescopeController.Slewing; - - Assert.That(slewing, Is.False); - } - - [Test] - public void utcDate_Get_ReturnsExpectedValue() - { - DateTime expectedDate = new DateTime(2019, 04, 30, 11, 32, 24, DateTimeKind.Local); - - var dateString = "04/30/19"; - var timeString = "12:32:24"; - - _isConnected = true; - - _telescopeController.Connected = true; - - serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); - serialMock.Setup(x => x.CommandTerminated(":GC#", "#")).Returns(dateString); - serialMock.Setup(x => x.CommandTerminated(":GL#", "#")).Returns(timeString); - - var result = _telescopeController.utcDate; - - Assert.That(result, Is.EqualTo(expectedDate)); - } - - [Test] - public void utcDate_Set_SetsTelescopeDateAndTime() - { - DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); - - serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); - serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour+1:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); - serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); - - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.utcDate = testDateTime; - } - - [Test] - public void utcDate_Set_ThrowsExceptionWhenTimeInvalid() - { - DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Utc); - - serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); - //serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); - serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); - - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws( () => {_telescopeController.utcDate = testDateTime; }); - - Assert.That( exception.Message, Is.EqualTo("Failed to set local time")); - } - - [Test] - public void utcDate_Set_ThrowsExceptionWhenDateInvalid() - { - DateTime testDateTime = new DateTime(2019, 04, 30, 19, 53, 32, DateTimeKind.Local); - - serialMock.Setup(x => x.CommandTerminated(":GG#", "#")).Returns("-01"); - serialMock.Setup(x => x.CommandChar($":SL{testDateTime.Hour+1:00}:{testDateTime.Minute:00}:{testDateTime.Second:00}#")).Returns('1'); - //serialMock.Setup(x => x.CommandChar($":SC{testDateTime.Month:00}/{testDateTime.Day:00}/{testDateTime:yy}#")).Returns('1'); - - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.utcDate = testDateTime; }); - - Assert.That(exception.Message, Is.EqualTo("Failed to set local date")); - } - - [TestCase("+12*34", 12.566666666666666)] - [TestCase("+12*34.56", 12.582222222222223)] - [TestCase("-67*34.56", -67.582222222222214)] - public void SiteLatitude_Get_ReturnsExpectedDouble( string latitude, double expectedResult) - { - serialMock.Setup(x => x.CommandTerminated(":Gt#", "#")).Returns(latitude); - - _isConnected = true; - - _telescopeController.Connected = true; - - var result = _telescopeController.SiteLatitude; - - Assert.That(result, Is.EqualTo(expectedResult)); - } - - [Test] - public void SiteLatitude_Set_ThrowsExeptionWhenValueTooSmall() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws( () => { _telescopeController.SiteLatitude = -91;}); - - Assert.That(exception.Message, Is.EqualTo("Latitude cannot be less than -90 degrees.")); - } - - [Test] - public void SiteLatitude_Set_ThrowsExeptionWhenValueTooLarge() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 91; }); - - Assert.That(exception.Message, Is.EqualTo("Latitude cannot be greater than 90 degrees.")); - } - - [Test] - public void SiteLatitude_Set_ThrowsExeptionWhenTelescopeReportsFail() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.SiteLatitude = 10; }); - - Assert.That(exception.Message, Is.EqualTo("Failed to set site latitude.")); - } - - [Test] - public void SiteLatitude_Set_NoErrorWhenValidValueSentSuccessfully() - { - serialMock.Setup(x => x.CommandChar(":Sts10*00#")).Returns('1'); - - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.SiteLatitude = 10; - } - - - [TestCase("012*34", 12.566666666666666)] - [TestCase("012:34.56", 12.582222222222223)] - [TestCase("350:34.56", -9.4177777777777578)] - public void SiteLongitude_Get_ReturnsExpectedDouble(string longitude, double expectedResult) - { - serialMock.Setup(x => x.CommandTerminated(":Gg#", "#")).Returns(longitude); - - _isConnected = true; - - _telescopeController.Connected = true; - - var result = _telescopeController.SiteLongitude; - - Assert.That(result, Is.EqualTo(expectedResult)); - } - - [Test] - public void SiteLongitude_Set_ThrowsExeptionWhenValueTooSmall() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = -181; }); - - Assert.That(exception.Message, Is.EqualTo("Longitude cannot be lower than -180 degrees.")); - } - - [Test] - public void SiteLongitude_Set_ThrowsExeptionWhenValueTooLarge() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 181; }); - - Assert.That(exception.Message, Is.EqualTo("Longitude cannot be greater than 180 degrees.")); - } - - [Test] - public void SiteLongitude_Set_ThrowsExeptionWhenTelescopeReportsFail() - { - _isConnected = true; - - _telescopeController.Connected = true; - - var exception = Assert.Throws(() => { _telescopeController.SiteLongitude = 10; }); - - Assert.That(exception.Message, Is.EqualTo("Failed to set site longitude.")); - } - - [Test] - public void SiteLongitude_Set_NoErrorWhenValidValueSentSuccessfully() - { - serialMock.Setup(x => x.CommandChar(":Sg010*00#")).Returns('1'); - - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.SiteLongitude = 10; - } - - [Test] - public void PulseGuideEast() - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.PulseGuide(GuideDirections.guideEast,100); - - serialMock.Verify( x => x.Command(":Mge0100#"), Times.Once); - } - - [Test] - public void PulseGuideWest() - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.PulseGuide(GuideDirections.guideWest, 1200); - - serialMock.Verify(x => x.Command(":Mgw1200#"), Times.Once); - } - - [Test] - public void PulseGuideNorth() - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.PulseGuide(GuideDirections.guideNorth, 256); - - serialMock.Verify(x => x.Command(":Mgn0256#"), Times.Once); - } - - [Test] - public void PulseGuideSouth() - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.PulseGuide(GuideDirections.guideSouth, 1024); - - serialMock.Verify(x => x.Command(":Mgs1024#"), Times.Once); - } - - [TestCase('A', AlignmentModes.algAltAz)] - [TestCase('P', AlignmentModes.algPolar)] - public void AlignmentMode_Get_ReturnsExpectedValue(char commandResponse, AlignmentModes mode) - { - const char ack = (char)6; - - serialMock.Setup(x => x.CommandChar(ack.ToString())).Returns(commandResponse); - - _isConnected = true; - - _telescopeController.Connected = true; - - var result = _telescopeController.AlignmentMode; - - Assert.That(result, Is.EqualTo(mode)); - } - - [TestCase(AlignmentModes.algAltAz, ":AA#")] - [TestCase(AlignmentModes.algPolar, ":AP#")] - [TestCase(AlignmentModes.algGermanPolar, ":AP#")] - public void AligmentMode_Set_WorksAsExpected(AlignmentModes mode, string command) - { - _isConnected = true; - - _telescopeController.Connected = true; - - _telescopeController.AlignmentMode = mode; - - serialMock.Verify( x => x.Command(command), Times.Once); - } - - [Test] - public void AtParkIsFalseByDefault() - { - _isConnected = true; - _telescopeController.Connected = true; - - Assert.That( _telescopeController.AtPark, Is.False ); - } - - [Test] - public void AtParkIsTrueAfterParkingScope() - { - _isConnected = true; - - _telescopeController.Connected = true; - _telescopeController.Park(); - - Assert.That(_telescopeController.AtPark, Is.True); - } - - [Test] - public void Park_CallingParkSendsTheParkCommand() - { - _isConnected = true; - - _telescopeController.Connected = true; - _telescopeController.Park(); - - serialMock.Verify( x => x.Command(":hP#"), Times.Once); - } - - [Test] - public void Park_ParkingSecondTimeDoesNothing() - { - _isConnected = true; - - _telescopeController.Connected = true; - _telescopeController.Park(); - - _telescopeController.Park(); - - serialMock.Verify(x => x.Command(":hP#"), Times.Once); - } - - [TestCase("356*13",356.21666666666664)] - [TestCase("356*13'21", 356.22249999999997)] - public void Azimuth_CanGetValue( string response, double expectedResult ) - { - serialMock.Setup(x => x.CommandTerminated(":GZ#", "#")).Returns(response); - - _isConnected = true; - - _telescopeController.Connected = true; - - var az = _telescopeController.Azimuth; - - Assert.That( az, Is.EqualTo(expectedResult)); - } - - [TestCase("+75*13", 75.2166666666666654)] - [TestCase("+65*13'21", 65.222499999999997)] - public void Declination_CanGetValue(string response, double expectedResult) - { - serialMock.Setup(x => x.CommandTerminated(":GD#", "#")).Returns(response); - - _isConnected = true; - - _telescopeController.Connected = true; - - var result = _telescopeController.Declination; - - Assert.That(result, Is.EqualTo(expectedResult)); - } - } -} diff --git a/MeadeAutostar497.UnitTests/packages.config b/MeadeAutostar497.UnitTests/packages.config deleted file mode 100644 index e7172db..0000000 --- a/MeadeAutostar497.UnitTests/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/MeadeAutostar497.sln b/MeadeAutostar497.sln deleted file mode 100644 index 69570e9..0000000 --- a/MeadeAutostar497.sln +++ /dev/null @@ -1,49 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.136 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeadeAutostar497", "MeadeAutostar497\MeadeAutostar497.csproj", "{64308775-BD4A-469C-BCAB-3ED830B811AF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeadeAutostar497.UnitTests", "MeadeAutostar497.UnitTests\MeadeAutostar497.UnitTests.csproj", "{9638DA27-77C7-4B30-A730-6E7159A4A09F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsole", "TestConsole\TestConsole.csproj", "{D5207217-61C7-4E94-8097-91DBACE57D2A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|x86.ActiveCfg = Debug|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Debug|x86.Build.0 = Debug|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|Any CPU.Build.0 = Release|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|x86.ActiveCfg = Release|Any CPU - {9638DA27-77C7-4B30-A730-6E7159A4A09F}.Release|x86.Build.0 = Release|Any CPU - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86 - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86 - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.ActiveCfg = Release|x86 - {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FD610065-5DB2-4D32-8760-4E0552901C28} - EndGlobalSection -EndGlobal diff --git a/MeadeAutostar497/AscomClasses/Telescope.cs b/MeadeAutostar497/AscomClasses/Telescope.cs deleted file mode 100644 index 5f3c794..0000000 --- a/MeadeAutostar497/AscomClasses/Telescope.cs +++ /dev/null @@ -1,1226 +0,0 @@ -//tabs=4 -// -------------------------------------------------------------------------------- -// TODO fill in this information for your driver, then remove this line! -// -// ASCOM Telescope driver for MeadeAutostar497 -// -// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam -// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam -// erat, sed diam voluptua. At vero eos et accusam et justo duo -// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata -// sanctus est Lorem ipsum dolor sit amet. -// -// Implements: ASCOM Telescope interface version: -// Author: (XXX) Your N. Here -// -// Edit Log: -// -// Date Who Vers Description -// ----------- --- ----- ------------------------------------------------------- -// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template -// -------------------------------------------------------------------------------- -// - - -// This is used to define code in the template that is specific to one class implementation -// unused code canbe deleted and this definition removed. -#define Telescope - -using System; -using System.Runtime.InteropServices; -using ASCOM; -using ASCOM.Astrometry; -using ASCOM.Astrometry.AstroUtils; -using ASCOM.Utilities; -using ASCOM.DeviceInterface; -using System.Globalization; -using System.Collections; -using ASCOM.MeadeAutostar497.Controller; -using static System.String; - -namespace ASCOM.MeadeAutostar497 -{ - // - // Your driver's DeviceID is ASCOM.MeadeAutostar497.Telescope - // - // The Guid attribute sets the CLSID for ASCOM.MeadeAutostar497.Telescope - // The ClassInterface/None addribute prevents an empty interface called - // _MeadeAutostar497 from being created and used as the [default] interface - // - // TODO Replace the not implemented exceptions with code to implement the function or - // throw the appropriate ASCOM exception. - // - - /// - /// ASCOM Telescope Driver for MeadeAutostar497. - /// - [Guid("58e4fe97-1760-4e22-8ecd-2225876aeefc")] - [ClassInterface(ClassInterfaceType.None)] - public class Telescope : ITelescopeV3, IFocuserV3 - { - private ITelescopeController _telescopeController; - - /// - /// ASCOM DeviceID (COM ProgID) for this driver. - /// The DeviceID is used by ASCOM applications to load the driver at runtime. - /// - internal static string driverID = "ASCOM.MeadeAutostar497.Telescope"; - // TODO Change the descriptive string for your driver then remove this line - /// - /// Driver description that displays in the ASCOM Chooser. - /// - private static string driverDescription = "Meade Autostar 497 .net"; - - internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence - internal static string comPortDefault = "COM1"; - internal static string traceStateProfileName = "Trace Level"; - internal static string traceStateDefault = "false"; - - internal static string comPort; // Variables to hold the currrent device configuration - - /// - /// Private variable to hold an ASCOM Utilities object - /// - private Util utilities; - - /// - /// Private variable to hold an ASCOM AstroUtilities object to provide the Range method - /// - private AstroUtils astroUtilities; - - /// - /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) - /// - internal static TraceLogger tl; - - /// - /// Initializes a new instance of the class. - /// Must be public for COM registration. - /// - public Telescope() - { - tl = new TraceLogger("", "MeadeAutostar497"); - ReadProfile(); // Read device configuration from the ASCOM Profile store - - tl.LogMessage("Telescope", "Starting initialisation"); - - utilities = new Util(); //Initialise util object - astroUtilities = new AstroUtils(); // Initialise astro utilities object - - //TODO: Implement your additional construction here - _telescopeController = TelescopeController.Instance; - - tl.LogMessage("Telescope", "Completed initialisation"); - } - - - // - // PUBLIC COM INTERFACE ITelescopeV3 IMPLEMENTATION - // - - #region Common properties and methods. - - /// - /// Displays the Setup Dialog form. - /// If the user clicks the OK button to dismiss the form, then - /// the new settings are saved, otherwise the old values are reloaded. - /// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED! - /// - public void SetupDialog() - { - // consider only showing the setup dialog if not connected - // or call a different dialog if connected - if (IsConnected) - { - System.Windows.Forms.MessageBox.Show("Already connected, just press OK"); - return; - } - - using (SetupDialogForm F = new SetupDialogForm()) - { - var result = F.ShowDialog(); - if (result == System.Windows.Forms.DialogResult.OK) - { - WriteProfile(); // Persist device configuration values to the ASCOM Profile store - } - } - } - - public ArrayList SupportedActions - { - get - { - tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); - return new ArrayList(); - } - } - - public string Action(string actionName, string actionParameters) - { - LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException("Action " + actionName + " is not implemented by this driver"); - } - - public void CommandBlind(string command, bool raw) - { - tl.LogMessage("CommandBlind", $"command={command} raw={raw}"); - - CheckConnected("CommandBlind"); - // Call CommandString and return as soon as it finishes - //this.CommandString(command, raw); - _telescopeController.CommandBlind(command, raw); - // or - //throw new ASCOM.MethodNotImplementedException("CommandBlind"); - // DO NOT have both these sections! One or the other - } - - public bool CommandBool(string command, bool raw) - { - tl.LogMessage("CommandBool", $"command={command} raw={raw}"); - CheckConnected("CommandBool"); - string ret = CommandString(command, raw); - // TODO decode the return string and return true or false - // or - throw new ASCOM.MethodNotImplementedException("CommandBool"); - // DO NOT have both these sections! One or the other - } - - public string CommandString(string command, bool raw) - { - tl.LogMessage("CommandString", $"command={command} raw={raw}"); - // it's a good idea to put all the low level communication with the device here, - // then all communication calls this function - // you need something to ensure that only one command is in progress at a time - CheckConnected("CommandString"); - //throw new ASCOM.MethodNotImplementedException("CommandString"); - return _telescopeController.CommandString(command, raw); - } - - public void Dispose() - { - _telescopeController.Connected = false; - - // Clean up the tracelogger and util objects - tl.Enabled = false; - tl.Dispose(); - tl = null; - utilities.Dispose(); - utilities = null; - astroUtilities.Dispose(); - astroUtilities = null; - } - - public bool Connected - { - get - { - LogMessage("Connected", "Get {0}", IsConnected); - return IsConnected; - } - set - { - tl.LogMessage("Connected", "Set {0}", value); - if (value == IsConnected) - return; - - if (value) - { - LogMessage("Connected Set", "Connecting to port {0}", comPort); - _telescopeController.Port = comPort; - _telescopeController.Connected = true; - } - else - { - LogMessage("Connected Set", "Disconnecting from port {0}", comPort); - _telescopeController.Connected = false; - } - } - } - - public string Description - { - // TODO customise this device description - get - { - tl.LogMessage("Description Get", driverDescription); - return driverDescription; - } - } - - public string DriverInfo - { - get - { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - // TODO customise this driver description - string driverInfo = Format(CultureInfo.InvariantCulture, "Information about the driver itself. Version: {0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverInfo Get", driverInfo); - return driverInfo; - } - } - - public string DriverVersion - { - get - { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - string driverVersion = Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverVersion Get", driverVersion); - return driverVersion; - } - } - - public short InterfaceVersion - { - // set by the driver wizard - get - { - LogMessage("InterfaceVersion Get", "3"); - return Convert.ToInt16("3"); - } - } - - public string Name - { - get - { - string name = "Meade Autostar 497 .net"; - tl.LogMessage("Name Get", name); - return name; - } - } - - #endregion - - #region ITelescope Implementation - public void AbortSlew() - { - tl.LogMessage("AbortSlew", "Aborting slew"); - _telescopeController.AbortSlew(); - } - - public AlignmentModes AlignmentMode - { - get - { - tl.LogMessage("AlignmentMode Get", "Getting alignmode"); - var alignmode = _telescopeController.AlignmentMode; - tl.LogMessage("AlignmentMode Get", $"alignmode = {alignmode}"); - return alignmode; - } - } - - public double Altitude - { - get - { - var alt = _telescopeController.Altitude; - tl.LogMessage("Altitude", $"{alt}"); - return alt; - } - } - - public double ApertureArea - { - get - { - tl.LogMessage("ApertureArea Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("ApertureArea", false); - } - } - - public double ApertureDiameter - { - get - { - tl.LogMessage("ApertureDiameter Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("ApertureDiameter", false); - } - } - - public bool AtHome - { - get - { - tl.LogMessage("AtHome", "Get - " + false.ToString()); - return false; - } - } - - public bool AtPark - { - get - { - var atPatk = _telescopeController.AtPark; - tl.LogMessage("AtPark", "Get - " + atPatk.ToString()); - return atPatk; - } - } - - public IAxisRates AxisRates(TelescopeAxes Axis) - { - tl.LogMessage("AxisRates", "Get - " + Axis.ToString()); - return new AxisRates(Axis); - } - - public double Azimuth - { - get - { - var az = _telescopeController.Azimuth; - tl.LogMessage("Azimuth Get", $"{az}"); - return az; - } - } - - public bool CanFindHome - { - get - { - tl.LogMessage("CanFindHome", "Get - " + false.ToString()); - return false; - } - } - - public bool CanMoveAxis(TelescopeAxes Axis) - { - tl.LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); - switch (Axis) - { - case TelescopeAxes.axisPrimary: return true; //RA or AZ - case TelescopeAxes.axisSecondary: return true; //Dev or Alt - case TelescopeAxes.axisTertiary: return false; //rotator / derotator - default: throw new InvalidValueException("CanMoveAxis", Axis.ToString(), "0 to 2"); - } - } - - public bool CanPark - { - get - { - tl.LogMessage("CanPark", "Get - " + true.ToString()); - return true; - } - } - - public bool CanPulseGuide - { - get - { - tl.LogMessage("CanPulseGuide", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSetDeclinationRate - { - get - { - tl.LogMessage("CanSetDeclinationRate", "Get - " + false.ToString()); - return false; - } - } - - public bool CanSetGuideRates - { - get - { - tl.LogMessage("CanSetGuideRates", "Get - " + false.ToString()); - return false; - } - } - - public bool CanSetPark - { - get - { - tl.LogMessage("CanSetPark", "Get - " + false.ToString()); - return false; - } - } - - public bool CanSetPierSide - { - get - { - tl.LogMessage("CanSetPierSide", "Get - " + false.ToString()); - return false; - } - } - - public bool CanSetRightAscensionRate - { - get - { - tl.LogMessage("CanSetRightAscensionRate", "Get - " + false.ToString()); - return false; - } - } - - public bool CanSetTracking - { - get - { - tl.LogMessage("CanSetTracking", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSlew - { - get - { - tl.LogMessage("CanSlew", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSlewAltAz - { - get - { - tl.LogMessage("CanSlewAltAz", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSlewAltAzAsync - { - get - { - tl.LogMessage("CanSlewAltAzAsync", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSlewAsync - { - get - { - tl.LogMessage("CanSlewAsync", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSync - { - get - { - tl.LogMessage("CanSync", "Get - " + true.ToString()); - return true; - } - } - - public bool CanSyncAltAz - { - get - { - tl.LogMessage("CanSyncAltAz", "Get - " + false.ToString()); - return false; - } - } - - public bool CanUnpark - { - get - { - tl.LogMessage("CanUnpark", "Get - " + false.ToString()); - return false; - } - } - - public double Declination - { - get - { - double declination = _telescopeController.Declination; - tl.LogMessage("Declination", "Get - " + utilities.DegreesToDMS(declination, ":", ":")); - return declination; - } - } - - public double DeclinationRate - { - get - { - double declination = 0.0; - tl.LogMessage("DeclinationRate", "Get - " + declination.ToString()); - return declination; - } - set - { - tl.LogMessage("DeclinationRate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DeclinationRate", true); - } - } - - public PierSide DestinationSideOfPier(double RightAscension, double Declination) - { - tl.LogMessage("DestinationSideOfPier Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DestinationSideOfPier", false); - } - - public bool DoesRefraction - { - get - { - tl.LogMessage("DoesRefraction Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DoesRefraction", false); - } - set - { - tl.LogMessage("DoesRefraction Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DoesRefraction", true); - } - } - - public EquatorialCoordinateType EquatorialSystem - { - get - { - EquatorialCoordinateType equatorialSystem = EquatorialCoordinateType.equTopocentric; - tl.LogMessage("DeclinationRate", "Get - " + equatorialSystem.ToString()); - return equatorialSystem; - } - } - - public void FindHome() - { - tl.LogMessage("FindHome", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("FindHome"); - } - - public double FocalLength - { - get - { - tl.LogMessage("FocalLength Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("FocalLength", false); - } - } - - public double GuideRateDeclination - { - get - { - tl.LogMessage("GuideRateDeclination Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", false); - } - set - { - tl.LogMessage("GuideRateDeclination Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", true); - } - } - - public double GuideRateRightAscension - { - get - { - tl.LogMessage("GuideRateRightAscension Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", false); - } - set - { - tl.LogMessage("GuideRateRightAscension Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", true); - } - } - - public bool IsPulseGuiding - { - get - { - tl.LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); - //throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); - return false; - } - } - - public void MoveAxis(TelescopeAxes Axis, double Rate) - { - tl.LogMessage("MoveAxis", $"Axis={Axis} rate={Rate}"); - _telescopeController.MoveAxis(Axis, Rate); - } - - public void Park() - { - tl.LogMessage("Park", "Parking telescope"); - _telescopeController.Park(); - } - - public void PulseGuide(GuideDirections Direction, int Duration) - { - tl.LogMessage("PulseGuide", $"pulse guide direction {Direction} duration {Duration}"); - _telescopeController.PulseGuide(Direction, Duration); - } - - public double RightAscension - { - get - { - double rightAscension = _telescopeController.RightAscension; - tl.LogMessage("RightAscension", "Get - " + utilities.HoursToHMS(rightAscension)); - return rightAscension; - } - } - - public double RightAscensionRate - { - get - { - double rightAscensionRate = 0.0; - tl.LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString()); - return rightAscensionRate; - } - set - { - tl.LogMessage("RightAscensionRate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("RightAscensionRate", true); - } - } - - public void SetPark() - { - tl.LogMessage("SetPark", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SetPark"); - } - - public PierSide SideOfPier - { - get - { - tl.LogMessage("SideOfPier Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SideOfPier", false); - } - set - { - tl.LogMessage("SideOfPier Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SideOfPier", true); - } - } - - public double SiderealTime - { - get - { - // Now using NOVAS 3.1 - double siderealTime = 0.0; - using (var novas = new ASCOM.Astrometry.NOVAS.NOVAS31()) - { - var jd = utilities.DateUTCToJulian(DateTime.UtcNow); - novas.SiderealTime(jd, 0, novas.DeltaT(jd), - ASCOM.Astrometry.GstType.GreenwichApparentSiderealTime, - ASCOM.Astrometry.Method.EquinoxBased, - ASCOM.Astrometry.Accuracy.Reduced, ref siderealTime); - } - - // Allow for the longitude - siderealTime += SiteLongitude / 360.0 * 24.0; - - // Reduce to the range 0 to 24 hours - siderealTime = astroUtilities.ConditionRA(siderealTime); - - tl.LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); - return siderealTime; - } - } - - public double SiteElevation - { - get - { - tl.LogMessage("SiteElevation Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteElevation", false); - } - set - { - tl.LogMessage("SiteElevation Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteElevation", true); - } - } - - public double SiteLatitude - { - get - { - var siteLatitude = _telescopeController.SiteLatitude; - tl.LogMessage("SiteLatitude Get", $"{utilities.DegreesToDMS(siteLatitude)}"); - return siteLatitude; - } - set - { - tl.LogMessage("SiteLatitude Set", $"{utilities.DegreesToDMS(value)}"); - _telescopeController.SiteLatitude = value; - } - } - - public double SiteLongitude - { - get - { - var siteLongitude = _telescopeController.SiteLongitude; - tl.LogMessage("SiteLongitude Get", $"{utilities.DegreesToDMS(siteLongitude)}"); - return siteLongitude; - } - set - { - tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(value)}"); - _telescopeController.SiteLongitude = value; - } - } - - public short SlewSettleTime - { - get - { - tl.LogMessage("SlewSettleTime Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", false); - } - set - { - tl.LogMessage("SlewSettleTime Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", true); - } - } - - public void SlewToAltAz(double Azimuth, double Altitude) - { - tl.LogMessage("SlewToAltAz", $"Az=~{Azimuth} Alt={Altitude}"); - _telescopeController.SlewToAltAz(Azimuth, Altitude); - } - - public void SlewToAltAzAsync(double Azimuth, double Altitude) - { - tl.LogMessage("SlewToAltAzAsync", $"Az=~{Azimuth} Alt={Altitude}"); - _telescopeController.SlewToAltAzAsync(Azimuth, Altitude); - } - - public void SlewToCoordinates(double RightAscension, double Declination) - { - tl.LogMessage("SlewToCoordinates", $"Ra={RightAscension}, Dec={Declination}"); - _telescopeController.SlewToCoordinates(RightAscension, Declination); - } - - public void SlewToCoordinatesAsync(double RightAscension, double Declination) - { - tl.LogMessage("SlewToCoordinatesAsync", $"Ra={RightAscension}, Dec={Declination}"); - _telescopeController.SlewToCoordinatesAsync(RightAscension, Declination); - } - - public void SlewToTarget() - { - tl.LogMessage("SlewToTarget", "Executing"); - _telescopeController.SlewToTarget(); - } - - public void SlewToTargetAsync() - { - tl.LogMessage("SlewToTargetAsync", "Executing"); - _telescopeController.SlewToTargetAsync(); - } - - public bool Slewing - { - get - { - tl.LogMessage("Slewing Get", "Started"); - var result = _telescopeController.Slewing; - tl.LogMessage("Slewing Get", $"Result = {result}"); - return result; - } - } - - public void SyncToAltAz(double Azimuth, double Altitude) - { - tl.LogMessage("SyncToAltAz", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SyncToAltAz"); - } - - public void SyncToCoordinates(double RightAscension, double Declination) - { - tl.LogMessage("SyncToCoordinates", $"RA={RightAscension} Dec={Declination}"); - _telescopeController.TargetRightAscension = RightAscension; - _telescopeController.TargetDeclination = Declination; - - SyncToTarget(); - } - - public void SyncToTarget() - { - tl.LogMessage("SyncToTarget", "Executing"); - _telescopeController.SyncToTarget(); - } - - public double TargetDeclination - { - get - { - var targetDec = _telescopeController.TargetDeclination; - tl.LogMessage("TargetDeclination Get", $"{targetDec}"); - return targetDec; - } - set - { - tl.LogMessage("TargetDeclination Set", $"{value}"); - _telescopeController.TargetDeclination = value; - } - } - - public double TargetRightAscension - { - get - { - var targetRa = _telescopeController.TargetRightAscension; - tl.LogMessage("TargetRightAscension Get", $"{targetRa}"); - return targetRa; - } - set - { - tl.LogMessage("TargetRightAscension Set", $"{value}"); - _telescopeController.TargetRightAscension = value; - } - } - - private bool _tracking = true; - public bool Tracking - { - get - { - //todo implementing this, it exists. - - tl.LogMessage("Tracking", $"Get - {_tracking}" ); - return _tracking; - } - set - { - tl.LogMessage($"Tracking Set", $"{value}"); - _tracking = value; - } - } - - public DriveRates TrackingRate - { - get - { - var tr = _telescopeController.TrackingRate; - tl.LogMessage("TrackingRate Get", $"{tr}"); - return tr; - } - set - { - tl.LogMessage("TrackingRate Set", $"{value}"); - _telescopeController.TrackingRate = value; - } - } - - public ITrackingRates TrackingRates - { - get - { - ITrackingRates trackingRates = new TrackingRates(); - tl.LogMessage("TrackingRates", "Get - "); - foreach (DriveRates driveRate in trackingRates) - { - tl.LogMessage("TrackingRates", "Get - " + driveRate.ToString()); - } - return trackingRates; - } - } - - public DateTime UTCDate - { - get - { - tl.LogMessage("UTCDate", "Get started"); - - var utcDate = _telescopeController.utcDate; - tl.LogMessage("UTCDate", "Get - " + Format("MM/dd/yy HH:mm:ss", utcDate)); - return utcDate; - } - set - { - tl.LogMessage("UTCDate", "Set - " + Format("MM/dd/yy HH:mm:ss", value)); - _telescopeController.utcDate = value; - - } - } - - public void Unpark() - { - tl.LogMessage("Unpark", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("Unpark"); - } - - #endregion - - #region IFocuser Implementation - - //private int focuserPosition = 0; // Class level variable to hold the current focuser position - //private const int focuserSteps = 10000; - - public bool Absolute - { - get - { - tl.LogMessage("Absolute Get", false.ToString()); - return false; // This is an absolute focuser - } - } - - public void Halt() - { - tl.LogMessage("Halt", "Halting"); - _telescopeController.FocuserHalt(); - } - - public bool IsMoving - { - get - { - tl.LogMessage("IsMoving Get", false.ToString()); - return false; // This focuser always moves instantaneously so no need for IsMoving ever to be True - } - } - - public bool Link - { - get - { - tl.LogMessage("Link Get", this.Connected.ToString()); - return this.Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility - } - set - { - tl.LogMessage("Link Set", value.ToString()); - this.Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility - } - } - - public int MaxIncrement - { - get - { - var maxIncrement = _telescopeController.FocuserMaxIncrement; - tl.LogMessage("MaxIncrement Get", maxIncrement.ToString()); - return maxIncrement; // Maximum change in one move - } - } - - public int MaxStep - { - get - { - var maxStep = _telescopeController.FocuserMaxStep; - tl.LogMessage("MaxStep Get", maxStep.ToString()); - return maxStep; - } - } - - public void Move(int Position) - { - tl.LogMessage("Move", Position.ToString()); - _telescopeController.FocuserMove(Position); - //focuserPosition = Position; // Set the focuser position - } - - public int Position - { - get - { - throw new ASCOM.PropertyNotImplementedException("Position", false); - //return focuserPosition; // Return the focuser position - } - } - - public double StepSize - { - get - { - tl.LogMessage("StepSize Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("StepSize", false); - } - } - - public bool TempComp - { - get - { - tl.LogMessage("TempComp Get", false.ToString()); - return false; - } - set - { - tl.LogMessage("TempComp Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TempComp", false); - } - } - - public bool TempCompAvailable - { - get - { - tl.LogMessage("TempCompAvailable Get", false.ToString()); - return false; // Temperature compensation is not available in this driver - } - } - - public double Temperature - { - get - { - tl.LogMessage("Temperature Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Temperature", false); - } - } - - #endregion - - #region Private properties and methods - // here are some useful properties and methods that can be used as required - // to help with driver development - - #region ASCOM Registration - - // Register or unregister driver for ASCOM. This is harmless if already - // registered or unregistered. - // - /// - /// Register or unregister the driver with the ASCOM Platform. - /// This is harmless if the driver is already registered/unregistered. - /// - /// If true, registers the driver, otherwise unregisters it. - private static void RegUnregASCOM(bool bRegister) - { - using (var p = new ASCOM.Utilities.Profile()) - { - p.DeviceType = "Telescope"; - if (bRegister) - { - p.Register(driverID, driverDescription); - } - else - { - p.Unregister(driverID); - } - } - - using (var p = new ASCOM.Utilities.Profile()) - { - p.DeviceType = "Focuser"; - if (bRegister) - { - p.Register(driverID, driverDescription); - } - else - { - p.Unregister(driverID); - } - } - } - - /// - /// This function registers the driver with the ASCOM Chooser and - /// is called automatically whenever this class is registered for COM Interop. - /// - /// Type of the class being registered, not used. - /// - /// This method typically runs in two distinct situations: - /// - /// - /// In Visual Studio, when the project is successfully built. - /// For this to work correctly, the option Register for COM Interop - /// must be enabled in the project settings. - /// - /// During setup, when the installer registers the assembly for COM Interop. - /// - /// This technique should mean that it is never necessary to manually register a driver with ASCOM. - /// - [ComRegisterFunction] - public static void RegisterASCOM(Type t) - { - RegUnregASCOM(true); - } - - /// - /// This function unregisters the driver from the ASCOM Chooser and - /// is called automatically whenever this class is unregistered from COM Interop. - /// - /// Type of the class being registered, not used. - /// - /// This method typically runs in two distinct situations: - /// - /// - /// In Visual Studio, when the project is cleaned or prior to rebuilding. - /// For this to work correctly, the option Register for COM Interop - /// must be enabled in the project settings. - /// - /// During uninstall, when the installer unregisters the assembly from COM Interop. - /// - /// This technique should mean that it is never necessary to manually unregister a driver from ASCOM. - /// - [ComUnregisterFunction] - public static void UnregisterASCOM(Type t) - { - RegUnregASCOM(false); - } - - #endregion - - /// - /// Returns true if there is a valid connection to the driver hardware - /// - private bool IsConnected => _telescopeController.Connected; - - /// - /// Use this function to throw an exception if we aren't connected to the hardware - /// - /// - private void CheckConnected(string message) - { - if (!IsConnected) - { - throw new ASCOM.NotConnectedException(message); - } - } - - /// - /// Read the device configuration from the ASCOM Profile store - /// - internal void ReadProfile() - { - using (Profile driverProfile = new Profile()) - { - driverProfile.DeviceType = "Telescope"; - tl.Enabled = Convert.ToBoolean(driverProfile.GetValue(driverID, traceStateProfileName, Empty, traceStateDefault)); - comPort = driverProfile.GetValue(driverID, comPortProfileName, Empty, comPortDefault); - } - } - - /// - /// Write the device configuration to the ASCOM Profile store - /// - internal void WriteProfile() - { - using (Profile driverProfile = new Profile()) - { - driverProfile.DeviceType = "Telescope"; - driverProfile.WriteValue(driverID, traceStateProfileName, tl.Enabled.ToString()); - driverProfile.WriteValue(driverID, comPortProfileName, comPort.ToString()); - } - } - - /// - /// Log helper function that takes formatted strings and arguments - /// - /// - /// - /// - internal static void LogMessage(string identifier, string message, params object[] args) - { - var msg = Format(message, args); - tl.LogMessage(identifier, msg); - } - #endregion - } -} diff --git a/MeadeAutostar497/Controller/FirmwareVersion.cs b/MeadeAutostar497/Controller/FirmwareVersion.cs deleted file mode 100644 index bdd0976..0000000 --- a/MeadeAutostar497/Controller/FirmwareVersion.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace ASCOM.MeadeAutostar497.Controller -{ - enum FirmwareVersion - { - autostar497_30eb, - autostar497_30ed, - autostar497_30ee, - autostar497_31ee, - autostar497_32ea, - //PEC added for Polar mounted scopes - - autostar497_32ee, - autostar497_32eh, - //Some serial strings fixed. - - autostar497_32ei, - autostar497_33ef, - //Some serial strings fixed. - - autostar497_33el, - autostar497_40eb, - autostar497_40ee, - autostar497_40ef, - autostar497_41ec, - autostar497_42ed, - //Get serial command for daylight savings (:GH# returns 0 for disabled 1 for enabled) - //Set serial command for daylight savings (:SH0# disables, :SH1# enables) - - autostar497_43ea, - autostar497_43ed, - autostar497_43eg - //Added :GW#, :AL#, :AA#, & :AP# - } -} \ No newline at end of file diff --git a/MeadeAutostar497/Controller/ISerialProcessor.cs b/MeadeAutostar497/Controller/ISerialProcessor.cs deleted file mode 100644 index 5578bf3..0000000 --- a/MeadeAutostar497/Controller/ISerialProcessor.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.IO.Ports; -using System.Runtime.InteropServices; - -namespace ASCOM.MeadeAutostar497.Controller -{ - [ComVisible(false)] - public interface ISerialProcessor - { - bool IsOpen { get; } - bool DtrEnable { get; set; } - bool RtsEnable { get; set; } - int BaudRate { get; set; } - int DataBits { get; set; } - StopBits StopBits { get; set; } - Parity Parity { get; set; } - string PortName { get; set; } - string[] GetPortNames(); - void Open(); - void Close(); - - string CommandTerminated(string command, string terminator); - char CommandChar(string command); - string ReadTerminated(string terminator); - void Command(string command); - void Lock(); - void Unlock(); - } -} \ No newline at end of file diff --git a/MeadeAutostar497/Controller/ITelescopeController.cs b/MeadeAutostar497/Controller/ITelescopeController.cs deleted file mode 100644 index 9873c48..0000000 --- a/MeadeAutostar497/Controller/ITelescopeController.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using ASCOM.DeviceInterface; - -namespace ASCOM.MeadeAutostar497.Controller -{ - public interface ITelescopeController - { - string Port { get; set; } - bool Connected { get; set; } - - bool Slewing { get; } - DateTime utcDate { get; set; } - double SiteLatitude { get; set; } - double SiteLongitude { get; set; } - AlignmentModes AlignmentMode { get; set; } - bool AtPark { get; } - double Altitude { get; } - double Azimuth { get; } - double RightAscension { get; } - double Declination { get; } - double TargetRightAscension { get; set; } - double TargetDeclination { get; set; } - DriveRates TrackingRate { get; set; } - int FocuserMaxIncrement { get; set; } - int FocuserMaxStep { get; set; } - void AbortSlew(); - void PulseGuide(GuideDirections direction, int duration); - void Park(); - void SlewToCoordinates(double rightAscension, double declination); - void SlewToCoordinatesAsync(double rightAscension, double declination); - void SlewToAltAz(double azimuth, double altitude); - void SlewToAltAzAsync(double azimuth, double altitude); - void SyncToTarget(); - void SlewToTarget(); - void SlewToTargetAsync(); - void MoveAxis(TelescopeAxes axis, double rate); - void FocuserHalt(); - void FocuserMove(int position); - string CommandString(string command, bool raw); - void CommandBlind(string command, bool raw); - } -} \ No newline at end of file diff --git a/MeadeAutostar497/Controller/SerialProcessor.cs b/MeadeAutostar497/Controller/SerialProcessor.cs deleted file mode 100644 index 1c77556..0000000 --- a/MeadeAutostar497/Controller/SerialProcessor.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.IO.Ports; -using System.Runtime.InteropServices; -using System.Threading; - -namespace ASCOM.MeadeAutostar497.Controller -{ - [ComVisible(false)] - public class SerialProcessor : ISerialProcessor - { - private SerialPort _serialPort = new SerialPort(); - private Mutex serialMutex = new Mutex(); - - public bool IsOpen => _serialPort.IsOpen; - - public bool DtrEnable - { - get => _serialPort.DtrEnable; - set => _serialPort.DtrEnable = value; - } - - public bool RtsEnable - { - get => _serialPort.RtsEnable; - set => _serialPort.RtsEnable = value; - } - - public int BaudRate - { - get => _serialPort.BaudRate; - set => _serialPort.BaudRate = value; - } - - public int DataBits - { - get => _serialPort.DataBits; - set => _serialPort.DataBits = value; - } - - public StopBits StopBits - { - get => _serialPort.StopBits; - set => _serialPort.StopBits = value; - } - - public Parity Parity - { - get => _serialPort.Parity; - set => _serialPort.Parity = value; - } - - public string PortName - { - get => _serialPort.PortName; - set => _serialPort.PortName = value; - } - - public string[] GetPortNames() - { - return SerialPort.GetPortNames(); - } - - public void Open() - { - _serialPort.ReadTimeout = 5000; - _serialPort.WriteTimeout = 5000; - _serialPort.Open(); - } - - public void Close() - { - _serialPort.Close(); - } - - public string CommandTerminated(string command, string terminator) - { - Lock(); - try - { - _serialPort.Write(command); - string result = _serialPort.ReadTo("#"); - return result; - } - finally - { - Unlock(); - } - } - - public char CommandChar(string command) - { - Lock(); - try - { - _serialPort.Write(command); - var result = _serialPort.ReadChar(); - return Convert.ToChar(result); - } - finally - { - Unlock(); - } - } - - public string ReadTerminated(string terminator) - { - Lock(); - try - { - string result = _serialPort.ReadTo("#"); - return result; - } - finally - { - Unlock(); - } - } - - public void Command(string command) - { - Lock(); - try - { - _serialPort.Write(command); - } - finally - { - Unlock(); - } - } - - public void Lock() - { - serialMutex.WaitOne(); - } - - public void Unlock() - { - serialMutex.ReleaseMutex(); - } - } -} diff --git a/MeadeAutostar497/Controller/TelescopeController.cs b/MeadeAutostar497/Controller/TelescopeController.cs deleted file mode 100644 index e314982..0000000 --- a/MeadeAutostar497/Controller/TelescopeController.cs +++ /dev/null @@ -1,992 +0,0 @@ -using System; -using System.IO.Ports; -using System.Linq; -using System.Threading; -using ASCOM.DeviceInterface; -using ASCOM.Utilities; -using ASCOM.Utilities.Interfaces; - -namespace ASCOM.MeadeAutostar497.Controller -{ - //todo stop this being a singleton, and instead use a server to make only a single instance. - public sealed class TelescopeController : ITelescopeController - { - private const double INVALID_PARAMETER = -1000; - - private static readonly Lazy Lazy = new Lazy(); - - public static TelescopeController Instance => Lazy.Value; - - //todo remove this as it can cause problems in production - private ISerialProcessor _serialPort; - public ISerialProcessor SerialPort - { - get => _serialPort ?? (_serialPort = new SerialProcessor()); - set - { - if (_serialPort == value) - return; - - if (_serialPort != null) - { - if (_serialPort.IsOpen) - throw new InvalidOperationException("Please disconnect before changing the serial engine."); - } - - _serialPort = value; - } - } - - private IUtil _util; - public IUtil Util - { - get => _util ?? (_util = new Util()); - set - { - if (Equals(_util, value)) - return; - - _util = value; - } - } - - private string _port = "COM1"; - public string Port - { - get => _port; - set - { - if (_port == value) return; - - if (Connected) - throw new InvalidOperationException("Please disconnect from the scope before changing port."); - - if (!ValidPort(value)) - throw new InvalidOperationException($"Unable to select port {value} as it does not exist."); - - _port = value; - } - } - - private bool ValidPort(string value) - { - return SerialPort.GetPortNames().Contains(value); - } - - public bool Connected - { - get => SerialPort.IsOpen; - set - { - if (value == Connected) - return; - - if (value) - { - //Connecting - try - { - AtPark = false; - SerialPort.DtrEnable = false; - SerialPort.RtsEnable = false; - SerialPort.BaudRate = 9600; - SerialPort.DataBits = 8; - SerialPort.StopBits = StopBits.One; - SerialPort.Parity = Parity.None; - SerialPort.PortName = Port; - SerialPort.Open(); - - TestConnectionActive(); - SetFocuserSpeedFastest(); - } - catch (Exception) - { - if (SerialPort.IsOpen) - SerialPort.Close(); - throw; - } - } - else - { - //Disconnecting - SerialPort.Close(); - AtPark = false; - } - } - } - - private void TestConnectionActive() - { - var firmwareVersionNumber = SerialPort.CommandTerminated(":GVN#", "#"); - if (string.IsNullOrEmpty(firmwareVersionNumber)) - { - throw new InvalidOperationException("Failed to communicate with telescope."); - } - } - - public bool Slewing - { - get - { - if (!Connected) return false; - - - if (movingAxis()) - return true; - - var result = SerialPort.CommandTerminated(":D#", "#"); - return result != string.Empty; - } - } - - public DateTime utcDate - { - get - { - string telescopeDate = SerialPort.CommandTerminated(":GC#", "#"); - string telescopeTime = SerialPort.CommandTerminated(":GL#", "#"); - - int month = telescopeDate.Substring(0, 2).ToInteger(); - int day = telescopeDate.Substring(3, 2).ToInteger(); - int year = telescopeDate.Substring(6, 2).ToInteger(); - - if (year < 2000) //todo fix this hack that will create a Y2K100 bug - { - year = year + 2000; - } - - int hour = telescopeTime.Substring(0, 2).ToInteger(); - int minute = telescopeTime.Substring(3, 2).ToInteger(); - int second = telescopeTime.Substring(6, 2).ToInteger(); - - var utcCorrection = GetUtcCorrection(); - - //Todo is this telescope local time, or real utc? - var newDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + utcCorrection; - - return newDate; - } - set - { - var utcCorrection = GetUtcCorrection(); - var localDateTime = value - utcCorrection; - - //Todo is this telescope local time, or real utc? - var timeResult = SerialPort.CommandChar($":SL{localDateTime:HH:mm:ss}#"); - if (timeResult != '1') - { - throw new InvalidOperationException("Failed to set local time"); - } - - SerialPort.Lock(); - try - { - var dateResult = SerialPort.CommandChar($":SC{localDateTime:MM/dd/yy}#"); - if (dateResult != '1') - { - throw new InvalidOperationException("Failed to set local date"); - } - - //throwing away these two strings which represent - SerialPort.ReadTerminated("#"); //Updating Planetary Data# - SerialPort.ReadTerminated("#"); // # - } - finally - { - SerialPort.Unlock(); - } - } - - } - - private TimeSpan GetUtcCorrection() - { - string utcOffSet = SerialPort.CommandTerminated(":GG#", "#"); - double utcOffsetHours = double.Parse(utcOffSet); - TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); - return utcCorrection; - } - - public double SiteLatitude - { - get - { - var latitude = SerialPort.CommandTerminated( ":Gt#", "#"); - - return DmsToDouble(latitude); - } - set - { - if (value > 90) - throw new InvalidValueException("Latitude cannot be greater than 90 degrees."); - - if (value < -90) - throw new InvalidValueException("Latitude cannot be less than -90 degrees."); - - int d = Convert.ToInt32(Math.Floor(value)); - int m = Convert.ToInt32(60 * (value - d)); - - var result = SerialPort.CommandChar($":Sts{d:00}*{m:00}#"); - if (result != '1') - throw new InvalidOperationException("Failed to set site latitude."); - } - } - - private double DmsToDouble(string dms) - { - if (IsNumeric(dms[0])) - { - double l = int.Parse(dms.Substring(0, 3)); - l = l + double.Parse(dms.Substring(4, 2)) / 60; - if (dms.Length == 9) - l = l + double.Parse(dms.Substring(7, 2)) / 60 / 60; - - return l; - } - - double lat = int.Parse(dms.Substring(1, 2)); - lat = lat + double.Parse(dms.Substring(4, 2)) / 60; - if (dms.Length == 9) - lat = lat + double.Parse(dms.Substring(7, 2)) / 60 / 60; - - if (dms[0] == '-') - lat = -lat; - - return lat; - } - - private bool IsNumeric(char c) - { - char[] nums = new[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - return nums.Contains(c); - } - - public double SiteLongitude - { - get - { - var longitude = SerialPort.CommandTerminated(":Gg#", "#"); - double l = DmsToDouble(longitude); - - if (l > 180) - l = l - 360; - - return l; - } - set - { - if (value > 180) - throw new InvalidValueException("Longitude cannot be greater than 180 degrees."); - - if (value < -180) - throw new InvalidValueException("Longitude cannot be lower than -180 degrees."); - - int d = Convert.ToInt32(Math.Floor(value)); - int m = Convert.ToInt32(60 * (value - d)); - - var result = SerialPort.CommandChar($":Sg{d:000}*{m:00}#"); - if (result != '1') - throw new InvalidOperationException("Failed to set site longitude."); - } - - } - - public AlignmentModes AlignmentMode - { - get - { - const char ack = (char)6; - //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); - var alignmentString = SerialPort.CommandChar(ack.ToString()); - //:GW# Get Scope Alignment Status - //Returns: # - // where: - //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial - //tracking: T - tracking, N - not tracking - //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. - - switch (alignmentString) - { - case 'A': return AlignmentModes.algAltAz; - case 'P': return AlignmentModes.algPolar; - case 'G': return AlignmentModes.algGermanPolar; - default: - throw new InvalidValueException($"unknown alignment returned from telescope: {alignmentString}"); - } - } - set - { - switch (value) - { - case AlignmentModes.algAltAz: - SerialPort.Command(":AA#"); - //:AA# Sets telescope the AltAz alignment mode - //Returns: nothing - break; - case AlignmentModes.algPolar: - case AlignmentModes.algGermanPolar: - SerialPort.Command(":AP#"); - //:AP# Sets telescope to Polar alignment mode - //Returns: nothing - break; - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - - //:AL# Sets telescope to Land alignment mode - //Returns: nothing - } - } - - public bool AtPark { get; private set; } - - public double Azimuth - { - get - { - var result = SerialPort.CommandTerminated(":GZ#", "#"); - //:GZ# Get telescope azimuth - //Returns: DDD*MM#T or DDD*MM’SS# - //The current telescope Azimuth depending on the selected precision. - - double az = DmsToDouble(result); - - return az; - } - } - - public double RightAscension { - get - { - var result = SerialPort.CommandTerminated(":GR#", "#"); - //:GR# Get Telescope RA - //Returns: HH: MM.T# or HH:MM:SS# - //Depending which precision is set for the telescope - - double ra = HmsToDouble(result); - - return ra; - } - } - - private double HmsToDouble(string hms) - { - return Util.HMSToHours(hms); - } - - public double Declination - { - get - { - var result = SerialPort.CommandTerminated(":GD#", "#"); - //:GD# Get Telescope Declination. - //Returns: sDD* MM# or sDD*MM’SS# - //Depending upon the current precision setting for the telescope. - - double az = DmsToDouble(result); - - return az; - } - } - - private double _targetRightAscension = INVALID_PARAMETER; - public double TargetRightAscension { - get - { - if (_targetRightAscension == INVALID_PARAMETER) - throw new ASCOM.InvalidOperationException("Target not set"); - - //var result = SerialPort.CommandTerminated(":Gr#", "#"); - ////:Gr# Get current/target object RA - ////Returns: HH: MM.T# or HH:MM:SS - ////Depending upon which precision is set for the telescope - - //double targetRa = HmsToDouble(result); - //return targetRa; - return _targetRightAscension; - } - set - { - if (value < 0) - throw new InvalidValueException("Right ascension value cannot be below 0"); - - if (value >= 24) - throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); - - - //todo implement the low precision version - - var hms = Util.HoursToHMS(value, ":", ":", ":", 2); - var response = SerialPort.CommandChar($":Sr{hms}#"); - //:SrHH:MM.T# - //:SrHH:MM:SS# - //Set target object RA to HH:MM.T or HH: MM: SS depending on the current precision setting. - // Returns: - //0 – Invalid - //1 - Valid - - if (response == '0') - throw new InvalidOperationException("Failed to set TargetRightAscension."); - - _targetRightAscension = value; - } - } - - private double _targetDeclination = INVALID_PARAMETER; - public double TargetDeclination { - get - { - if (_targetDeclination == INVALID_PARAMETER) - throw new ASCOM.InvalidOperationException("Target not set"); - - //var result = SerialPort.CommandTerminated(":Gd#", "#"); - ////:Gd# Get Currently Selected Object/Target Declination - ////Returns: sDD* MM# or sDD*MM’SS# - ////Depending upon the current precision setting for the telescope. - - //double targetDec = DmsToDouble(result); - - //return targetDec; - return _targetDeclination; - } - set - { - //todo implement low precision version of this. - if (value > 90) - throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); - - if (value < -90) - throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); - - - var dms = Util.DegreesToDMS(value, "*", ":", ":", 2); - var s = value < 0 ? '-' : '+'; - - var result = SerialPort.CommandChar($":Sd{s}{dms}#"); - //:SdsDD*MM# - //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting - //Returns: - //1 - Dec Accepted - //0 – Dec invalid - - if (result == '0') - { - throw new ASCOM.InvalidOperationException("Target declination invalid"); - } - - _targetDeclination = value; - } - } - - private DriveRates _trackingRate = DriveRates.driveSidereal; - public DriveRates TrackingRate - { - get - { - //var result = SerialPort.CommandTerminated(":GT#", "#"); - - //double rate = double.Parse(result); - - - //if (rate == 60.1) - // return DriveRates.driveLunar; - //else if (rate == 60.1) - // return DriveRates.driveSidereal; - - //return DriveRates.driveKing; - return _trackingRate; - } - set - { - switch (value) - { - case DriveRates.driveSidereal: - SerialPort.Command(":TQ#"); - //:TQ# Selects sidereal tracking rate - //Returns: Nothing - break; - case DriveRates.driveLunar: - SerialPort.Command(":TL#"); - //:TL# Set Lunar Tracking Rage - //Returns: Nothing - break; - //case DriveRates.driveSolar: - // SerialPort.Command(":TS#"); - // //:TS# Select Solar tracking rate. [LS Only] - // //Returns: Nothing - // break; - case DriveRates.driveKing: - //:TM# Select custom tracking rate [ no-op in Autostar II] - //Returns: Nothing - break; - default: - throw new ArgumentOutOfRangeException(nameof(value), value, null); - } - - _trackingRate = value; - } - } - - public int FocuserMaxIncrement { get; set; } = 7000; - - public int FocuserMaxStep { get; set; } = 7000; - - public double Altitude { - get - { - var result = SerialPort.CommandTerminated(":GA#", "#"); - //:GA# Get Telescope Altitude - //Returns: sDD* MM# or sDD*MM’SS# - //The current scope altitude. The returned format depending on the current precision setting. - return DmsToDouble(result); - } - } - - public void AbortSlew() - { - SerialPort.Command("#:Q#"); - } - - public void PulseGuide(GuideDirections direction, int duration) - { - string d = string.Empty; - switch (direction) - { - case GuideDirections.guideEast: - d = "e"; - break; - case GuideDirections.guideNorth: - d = "n"; - break; - case GuideDirections.guideSouth: - d = "s"; - break; - case GuideDirections.guideWest: - d = "w"; - break; - } - - if (UserNewerPulseGuiding) - { - _serialPort.Command($":Mg{d}{duration:0000}#"); - Thread.Sleep(duration); //todo figure out if this is really needed - } - else - { - SerialPort.Lock(); - try - { - _serialPort.Command(":RG#"); //Make sure we are at guide rate - _serialPort.Command($":M{d}#"); - Thread.Sleep(duration); - _serialPort.Command($":Q{d}#"); - - //classic only !!!, this is needed since once in a while one is not enough - Thread.Sleep(200); - _serialPort.Command($":Q{d}#"); - } - finally - { - SerialPort.Unlock(); - } - } - } - - public void Park() - { - if (AtPark) - return; - - AtPark = true; - _serialPort.Command(":hP#"); - } - - public void SlewToCoordinates(double rightAscension, double declination) - { - SlewToCoordinatesAsync(rightAscension, declination); - - while (Slewing) //wait for slew to complete - { - Util.WaitForMilliseconds(200); //be responsive to AbortSlew(); - } - } - - public void SlewToCoordinatesAsync(double rightAscension, double declination) - { - SerialPort.Lock(); - try - { - TargetRightAscension = rightAscension; - TargetDeclination = declination; - - DoSlewAsync(true); - } - finally - { - SerialPort.Unlock(); - } - } - - public void SlewToAltAz(double azimuth, double altitude) - { - SlewToAltAzAsync(azimuth, altitude); - - while (Slewing) //wait for slew to complete - { - Util.WaitForMilliseconds(200); //be responsive to AbortSlew(); - } - } - - private double TargetAltitude - { - set - { - if (value > 90) - throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); - - if (value < 0) - throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); - - - var dms = Util.DegreesToDMS(value, "*", "'", ".", 2); - var s = value < 0 ? '-' : '+'; - - var result = SerialPort.CommandChar($":Sa{s}{dms}#"); - //:SasDD*MM# - //Set target object altitude to sDD*MM# or sDD*MM’SS# [LX 16â€, Autostar, Autostar II] - //Returns: - //1 Object within slew range - //0 Object out of slew range - - if (result == '0') - throw new ASCOM.InvalidOperationException("Target altitude out of slew range"); - } - } - - private double TargetAzimuth - { - set - { - if (value >= 360) - throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); - - if (value < 0) - throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); - - var dms = Util.DegreesToDM(value, "*", ":", 2); - - var result = SerialPort.CommandChar($":Sd{dms}#"); - //:SzDDD*MM# - //Sets the target Object Azimuth[LX 16†and Autostar II only] - //Returns: - //0 – Invalid - //1 - Valid - - if (result == '0') - throw new ASCOM.InvalidOperationException("Target Azimuth out of slew range"); - - } - } - - public void SlewToAltAzAsync(double azimuth, double altitude) - { - SerialPort.Lock(); - try - { - TargetAltitude = altitude; - TargetAzimuth = azimuth; - - DoSlewAsync(false); - } - finally - { - SerialPort.Unlock(); - } - } - - public void SyncToTarget() - { - var result = SerialPort.CommandTerminated(":CM#", "#"); - //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. - //Returns: - //LX200's - a "#" terminated string with the name of the object that was synced. - // Autostars & Autostar II - At static string: " M31 EX GAL MAG 3.5 SZ178.0'#" - - if (result == string.Empty) - throw new ASCOM.InvalidOperationException("Unable to perform sync"); - } - - public void SlewToTarget() - { - SlewToTargetAsync(); - - while (Slewing) - { - Util.WaitForMilliseconds(200); - } - } - - public void SlewToTargetAsync() - { - if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER ) - throw new ASCOM.InvalidOperationException("No target selected to slew to."); - - DoSlewAsync(true); - } - - private bool movingAxis() - { - return _movingPrimary || _movingSecondary; - } - - private bool _movingPrimary; - private bool _movingSecondary; - - public void MoveAxis(TelescopeAxes axis, double rate) - { - SerialPort.Lock(); - try - { - var absrate = Math.Abs(rate); - - switch (absrate) - { - case 0: - //do nothing, it's ok this time as we're halting the slew. - break; - case 1: - SerialPort.Command(":RG#"); - //:RG# Set Slew rate to Guiding Rate (slowest) - //Returns: Nothing - break; - case 2: - SerialPort.Command(":RC#"); - //:RC# Set Slew rate to Centering rate (2nd slowest) - //Returns: Nothing - break; - case 3: - SerialPort.Command(":RM#"); - //:RM# Set Slew rate to Find Rate (2nd Fastest) - //Returns: Nothing - break; - case 4: - SerialPort.Command(":RS#"); - //:RS# Set Slew rate to max (fastest) - //Returns: Nothing - break; - default: - throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); - - } - - switch (axis) - { - case TelescopeAxes.axisPrimary: - if (rate == 0) - { - _movingPrimary = false; - SerialPort.Command(":Qe#"); - //:Qe# Halt eastward Slews - //Returns: Nothing - SerialPort.Command(":Qw#"); - //:Qw# Halt westward Slews - //Returns: Nothing - } - else if (rate > 0) - { - SerialPort.Command(":Me#"); - //:Me# Move Telescope East at current slew rate - //Returns: Nothing - _movingPrimary = true; - } - else - { - SerialPort.Command(":Mw#"); - //:Mw# Move Telescope West at current slew rate - //Returns: Nothing - _movingPrimary = true; - } - - break; - case TelescopeAxes.axisSecondary: - if (rate == 0) - { - _movingSecondary = false; - SerialPort.Command(":Qn#"); - //:Qn# Halt northward Slews - //Returns: Nothing - SerialPort.Command(":Qs#"); - //:Qs# Halt southward Slews - //Returns: Nothing - } - else if (rate > 0) - { - SerialPort.Command(":Mn#"); - //:Mn# Move Telescope North at current slew rate - //Returns: Nothing - _movingSecondary = true; - } - else - { - SerialPort.Command(":Ms#"); - //:Ms# Move Telescope South at current slew rate - //Returns: Nothing - _movingSecondary = true; - } - - break; - default: - throw new ASCOM.MethodNotImplementedException("Can not move this axis."); - } - } - finally - { - SerialPort.Unlock(); - } - } - - public void FocuserHalt() - { - SerialPort.Command(":FQ#"); - //:FQ# Halt Focuser Motion - //Returns: Nothing - } - - public void FocuserMove(int newPosition) - { - //todo implement backlash compensation - //todo implement direction reverse - //todo implement dynamic braking - - if (newPosition < -FocuserMaxIncrement || newPosition > FocuserMaxIncrement) - { - throw new ASCOM.InvalidValueException($"position out of range {-FocuserMaxIncrement} < {newPosition} < {FocuserMaxIncrement}"); - } - - if (newPosition == 0) - return; - - if (newPosition > 0) - { - //desired move direction is out - MoveFocuser(true, Math.Abs(newPosition)); - } - else - { - //desired move direction is in - MoveFocuser(false, Math.Abs(newPosition)); - } - } - - public string CommandString(string command, bool raw) - { - return SerialPort.CommandTerminated(command, "#"); - } - - public void CommandBlind(string command, bool raw) - { - SerialPort.Command(command); - } - - private void MoveFocuser(bool directionOut, int steps) - { - SerialPort.Command(directionOut ? ":F+#" : ":F-#"); - //:F+# Start Focuser moving inward (toward objective) - //Returns: None - - //:F-# Start Focuser moving outward (away from objective) - //Returns: None - - Util.WaitForMilliseconds(steps); - - FocuserHalt(); - } - - private void SetFocuserSpeedFastest() - { - SerialPort.Command(":FF#"); - //:FF# Set Focus speed to fastest setting - //Returns: Nothing - } - - private void SetFocuserSpeedSlowest() - { - SerialPort.Command(":FS#"); - //:FS# Set Focus speed to slowest setting - //Returns: Nothing - } - - private void SetFocuserSpeed( int speed) - { - if (speed < 1) - throw new ArgumentOutOfRangeException("speed is too low"); - - if (speed > 4) - throw new ArgumentOutOfRangeException("speed is too high"); - - SerialPort.Command($":F{speed}#"); - //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 - //Returns: Nothing - //All others – Not Supported - } - - //todo remove the polar parameter and split method into two. - private void DoSlewAsync( bool polar) - { - SerialPort.Lock(); - try - { - switch (polar) - { - case true: - var response = SerialPort.CommandChar(":MS#"); - //:MS# Slew to Target Object - //Returns: - //0 Slew is Possible - //1# Object Below Horizon w/string message - //2# Object Below Higher w/string message - - switch (response) - { - case '0': - //We're slewing everything should be working just fine. - break; - case '1': - //Below Horizon - string belowHorizonMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowHorizonMessage); - case '2': - //Below Horizon - string belowMinimumElevationMessage = SerialPort.ReadTerminated("#"); - throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); - default: - throw new ASCOM.DriverException("This error should not happen"); - - } - - break; - case false: - var maResponse = SerialPort.CommandChar(":MA#"); - //:MA# Autostar, LX 16â€, Autostar II – Slew to target Alt and Az - //Returns: - //0 - No fault - //1 – Fault - // LX200 – Not supported - - if (maResponse == '1') - { - throw new ASCOM.InvalidOperationException("fault"); - } - - break; - } - } - finally - { - SerialPort.Unlock(); - } - } - - public bool UserNewerPulseGuiding { get; set; } = true; //todo make this a device setting - } -} diff --git a/TargetToBeat.txt b/TargetToBeat.txt deleted file mode 100644 index 8255bd9..0000000 --- a/TargetToBeat.txt +++ /dev/null @@ -1,249 +0,0 @@ - -ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:34 -ConformanceCheck Running on: ASCOM Platform 6.4 SP1 6.4.1.2695 - -ConformanceCheck Driver ProgID: MeadeEx.Telescope - -Error handling -Error number for "Not Implemented" is: 80040400 -Error number for "Invalid Value 1" is: 80040401 -Error number for "Invalid Value 2" is: 80040405 -Error number for "Value Not Set 1" is: 80040402 -Error number for "Value Not Set 2" is: 80040403 -Error messages will not be interpreted to infer state. - -21:04:42.255 Driver Access Checks OK -21:04:42.997 AccessChecks OK Successfully created driver using late binding -21:04:50.059 AccessChecks OK Successfully connected using late binding -21:04:50.063 AccessChecks INFO The driver is a COM object -21:04:57.769 AccessChecks INFO Device exposes interface ITelescopeV2 -21:04:58.546 AccessChecks INFO Device does not expose interface ITelescopeV3 -21:04:59.881 AccessChecks OK Successfully created driver using driver access toolkit -21:05:06.873 AccessChecks OK Successfully connected using driver access toolkit - -Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -21:05:08.261 ConformanceCheck OK Driver instance created successfully -21:05:15.293 ConformanceCheck OK Connected OK - -Common Driver Methods -21:05:15.333 InterfaceVersion OK 2 -21:05:15.362 Connected OK True -21:05:15.448 Description OK Meade Autostar 497: ETX Autostar|A|43Ea|Jun 02 2006@10:09:40 -21:05:15.480 DriverInfo OK ASCOM Meade Telescope/Focuser driver for classic and Autostar I 5.0.4 - ASCOM Iniative - http://ascom-standards.org/ - Last Modified 10/06/2013 19:06:54 -21:05:15.509 DriverVersion OK 5.0 -21:05:15.539 Name OK Autostar 497 -21:05:15.568 CommandString INFO Conform cannot test the CommandString method -21:05:15.572 CommandBlind INFO Conform cannot test the CommandBlind method -21:05:15.582 CommandBool INFO Conform cannot test the CommandBool method -21:05:15.588 Action INFO Conform cannot test the Action method -21:05:15.595 SupportedActions OK Driver returned an empty action list - -Can Properties -21:05:15.663 CanFindHome OK False -21:05:15.671 CanPark OK True -21:05:15.679 CanPulseGuide OK True -21:05:15.687 CanSetDeclinationRate OK False -21:05:15.695 CanSetGuideRates OK False -21:05:15.703 CanSetPark OK False -21:05:15.711 CanSetPierSide OK False -21:05:15.719 CanSetRightAscensionRate OK False -21:05:15.727 CanSetTracking OK False -21:05:15.735 CanSlew OK True -21:05:15.743 CanSlewltAz OK True -21:05:15.752 CanSlewAltAzAsync OK True -21:05:15.761 CanSlewAsync OK True -21:05:15.769 CanSync OK True -21:05:15.777 CanSyncAltAz OK False -21:05:15.785 CanUnPark OK False - -Pre-run Checks -21:05:15.834 Mount Safety INFO Scope is not parked, continuing testing -21:05:15.887 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -21:05:15.894 TimeCheck INFO PC UTCDate: 30-Apr-2019 20:05:15.894 -21:05:16.013 TimeCheck INFO Mount UTCDate: 30-Apr-2019 20:04:15.000 - -Properties -21:05:16.063 AlignmentMode OK algPolar -21:05:16.117 Altitude OK 90.00 -21:05:16.149 ApertureArea ERROR Unexpected DriverAccessCOMException, : Property ApertureAreaThe supplied value is out of range for this property. -21:05:16.182 ApertureDiameter ERROR Unexpected DriverAccessCOMException, : Property ApertureDiameterThe supplied value is out of range for this property. -21:05:16.214 AtHome OK False -21:05:16.245 AtPark OK False -21:05:16.310 Azimuth OK 0.57 -21:05:16.369 Declination OK 89:59:59.00 -21:05:16.402 DeclinationRate Read OK 0.00 -21:05:16.434 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -21:05:16.469 DoesRefraction Read OK True -21:05:16.501 DoesRefraction Write ERROR Unexpected DriverAccessCOMException, : Property DoesRefractionThe supplied value is out of range for this property. -21:05:16.534 EquatorialSystem OK equLocalTopocentric -21:05:16.568 FocalLength ERROR Unexpected DriverAccessCOMException, : Property FocalLengthThe supplied value is out of range for this property. -21:05:16.602 GuideRateDeclination Read OK 0.00 -21:05:16.613 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -21:05:16.646 GuideRateRightAscension Read OK 0.00 -21:05:16.661 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -21:05:16.694 IsPulseGuiding OK False -21:05:16.748 RightAscension OK 22:28:48.00 -21:05:16.781 RightAscensionRate Read OK 0.00 -21:05:16.814 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -21:05:16.848 SiteElevation Read OK 0 -21:05:16.884 SiteElevation Write ERROR Unexpected DriverAccessCOMException, : Property SiteElevation The supplied value is out of range for this property. -21:05:16.896 SiteElevation Write ERROR Unexpected DriverAccessCOMException, : Property SiteElevation The supplied value is out of range for this property. -21:05:16.908 SiteElevation Write OK Legal value 0m written successfully -21:05:16.965 SiteLatitude Read OK 53:50:00.00 -21:05:16.999 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.012 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.025 SiteLatitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.096 SiteLongitude Read OK -01:46:00.00 -21:05:17.130 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.144 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.156 SiteLongitude Write OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.192 Slewing OK False -21:05:17.226 SlewSettleTime Read OK 0 -21:05:17.262 SlewSettleTime Write ERROR Unexpected DriverAccessCOMException, : Property SlewSettleTime The supplied value is out of range for this property. -21:05:17.277 SlewSettleTime Write OK Legal value 0 seconds written successfully -21:05:17.313 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -21:05:17.356 SiderealTime OK 10:31:06.00 -21:05:17.368 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:31:06.00, ASCOM: 10:32:07.97 -21:05:17.405 TargetDeclination Read ERROR Unexpected DriverAccessCOMException, : The target value is not set. -21:05:17.440 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -21:05:17.454 TargetRightAscension Read ERROR Unexpected DriverAccessCOMException, : The target value is not set. -21:05:17.489 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -21:05:17.502 Tracking Read OK True -21:05:17.537 Tracking Write OK CanSetTracking is False and a PropertyNotImplementedException exception was generated as expected -21:05:17.575 TrackingRates ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. -21:05:17.590 TrackingRates ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. -21:05:17.603 TrackingRates OK Dispose member not present -21:05:17.638 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -21:05:17.651 TrackingRate Read OK driveSidereal -21:05:17.665 TrackingRate Write ERROR Unexpected System.Reflection.TargetInvocationException exception, : Exception has been thrown by the target of an invocation. -21:05:17.760 UTCDate Read OK 30-Apr-2019 20:04:16.000 -21:05:17.774 UTCDate Write OK Optional member threw a PropertyNotImplementedException exception. - -Methods -21:05:17.858 CanMoveAxis:Primary OK CanMoveAxis:Primary False -21:05:17.894 CanMoveAxis:Secondary OK CanMoveAxis:Secondary False -21:05:17.931 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -21:05:17.967 Park/Unpark INFO Tests skipped -21:05:18.981 AbortSlew OK AbortSlew OK when not slewing -21:05:19.040 AxisRate:Primary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) - --- End of inner exception stack trace --- - at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 -21:05:19.055 AxisRate:Primary OK Empty axis rate returned -21:05:19.069 AxisRate:Primary OK AxisRates.Dispose() member not present for axis axisPrimary -21:05:19.085 AxisRate:Secondary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) - --- End of inner exception stack trace --- - at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 -21:05:19.100 AxisRate:Secondary OK Empty axis rate returned -21:05:19.117 AxisRate:Secondary OK AxisRates.Dispose() member not present for axis axisSecondary -21:05:19.132 AxisRate:Tertiary Enum ERROR .NET - Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Runtime.InteropServices.COMException: Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND)) - --- End of inner exception stack trace --- - at Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod(Method TargetProcedure, Object[] Arguments, Boolean[] CopyBack, BindingFlags Flags) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.ObjectLateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) - at Conform.TelescopeTester.TelescopeAxisRateTest(String p_Name, TelescopeAxes p_Axis) in J:\Conform\Conform\Devices\TelescopeTester.vb:line 3022 -21:05:19.149 AxisRate:Tertiary OK Empty axis rate returned -21:05:19.178 AxisRate:Tertiary OK AxisRates.Dispose() member not present for axis axisTertiary -21:05:19.195 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -21:05:19.234 MoveAxis Primary OK CanMoveAxis Primary is False and a MethodNotImplementedException exception was generated as expected -21:05:19.273 MoveAxis Secondary OK CanMoveAxis Secondary is False and a MethodNotImplementedException exception was generated as expected -21:05:19.314 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -21:05:21.349 PulseGuide OK Synchronous pulse guide found OK -21:06:13.942 SlewToCoordinates INFO Slewed within 15.0 arc seconds of expected RA: 09:31:10.00, actual RA: 09:31:09.00 -21:06:13.956 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 -21:06:13.971 SlewToCoordinates OK The TargetRightAscension property 09:31:10.00 matches the expected RA OK. -21:06:13.987 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -21:06:14.028 SlewToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:06:14.102 SlewToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:06:14.164 SlewToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:06:14.262 SlewToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:06:48.075 SlewToCoordinatesAsync INFO Slewed within 45.0 arc seconds of expected RA: 08:32:03.00, actual RA: 08:32:00.00 -21:06:48.090 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 -21:06:48.106 SlewToCoordinatesAsync OK The TargetRightAscension property 08:32:03.00 matches the expected RA OK. -21:06:48.122 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -21:06:48.164 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:06:48.239 SlewToCoordinatesAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:06:48.302 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:06:48.436 SlewToCoordinatesAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:07:22.044 SyncToCoordinates INFO Slewed to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 -21:07:22.061 SyncToCoordinates OK Slewed to start position OK. DEC: 26:55:00.00 -21:07:22.782 SyncToCoordinates INFO Synced to sync position within 15.0 arc seconds of expected RA: 07:28:37.00, actual RA: 07:28:36.00 -21:07:22.796 SyncToCoordinates OK Synced to sync position OK. DEC: 25:55:00.00 -21:07:22.812 SyncToCoordinates OK The TargetRightAscension property 07:28:37.00 matches the expected RA OK. -21:07:22.828 SyncToCoordinates OK The TargetDeclination property 25:55:00.00 matches the expected Declination OK. -21:07:53.961 SyncToCoordinates INFO Slewed back to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 -21:07:53.976 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:55:00.00 -21:07:54.692 SyncToCoordinates INFO Synced to reversed sync position within 30.0 arc seconds of expected RA: 07:36:37.00, actual RA: 07:36:35.00 -21:07:54.708 SyncToCoordinates OK Synced to reversed sync position OK. DEC: 27:55:00.00 -21:08:25.954 SyncToCoordinates INFO Slewed back to start position within 15.0 arc seconds of expected RA: 07:32:37.00, actual RA: 07:32:36.00 -21:08:25.969 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:55:00.00 -21:08:26.009 SyncToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, syncing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:08:26.087 SyncToCoordinates (Bad L) ERROR Unexpected DriverAccessCOMException, syncing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:08:26.150 SyncToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, syncing to bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:08:26.229 SyncToCoordinates (Bad H) ERROR Unexpected DriverAccessCOMException, syncing to bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:08:26.292 TargetRightAscension Write ERROR Unexpected DriverAccessCOMException, : Property TargetRightAscension The supplied value is out of range for this property. -21:08:26.311 TargetRightAscension Write ERROR Unexpected DriverAccessCOMException, : Property TargetRightAscension The supplied value is out of range for this property. -21:08:26.395 TargetRightAscension Write OK Legal value 06:34:15.00 HH:MM:SS written successfully -21:08:26.435 TargetDeclination Write ERROR Unexpected DriverAccessCOMException, : Property TargetDeclination The supplied value is out of range for this property. -21:08:26.454 TargetDeclination Write ERROR Unexpected DriverAccessCOMException, : Property TargetDeclination The supplied value is out of range for this property. -21:08:26.506 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -21:08:57.865 SlewToTarget INFO Slewed within 45.0 arc seconds of expected RA: 07:34:15.00, actual RA: 07:34:12.00 -21:08:57.880 SlewToTarget OK Slewed OK. DEC: 03:00:00.00 -21:08:57.897 SlewToTarget OK The TargetRightAscension property 07:34:15.00 matches the expected RA OK. -21:08:57.915 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -21:08:57.959 SlewToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:08:58.003 SlewToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:08:58.064 SlewToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:08:58.114 SlewToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:09:29.948 SlewToTargetAsync INFO Slewed within 45.0 arc seconds of expected RA: 06:34:47.00, actual RA: 06:34:44.00 -21:09:29.964 SlewToTargetAsync OK Slewed OK. DEC: 04:00:00.00 -21:09:29.979 SlewToTargetAsync OK The TargetRightAscension property 06:34:47.00 matches the expected RA OK. -21:09:29.996 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -21:09:30.038 SlewToTargetAsync (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:09:30.085 SlewToTargetAsync (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:09:30.150 SlewToTargetAsync (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:09:30.196 SlewToTargetAsync (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:09:30.257 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -21:09:30.278 SlewToAltAz ERROR Unexpected DriverAccessCOMException, CanSlewAltAz is True: Wrong tracking state -21:09:30.322 SlewToAltAz (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state -21:09:30.343 SlewToAltAz (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state -21:09:30.407 SlewToAltAz (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state -21:09:30.426 SlewToAltAz (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state -21:09:30.492 SlewToAltAzAsync ERROR Unexpected DriverAccessCOMException, CanSlewAltAzAsync is True: Wrong tracking state -21:09:30.534 SlewToAltAzAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state -21:09:30.552 SlewToAltAzAsync (Bad L) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state -21:09:30.617 SlewToAltAzAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Altitude coordinate: Wrong tracking state -21:09:30.637 SlewToAltAzAsync (Bad H) ERROR Unexpected DriverAccessCOMException, slewing to bad Azimuth coordinate: Wrong tracking state -21:10:05.974 SyncToTarget OK Slewed to start position OK. RA: 07:35:20.00 -21:10:05.993 SyncToTarget OK Slewed to start position OK. DEC: 26:55:00.00 -21:10:06.721 SyncToTarget OK Synced to sync position OK. RA: 07:31:20.00 -21:10:06.736 SyncToTarget OK Synced to sync position OK. DEC: 25:55:00.00 -21:10:37.626 SyncToTarget OK Slewed back to start position OK. RA: 07:35:20.00 -21:10:37.641 SyncToTarget OK Slewed back to start position OK. DEC: 26:55:00.00 -21:10:38.363 SyncToTarget OK Synced to reversed sync position OK. RA: 07:39:20.00 -21:10:38.381 SyncToTarget OK Synced to reversed sync position OK. DEC: 27:55:00.00 -21:11:09.639 SyncToTarget OK Slewed back to start position OK. RA: 07:35:20.00 -21:11:09.657 SyncToTarget OK Slewed back to start position OK. DEC: 26:55:00.00 -21:11:09.697 SyncToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:11:09.741 SyncToTarget (Bad L) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:11:09.803 SyncToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad RA coordinate: Property TargetRightAscension The supplied value is out of range for this property. -21:11:09.847 SyncToTarget (Bad H) ERROR Unexpected DriverAccessCOMException, Exception setting bad Dec coordinate: Property TargetDeclination The supplied value is out of range for this property. -21:11:10.010 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected - -SideOfPier Model Tests -21:11:10.080 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read - -Post-run Checks -21:11:10.180 Mount Safety INFO Tracking can't be turned off for this mount, please switch off manually. - -Conformance test complete - -Your driver had 53 errors, 0 warnings and 0 issues \ No newline at end of file diff --git a/TestConsole/Program.cs b/TelescopeTestConsole/Program.cs similarity index 71% rename from TestConsole/Program.cs rename to TelescopeTestConsole/Program.cs index 6c8fa71..72b790c 100644 --- a/TestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -22,17 +22,19 @@ namespace ASCOM // Uncomment the code that's required #if UseChooser // choose the device - string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.MeadeAutostar497.Telescope"); + string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.Meade.net.Telescope"); if (string.IsNullOrEmpty(id)) return; // create this device ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope(id); #else // this can be replaced by this code, it avoids the chooser and creates the driver class directly. - ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.MeadeAutostar497.Telescope"); + ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.Meade.net.Telescope"); #endif // now run some tests, adding code to your driver so that the tests will pass. // these first tests are common to all drivers. + + Console.WriteLine("name " + device.Name); Console.WriteLine("description " + device.Description); Console.WriteLine("DriverInfo " + device.DriverInfo); @@ -41,29 +43,11 @@ namespace ASCOM // TODO add more code to test the driver. device.Connected = true; - //Console.WriteLine(device.Slewing); + //Console.WriteLine($"Altitute {device.Altitude}"); - //device.UTCDate = DateTime.UtcNow; - //Console.WriteLine(device.UTCDate.ToLocalTime()); + //Console.WriteLine($"Dec {device.Declination}"); - - //Console.WriteLine(device.AlignmentMode); - - - - //double l = device.SiteLatitude; - //device.SiteLatitude = l; - - //double l = device.SiteLongitude; - //device.SiteLongitude = l; - //Console.WriteLine(device.SiteLongitude); - - //Console.WriteLine(device.RightAscension); - - //device.SlewToAltAz(0,0); - - - Console.WriteLine(device.TrackingRate); + device.SlewToAltAz(30, 45); device.Connected = false; Console.WriteLine("Press Enter to finish"); diff --git a/TestConsole/Properties/AssemblyInfo.cs b/TelescopeTestConsole/Properties/AssemblyInfo.cs similarity index 93% rename from TestConsole/Properties/AssemblyInfo.cs rename to TelescopeTestConsole/Properties/AssemblyInfo.cs index 86599a1..2b89b32 100644 --- a/TestConsole/Properties/AssemblyInfo.cs +++ b/TelescopeTestConsole/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("q Test Application")] +[assembly: AssemblyTitle("Meade.net Test Application")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("ASCOM Initiative")] -[assembly: AssemblyProduct("q")] +[assembly: AssemblyProduct("Meade.net")] [assembly: AssemblyCopyright("Copyright © ASCOM Initiative 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/TestConsole/TestConsole.csproj b/TelescopeTestConsole/TelescopeTestConsole.csproj similarity index 92% rename from TestConsole/TestConsole.csproj rename to TelescopeTestConsole/TelescopeTestConsole.csproj index 34ad58e..deb5415 100644 --- a/TestConsole/TestConsole.csproj +++ b/TelescopeTestConsole/TelescopeTestConsole.csproj @@ -8,15 +8,15 @@ {D5207217-61C7-4E94-8097-91DBACE57D2A} Exe Properties - TestConsole - TestConsole - v4.6 + ASCOM.Meade.net + ASCOM.Meade.net.Test + v4.7.1 512 - AnyCPU + x86 true full false diff --git a/TelescopeTestConsole/app.config b/TelescopeTestConsole/app.config new file mode 100644 index 0000000..70dcdba --- /dev/null +++ b/TelescopeTestConsole/app.config @@ -0,0 +1,3 @@ + + + From 85fcb8a73c0bf7442071fdb203cd69cad0af1f20 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 17 May 2019 23:56:55 +0100 Subject: [PATCH 039/109] Added comments for all meade commands. Fixed the Site Lat and Long setters --- Meade.net.Telescope/Telescope.cs | 116 ++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index f16ff1b..93f4eaf 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -231,6 +231,8 @@ namespace ASCOM.Meade.net LogMessage("Connected Set", "Connecting to port {0}", comPort); SharedResources.Connect("Serial"); connectedState = true; + + SelectSite(1); } else { @@ -241,6 +243,14 @@ namespace ASCOM.Meade.net } } + private void SelectSite(int site) + { + SharedResources.SendBlind($":W{site}#"); + //:W# + //Set current site to, an ASCII digit in the range 1..4 + //Returns: Nothing + } + public string Description { // TODO customise this device description @@ -311,11 +321,13 @@ namespace ASCOM.Meade.net #endregion #region ITelescope Implementation - + public void AbortSlew() { tl.LogMessage("AbortSlew", "Aborting slew"); SharedResources.SendBlind(":Q#"); + //:Q# Halt all current slewing + //Returns:Nothing } public AlignmentModes AlignmentMode @@ -327,6 +339,12 @@ namespace ASCOM.Meade.net const char ack = (char) 6; var alignmentString = SharedResources.SendChar(ack.ToString()); + //ACK <0x06> Query of alignment mounting mode. + //Returns: + //A If scope in AltAz Mode + //D If scope is currently in the Downloader[Autostar II & Autostar] + //L If scope in Land Mode + //P If scope in Polar Mode //todo implement GW Command //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); @@ -838,6 +856,8 @@ namespace ASCOM.Meade.net return; SharedResources.SendBlind(":hP#"); + //:hP# Autostar, Autostar II and LX 16”Slew to Park Position + //Returns: Nothing AtPark = true; } @@ -867,16 +887,43 @@ namespace ASCOM.Meade.net if (_userNewerPulseGuiding) { SharedResources.SendBlind($":Mg{d}{duration:0000}#"); - utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed + //:MgnDDDD# + //:MgsDDDD# + //:MgeDDDD# + //:MgwDDDD# + //Guide telescope in the commanded direction(nsew) for the number of milliseconds indicated by the unsigned number + //passed in the command.These commands support serial port driven guiding. + //Returns – Nothing + //LX200 – Not Supported + + utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed } else { SharedResources.Lock(() => { SharedResources.SendBlind(":RG#"); //Make sure we are at guide rate + //:RG# Set Slew rate to Guiding Rate (slowest) + //Returns: Nothing SharedResources.SendBlind($":M{d}#"); + //:Me# Move Telescope East at current slew rate + //Returns: Nothing + //:Mn# Move Telescope North at current slew rate + //Returns: Nothing + //:Ms# Move Telescope South at current slew rate + //Returns: Nothing + //:Mw# Move Telescope West at current slew rate + //Returns: Nothing utilities.WaitForMilliseconds(duration); SharedResources.SendBlind($":Q{d}#"); + //:Qe# Halt eastward Slews + //Returns: Nothing + //:Qn# Halt northward Slews + //Returns: Nothing + //:Qs# Halt southward Slews + //Returns: Nothing + //:Qw# Halt westward Slews + //Returns: Nothing }); } } @@ -977,6 +1024,9 @@ namespace ASCOM.Meade.net get { var latitude = SharedResources.SendString(":Gt#"); + //:Gt# Get Current Site Latitude + //Returns: sDD* MM# + //The latitude of the current site. Positive inplies North latitude. var siteLatitude = utilities.DMSToDegrees(latitude); tl.LogMessage("SiteLatitude Get", $"{utilities.DegreesToDMS(siteLatitude)}"); @@ -992,10 +1042,16 @@ namespace ASCOM.Meade.net if (value < -90) throw new InvalidValueException("Latitude cannot be less than -90 degrees."); + string sign = value > 0 ? "+" : "-"; int d = Convert.ToInt32(Math.Floor(value)); int m = Convert.ToInt32(60 * (value - d)); - var result = SharedResources.SendChar($":Sts{d:00}*{m:00}#"); + var result = SharedResources.SendChar($":St{sign}{d:00}*{m:00}#"); + //:StsDD*MM# + //Sets the current site latitude to sDD* MM# + //Returns: + //0 – Invalid + //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site latitude."); } @@ -1006,27 +1062,44 @@ namespace ASCOM.Meade.net get { var longitude = SharedResources.SendString(":Gg#"); + //:Gg# Get Current Site Longitude + //Returns: sDDD* MM# + //The current site Longitude. East Longitudes are expressed as negative double siteLongitude = utilities.DMSToDegrees(longitude); if (siteLongitude > 180) siteLongitude = siteLongitude - 360; + siteLongitude = -siteLongitude; + tl.LogMessage("SiteLongitude Get", $"{utilities.DegreesToDMS(siteLongitude)}"); return siteLongitude; } set { - tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(value)}"); - if (value > 180) + var newLongitude = value; + + tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(newLongitude)}"); + if (newLongitude > 180) throw new InvalidValueException("Longitude cannot be greater than 180 degrees."); - if (value < -180) + if (newLongitude < -180) throw new InvalidValueException("Longitude cannot be lower than -180 degrees."); - int d = Convert.ToInt32(Math.Floor(value)); - int m = Convert.ToInt32(60 * (value - d)); + if (newLongitude > 0) + newLongitude = 360 - newLongitude; + + newLongitude = Math.Abs(newLongitude); + + int d = Convert.ToInt32(Math.Floor(newLongitude)); + int m = Convert.ToInt32(60 * (newLongitude - d)); var result = SharedResources.SendChar($":Sg{d:000}*{m:00}#"); + //:SgDDD*MM# + //Set current site’s longitude to DDD*MM an ASCII position string + //Returns: + //0 – Invalid + //1 - Valid if (result != "1") throw new InvalidOperationException("Failed to set site longitude."); } @@ -1235,6 +1308,10 @@ namespace ASCOM.Meade.net return true; var result = SharedResources.SendString(":D#"); + //:D# Requests a string of bars indicating the distance to the current target location. + //Returns: + //LX200's – a string of bar characters indicating the distance. + //Autostars and Autostar II – a string containing one bar until a slew is complete, then a null string is returned. bool isSlewing = result != string.Empty; tl.LogMessage("Slewing Get", $"Result = {isSlewing}"); @@ -1458,6 +1535,10 @@ namespace ASCOM.Meade.net private TimeSpan GetUtcCorrection() { string utcOffSet = SharedResources.SendString(":GG#"); + //:GG# Get UTC offset time + //Returns: sHH# or sHH.H# + //The number of decimal hours to add to local time to convert it to UTC. If the number is a whole number the + //sHH# form is returned, otherwise the longer form is returned. double utcOffsetHours = double.Parse(utcOffSet); TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); return utcCorrection; @@ -1480,7 +1561,13 @@ namespace ASCOM.Meade.net { TelescopeDateDetails tdd = new TelescopeDateDetails(); tdd.telescopeDate = SharedResources.SendString(":GC#"); + //:GC# Get current date. + //Returns: MM / DD / YY# + //The current local calendar date for the telescope. tdd.telescopeTime = SharedResources.SendString(":GL#"); + //:GL# Get Local Time in 24 hour format + //Returns: HH: MM: SS# + //The Local Time in 24 - hour Format tdd.utcCorrection = GetUtcCorrection(); return tdd; @@ -1499,7 +1586,6 @@ namespace ASCOM.Meade.net int minute = telescopeDateDetails.telescopeTime.Substring(3, 2).ToInteger(); int second = telescopeDateDetails.telescopeTime.Substring(6, 2).ToInteger(); - //Todo is this telescope local time, or real utc? var utcDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + telescopeDateDetails.utcCorrection; @@ -1516,14 +1602,24 @@ namespace ASCOM.Meade.net var utcCorrection = GetUtcCorrection(); var localDateTime = value - utcCorrection; - //Todo is this telescope local time, or real utc? var timeResult = SharedResources.SendChar($":SL{localDateTime:HH:mm:ss}#"); + //:SLHH:MM:SS# + //Set the local Time + //Returns: + //0 – Invalid + //1 - Valid if (timeResult != "1") { throw new InvalidOperationException("Failed to set local time"); } var dateResult = SharedResources.SendChar($":SC{localDateTime:MM/dd/yy}#"); + //:SCMM/DD/YY# + //Change Handbox Date to MM/DD/YY + //Returns: + //D = ‘0’ if the date is invalid.The string is the null string. + //D = ‘1’ for valid dates and the string is “Updating Planetary Data# #” + //Note: For Autostar II this is the UTC data! if (dateResult != "1") { throw new InvalidOperationException("Failed to set local date"); From cf5a6c72fe4f2cda9b5413fbb1a67c1274f4d144 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 18 May 2019 00:08:07 +0100 Subject: [PATCH 040/109] Re instated the Altitude value and ran conformance for both the telescope and focuser. --- ASCOM.MeadeGeneric.Telescope.Validation.txt | 468 ++++++++++---------- ASCOM.MeadeGeneric.focuser.Validation.txt | 85 ++-- Meade.net.Telescope/Telescope.cs | 18 +- 3 files changed, 286 insertions(+), 285 deletions(-) diff --git a/ASCOM.MeadeGeneric.Telescope.Validation.txt b/ASCOM.MeadeGeneric.Telescope.Validation.txt index bb3467c..79c7484 100644 --- a/ASCOM.MeadeGeneric.Telescope.Validation.txt +++ b/ASCOM.MeadeGeneric.Telescope.Validation.txt @@ -1,4 +1,4 @@ -Conform Report Hash (V1): D69EDCF187DF1AC5C724D181E8851014862252A6F96F5BD9DDE1C8AF96CB36F7E019D48BA6EF49E5B0990934E09B5898888AF1D957D11C05084347222405B5F1 +Conform Report Hash (V1): E0EA1442C34B74A8386CB4D1755D11EA73FC54E7F9DC5CB5084F74C896E4979F909360686B70F44E734318AA35CB91C39347C5F65C93A03D420358D99DFCF5CE ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 @@ -14,256 +14,256 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -23:26:10.548 Driver Access Checks OK -23:26:11.194 AccessChecks OK Successfully created driver using late binding -23:26:11.406 AccessChecks OK Successfully connected using late binding -23:26:11.412 AccessChecks INFO The driver is a .NET object -23:26:11.417 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Telescope, ASCOM.Meade.net.Telescope, Version=6.4.0.0, Cultu -23:26:11.422 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -23:26:12.127 AccessChecks INFO Device does not expose interface ITelescopeV2 -23:26:12.921 AccessChecks INFO Device exposes interface ITelescopeV3 -23:26:14.237 AccessChecks OK Successfully created driver using driver access toolkit -23:26:14.396 AccessChecks OK Successfully connected using driver access toolkit +23:59:11.344 Driver Access Checks OK +23:59:11.990 AccessChecks OK Successfully created driver using late binding +23:59:12.222 AccessChecks OK Successfully connected using late binding +23:59:12.226 AccessChecks INFO The driver is a .NET object +23:59:12.231 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Telescope, ASCOM.Meade.net.Telescope, Version=0.4.0.0, Cultu +23:59:12.235 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +23:59:12.936 AccessChecks INFO Device does not expose interface ITelescopeV2 +23:59:13.747 AccessChecks INFO Device exposes interface ITelescopeV3 +23:59:15.062 AccessChecks OK Successfully created driver using driver access toolkit +23:59:15.233 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -23:26:15.721 ConformanceCheck OK Driver instance created successfully -23:26:15.918 ConformanceCheck OK Connected OK +23:59:16.556 ConformanceCheck OK Driver instance created successfully +23:59:16.766 ConformanceCheck OK Connected OK Common Driver Methods -23:26:15.957 InterfaceVersion OK 3 -23:26:15.986 Connected OK True -23:26:16.014 Description OK Meade Generic -23:26:16.042 DriverInfo OK Information about the driver itself. Version: 6.4 -23:26:16.071 DriverVersion OK 6.4 -23:26:16.099 Name OK Meade Generic -23:26:16.127 CommandString INFO Conform cannot test the CommandString method -23:26:16.133 CommandBlind INFO Conform cannot test the CommandBlind method -23:26:16.140 CommandBool INFO Conform cannot test the CommandBool method -23:26:16.146 Action INFO Conform cannot test the Action method -23:26:16.153 SupportedActions OK Driver returned an empty action list +23:59:16.808 InterfaceVersion OK 3 +23:59:16.837 Connected OK True +23:59:16.865 Description OK Meade Generic +23:59:16.894 DriverInfo OK Information about the driver itself. Version: 0.4 +23:59:16.923 DriverVersion OK 0.4 +23:59:16.952 Name OK Meade Generic +23:59:16.981 CommandString INFO Conform cannot test the CommandString method +23:59:16.987 CommandBlind INFO Conform cannot test the CommandBlind method +23:59:16.994 CommandBool INFO Conform cannot test the CommandBool method +23:59:17.001 Action INFO Conform cannot test the Action method +23:59:17.009 SupportedActions OK Driver returned an empty action list Can Properties -23:26:16.220 CanFindHome OK False -23:26:16.227 CanPark OK True -23:26:16.235 CanPulseGuide OK True -23:26:16.242 CanSetDeclinationRate OK False -23:26:16.250 CanSetGuideRates OK False -23:26:16.259 CanSetPark OK False -23:26:16.268 CanSetPierSide OK False -23:26:16.315 CanSetRightAscensionRate OK False -23:26:16.323 CanSetTracking OK True -23:26:16.331 CanSlew OK True -23:26:16.338 CanSlewltAz OK True -23:26:16.347 CanSlewAltAzAsync OK True -23:26:16.355 CanSlewAsync OK True -23:26:16.364 CanSync OK True -23:26:16.372 CanSyncAltAz OK False -23:26:16.381 CanUnPark OK False +23:59:17.077 CanFindHome OK False +23:59:17.086 CanPark OK True +23:59:17.094 CanPulseGuide OK True +23:59:17.103 CanSetDeclinationRate OK False +23:59:17.111 CanSetGuideRates OK False +23:59:17.119 CanSetPark OK False +23:59:17.128 CanSetPierSide OK False +23:59:17.139 CanSetRightAscensionRate OK False +23:59:17.147 CanSetTracking OK True +23:59:17.156 CanSlew OK True +23:59:17.161 CanSlewltAz OK True +23:59:17.172 CanSlewAltAzAsync OK True +23:59:17.182 CanSlewAsync OK True +23:59:17.191 CanSync OK True +23:59:17.201 CanSyncAltAz OK False +23:59:17.210 CanUnPark OK False Pre-run Checks -23:26:16.430 Mount Safety INFO Scope is not parked, continuing testing -23:26:16.461 Mount Safety INFO Scope tracking has been enabled -23:26:16.493 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -23:26:16.501 TimeCheck INFO PC UTCDate: 16-May-2019 22:26:16.501 -23:26:20.497 TimeCheck INFO Mount UTCDate: 02-May-2019 20:48:03.000 +23:59:17.257 Mount Safety INFO Scope is not parked, continuing testing +23:59:17.288 Mount Safety INFO Scope tracking has been enabled +23:59:17.319 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +23:59:17.327 TimeCheck INFO PC UTCDate: 17-May-2019 22:59:17.327 +23:59:17.449 TimeCheck INFO Mount UTCDate: 17-May-2019 22:59:16.000 Properties -23:26:20.700 AlignmentMode OK algPolar -23:26:21.594 Altitude WARNING Altitude is <0.0 degrees: -0.69166667 -23:26:21.628 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -23:26:21.662 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -23:26:21.694 AtHome OK False -23:26:21.726 AtPark OK False -23:26:22.439 Azimuth OK 104.84 -23:26:23.342 Declination OK 00:41:30.00 -23:26:23.374 DeclinationRate Read OK 0.00 -23:26:23.406 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -23:26:23.440 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:23.474 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:23.507 EquatorialSystem OK equLocalTopocentric -23:26:23.539 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -23:26:23.590 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:23.601 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -23:26:23.634 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:23.645 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -23:26:23.679 IsPulseGuiding OK False -23:26:24.386 RightAscension OK 09:40:57.00 -23:26:24.420 RightAscensionRate Read OK 0.00 -23:26:24.455 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -23:26:24.488 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:24.523 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:24.534 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:24.545 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:25.089 SiteLatitude Read OK 00:00:00.00 -23:26:25.126 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -23:26:25.137 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -23:26:27.021 SiteLatitude Write OK Legal value 00:00:00.00 degrees written successfully -23:26:27.875 SiteLongitude Read OK -53:48:00.00 -23:26:27.911 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -23:26:27.924 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -23:26:29.326 SiteLongitude Write OK Legal value -53:48:00.00 degrees written successfully -23:26:29.945 Slewing OK False -23:26:29.983 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:30.019 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:30.037 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -23:26:30.072 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -23:26:30.839 SiderealTime OK 10:27:03.72 -23:26:30.851 SiderealTime OK Scope and ASCOM sidereal times agree to better than 5 minutes, Scope: 10:27:03.72, ASCOM: 10:28:41.54 -23:26:30.888 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -23:26:30.923 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -23:26:30.936 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -23:26:30.975 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -23:26:30.988 Tracking Read OK True -23:26:32.051 Tracking Write OK False -23:26:33.116 TrackingRates Found drive rate: driveSidereal -23:26:33.129 TrackingRates Found drive rate: driveLunar -23:26:33.141 TrackingRates OK Drive rates read OK -23:26:33.154 TrackingRates OK Disposed tracking rates OK -23:26:33.189 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -23:26:33.205 TrackingRate Read OK driveSidereal -23:26:33.244 TrackingRate Write OK Successfully set drive rate: driveSidereal -23:26:33.281 TrackingRate Write OK Successfully set drive rate: driveLunar -23:26:37.575 UTCDate Read OK 02-May-2019 20:48:20.000 -23:26:43.750 UTCDate Write OK New UTCDate written successfully: 02/05/2019 21:48:20 +23:59:17.513 AlignmentMode OK algPolar +23:59:17.564 Altitude OK 88.71 +23:59:17.602 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +23:59:17.635 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +23:59:17.667 AtHome OK False +23:59:17.699 AtPark OK False +23:59:17.746 Azimuth OK 0.00 +23:59:17.802 Declination OK 88:42:41.00 +23:59:17.834 DeclinationRate Read OK 0.00 +23:59:17.867 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +23:59:17.902 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:17.935 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:17.968 EquatorialSystem OK equLocalTopocentric +23:59:18.002 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.043 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.054 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +23:59:18.087 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.099 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +23:59:18.132 IsPulseGuiding OK False +23:59:18.179 RightAscension OK 14:41:52.00 +23:59:18.213 RightAscensionRate Read OK 0.00 +23:59:18.247 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +23:59:18.281 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.316 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.327 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.338 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.394 SiteLatitude Read OK 53:48:00.00 +23:59:18.432 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +23:59:18.444 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +23:59:18.477 SiteLatitude Write OK Legal value 53:48:00.00 degrees written successfully +23:59:18.535 SiteLongitude Read OK -01:47:00.00 +23:59:18.570 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +23:59:18.583 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +23:59:18.621 SiteLongitude Write OK Legal value -01:47:00.00 degrees written successfully +23:59:18.667 Slewing OK False +23:59:18.704 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.739 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.752 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.786 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +23:59:18.834 SiderealTime OK 14:33:34.37 +23:59:18.847 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 14:33:34.37, ASCOM: 14:33:35.47 +23:59:18.882 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +23:59:18.917 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +23:59:18.929 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +23:59:18.964 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +23:59:18.976 Tracking Read OK True +23:59:20.035 Tracking Write OK False +23:59:21.100 TrackingRates Found drive rate: driveSidereal +23:59:21.112 TrackingRates Found drive rate: driveLunar +23:59:21.124 TrackingRates OK Drive rates read OK +23:59:21.139 TrackingRates OK Disposed tracking rates OK +23:59:21.174 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +23:59:21.184 TrackingRate Read OK driveSidereal +23:59:21.223 TrackingRate Write OK Successfully set drive rate: driveSidereal +23:59:21.258 TrackingRate Write OK Successfully set drive rate: driveLunar +23:59:21.338 UTCDate Read OK 17-May-2019 22:59:20.000 +23:59:21.554 UTCDate Write OK New UTCDate written successfully: 17/05/2019 23:59:20 Methods -23:26:50.522 CanMoveAxis:Primary OK CanMoveAxis:Primary True -23:26:50.560 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -23:26:50.597 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -23:26:50.634 Park/Unpark INFO Tests skipped -23:26:50.653 AbortSlew OK AbortSlew OK when not slewing -23:26:50.718 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -23:26:50.731 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -23:26:50.743 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -23:26:50.755 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -23:26:50.767 AxisRate:Primary OK No overlapping axis rates found -23:26:50.781 AxisRate:Primary OK No duplicate axis rates found -23:26:50.795 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -23:26:50.809 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -23:26:50.823 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -23:26:50.836 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -23:26:50.848 AxisRate:Primary OK Disposed axis rates OK -23:26:50.862 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -23:26:50.875 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -23:26:50.888 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -23:26:50.901 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -23:26:50.913 AxisRate:Secondary OK No overlapping axis rates found -23:26:50.926 AxisRate:Secondary OK No duplicate axis rates found -23:26:50.939 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -23:26:50.951 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -23:26:50.964 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -23:26:50.977 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -23:26:50.991 AxisRate:Secondary OK Disposed axis rates OK -23:26:51.006 AxisRate:Tertiary OK Empty axis rate returned -23:26:51.020 AxisRate:Tertiary OK Disposed axis rates OK -23:26:51.037 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -23:26:51.087 MoveAxis Primary OK Can successfully set a movement rate of zero -23:26:51.104 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -23:26:51.141 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -23:26:55.308 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -23:27:01.632 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -23:27:05.847 MoveAxis Primary OK Tracking state correctly retained for both tracking states -23:27:05.863 MoveAxis Primary OK AxisRates object successfully disposed -23:27:05.923 MoveAxis Secondary OK Can successfully set a movement rate of zero -23:27:05.939 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -23:27:05.976 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -23:27:10.149 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -23:27:16.454 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -23:27:20.626 MoveAxis Secondary OK Tracking state correctly retained for both tracking states -23:27:20.641 MoveAxis Secondary OK AxisRates object successfully disposed -23:27:20.701 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -23:27:22.740 PulseGuide OK Synchronous pulse guide found OK -23:27:53.262 SlewToCoordinates OK Slewed OK. RA: 09:27:56.59 -23:27:53.280 SlewToCoordinates INFO Slewed within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -23:27:53.295 SlewToCoordinates OK The TargetRightAscension property 09:27:56.59 matches the expected RA OK. -23:27:53.309 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -23:27:53.356 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -23:27:57.509 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -23:27:57.569 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -23:28:01.565 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -23:28:33.449 SlewToCoordinatesAsync INFO Slewed within 52.6 arc seconds of expected RA: 08:28:35.51, actual RA: 08:28:32.00 -23:28:33.463 SlewToCoordinatesAsync INFO Slewed within 14398.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: -01:59:58.00 -23:28:33.479 SlewToCoordinatesAsync OK The TargetRightAscension property 08:28:35.51 matches the expected RA OK. -23:28:33.496 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -23:28:33.539 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -23:28:37.553 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -23:28:37.614 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -23:28:41.477 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -23:29:15.070 SyncToCoordinates INFO Slewed to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 -23:29:15.084 SyncToCoordinates OK Slewed to start position OK. DEC: 00:00:00.00 -23:29:22.898 SyncToCoordinates INFO Synced to sync position within 33.3 arc seconds of expected RA: 07:25:17.22, actual RA: 07:25:15.00 -23:29:22.912 SyncToCoordinates INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -23:29:22.928 SyncToCoordinates OK The TargetRightAscension property 07:25:17.22 matches the expected RA OK. -23:29:22.942 SyncToCoordinates OK The TargetDeclination property -01:00:00.00 matches the expected Declination OK. -23:29:51.132 SyncToCoordinates INFO Slewed back to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 -23:29:51.146 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -23:30:01.039 SyncToCoordinates INFO Synced to reversed sync position within 18.3 arc seconds of expected RA: 07:33:17.22, actual RA: 07:33:16.00 -23:30:01.052 SyncToCoordinates INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -23:30:31.303 SyncToCoordinates INFO Slewed back to start position within 18.3 arc seconds of expected RA: 07:29:17.22, actual RA: 07:29:16.00 -23:30:31.317 SyncToCoordinates OK Slewed back to start position OK. DEC: 00:00:00.00 -23:30:31.357 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -23:30:35.078 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -23:30:35.139 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -23:30:39.202 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -23:30:39.261 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -23:30:39.277 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -23:30:43.319 TargetRightAscension Write OK Legal value 06:31:13.60 HH:MM:SS written successfully -23:30:43.356 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -23:30:43.372 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -23:30:46.838 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -23:31:17.315 SlewToTarget INFO Slewed within 18.1 arc seconds of expected RA: 07:31:21.21, actual RA: 07:31:20.00 -23:31:17.331 SlewToTarget INFO Slewed within 21597.0 arc seconds of expected DEC: 03:00:00.00, actual DEC: -02:59:57.00 -23:31:17.350 SlewToTarget OK The TargetRightAscension property 07:31:21.21 matches the expected RA OK. -23:31:17.379 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -23:31:17.421 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -23:31:18.143 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -23:31:18.205 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -23:31:18.847 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -23:31:51.318 SlewToTargetAsync INFO Slewed within 19.9 arc seconds of expected RA: 06:31:53.33, actual RA: 06:31:52.00 -23:31:51.332 SlewToTargetAsync INFO Slewed within 28799.0 arc seconds of expected DEC: 04:00:00.00, actual DEC: -03:59:59.00 -23:31:51.347 SlewToTargetAsync OK The TargetRightAscension property 06:31:53.33 matches the expected RA OK. -23:31:51.361 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -23:31:51.402 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -23:31:52.156 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -23:31:52.221 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -23:31:52.868 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -23:31:52.927 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -23:32:02.721 SlewToAltAz INFO Slewed to within 93:51:10.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -23:32:02.735 SlewToAltAz INFO Slewed to within 46:00:01.00 DD:MM:SS of expected Altitude: 50:00:00.00 -23:32:02.775 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -23:32:06.306 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -23:32:06.368 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -23:32:09.947 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -23:32:24.096 SlewToAltAzAsync INFO Slewed to within 98:56:32.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -23:32:24.110 SlewToAltAzAsync INFO Slewed to within 51:00:01.00 DD:MM:SS of expected Altitude: 55:00:00.00 -23:32:24.154 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -23:32:27.733 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -23:32:27.793 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -23:32:31.369 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -23:33:05.205 SyncToTarget INFO Slewed to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 -23:33:05.220 SyncToTarget OK Slewed to start position OK. DEC: 00:00:00.00 -23:33:15.238 SyncToTarget INFO Synced to sync position within 71.0 arc seconds of expected RA: 07:29:07.73, actual RA: 07:29:03.00 -23:33:15.252 SyncToTarget INFO Synced to sync position within 3660.0 arc seconds of expected DEC: -01:00:00.00, actual DEC: 00:01:00.00 -23:33:45.180 SyncToTarget INFO Slewed back to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 -23:33:45.195 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -23:33:55.078 SyncToTarget INFO Synced to reversed sync position within 71.0 arc seconds of expected RA: 07:37:07.73, actual RA: 07:37:03.00 -23:33:55.093 SyncToTarget INFO Synced to reversed sync position within 7200.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: -01:00:00.00 -23:34:25.167 SyncToTarget INFO Slewed back to start position within 56.0 arc seconds of expected RA: 07:33:07.73, actual RA: 07:33:04.00 -23:34:25.192 SyncToTarget OK Slewed back to start position OK. DEC: 00:00:00.00 -23:34:25.232 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -23:34:25.975 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -23:34:26.037 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -23:34:26.840 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -23:34:30.138 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +23:59:21.831 CanMoveAxis:Primary OK CanMoveAxis:Primary True +23:59:21.868 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +23:59:21.904 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +23:59:21.940 Park/Unpark INFO Tests skipped +23:59:21.958 AbortSlew OK AbortSlew OK when not slewing +23:59:22.020 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +23:59:22.037 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +23:59:22.050 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +23:59:22.062 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +23:59:22.075 AxisRate:Primary OK No overlapping axis rates found +23:59:22.091 AxisRate:Primary OK No duplicate axis rates found +23:59:22.109 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +23:59:22.122 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +23:59:22.135 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +23:59:22.147 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +23:59:22.160 AxisRate:Primary OK Disposed axis rates OK +23:59:22.173 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +23:59:22.185 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +23:59:22.197 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +23:59:22.209 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +23:59:22.222 AxisRate:Secondary OK No overlapping axis rates found +23:59:22.234 AxisRate:Secondary OK No duplicate axis rates found +23:59:22.246 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +23:59:22.258 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +23:59:22.271 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +23:59:22.283 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +23:59:22.297 AxisRate:Secondary OK Disposed axis rates OK +23:59:22.311 AxisRate:Tertiary OK Empty axis rate returned +23:59:22.325 AxisRate:Tertiary OK Disposed axis rates OK +23:59:22.341 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +23:59:22.386 MoveAxis Primary OK Can successfully set a movement rate of zero +23:59:22.405 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +23:59:22.442 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +23:59:26.654 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +23:59:30.860 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +23:59:35.034 MoveAxis Primary OK Tracking state correctly retained for both tracking states +23:59:35.050 MoveAxis Primary OK AxisRates object successfully disposed +23:59:35.110 MoveAxis Secondary OK Can successfully set a movement rate of zero +23:59:35.125 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +23:59:35.164 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +23:59:39.333 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +23:59:43.535 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +23:59:47.752 MoveAxis Secondary OK Tracking state correctly retained for both tracking states +23:59:47.770 MoveAxis Secondary OK AxisRates object successfully disposed +23:59:47.828 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +23:59:49.867 PulseGuide OK Synchronous pulse guide found OK +00:00:19.740 SlewToCoordinates INFO Slewed within 23.9 arc seconds of expected RA: 13:34:05.59, actual RA: 13:34:04.00 +00:00:19.753 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 +00:00:19.766 SlewToCoordinates OK The TargetRightAscension property 13:34:05.59 matches the expected RA OK. +00:00:19.782 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +00:00:19.829 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +00:00:19.944 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +00:00:20.006 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +00:00:20.074 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +00:00:38.898 SlewToCoordinatesAsync INFO Slewed within 58.1 arc seconds of expected RA: 12:34:35.88, actual RA: 12:34:32.00 +00:00:38.914 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 +00:00:38.927 SlewToCoordinatesAsync OK The TargetRightAscension property 12:34:35.88 matches the expected RA OK. +00:00:38.940 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +00:00:38.979 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +00:00:39.077 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +00:00:39.137 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +00:00:39.205 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +00:01:00.519 SyncToCoordinates INFO Slewed to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 +00:01:00.532 SyncToCoordinates OK Slewed to start position OK. DEC: 26:54:00.00 +00:01:01.420 SyncToCoordinates INFO Synced to sync position within 3553.2 arc seconds of expected RA: 11:30:55.12, actual RA: 11:34:52.00 +00:01:01.434 SyncToCoordinates INFO Synced to sync position within 3597.0 arc seconds of expected DEC: 25:54:00.00, actual DEC: 26:53:57.00 +00:01:01.447 SyncToCoordinates OK The TargetRightAscension property 11:30:55.12 matches the expected RA OK. +00:01:01.461 SyncToCoordinates OK The TargetDeclination property 25:54:00.00 matches the expected Declination OK. +00:01:17.464 SyncToCoordinates INFO Slewed back to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 +00:01:17.481 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 +00:01:18.320 SyncToCoordinates INFO Synced to reversed sync position within 3646.8 arc seconds of expected RA: 11:38:55.12, actual RA: 11:34:52.00 +00:01:18.334 SyncToCoordinates INFO Synced to reversed sync position within 3603.0 arc seconds of expected DEC: 27:54:00.00, actual DEC: 26:53:57.00 +00:01:34.081 SyncToCoordinates INFO Slewed back to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 +00:01:34.095 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 +00:01:34.134 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +00:01:34.238 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +00:01:34.299 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +00:01:34.373 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +00:01:34.431 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +00:01:34.450 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +00:01:34.557 TargetRightAscension Write OK Legal value 10:35:50.41 HH:MM:SS written successfully +00:01:34.593 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +00:01:34.607 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +00:01:34.659 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +00:01:53.415 SlewToTarget INFO Slewed within 39.7 arc seconds of expected RA: 11:35:50.64, actual RA: 11:35:48.00 +00:01:53.430 SlewToTarget OK Slewed OK. DEC: 03:00:00.00 +00:01:53.444 SlewToTarget OK The TargetRightAscension property 11:35:50.64 matches the expected RA OK. +00:01:53.458 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +00:01:53.499 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +00:01:53.590 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +00:01:53.651 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +00:01:53.698 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +00:02:12.772 SlewToTargetAsync INFO Slewed within 26.4 arc seconds of expected RA: 10:36:09.76, actual RA: 10:36:08.00 +00:02:12.789 SlewToTargetAsync OK Slewed OK. DEC: 04:00:00.00 +00:02:12.804 SlewToTargetAsync OK The TargetRightAscension property 10:36:09.76 matches the expected RA OK. +00:02:12.819 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +00:02:12.859 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +00:02:12.896 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +00:02:12.972 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +00:02:13.070 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +00:02:13.133 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +00:02:13.371 SlewToAltAz INFO Slewed to within 87:49:32.00 DD:MM:SS of expected Azimuth: 150:00:00.00 +00:02:13.387 SlewToAltAz INFO Slewed to within 46:00:03.00 DD:MM:SS of expected Altitude: 50:00:00.00 +00:02:13.430 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +00:02:13.473 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +00:02:13.538 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +00:02:13.575 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +00:02:18.862 SlewToAltAzAsync INFO Slewed to within 92:48:04.00 DD:MM:SS of expected Azimuth: 155:00:00.00 +00:02:18.876 SlewToAltAzAsync INFO Slewed to within 51:00:02.00 DD:MM:SS of expected Altitude: 55:00:00.00 +00:02:18.917 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +00:02:18.960 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +00:02:19.024 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +00:02:19.064 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +00:02:40.297 SyncToTarget INFO Slewed to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 +00:02:40.311 SyncToTarget OK Slewed to start position OK. DEC: 26:54:00.00 +00:02:41.176 SyncToTarget INFO Synced to sync position within 3551.4 arc seconds of expected RA: 11:32:35.24, actual RA: 11:36:32.00 +00:02:41.192 SyncToTarget INFO Synced to sync position within 3598.0 arc seconds of expected DEC: 25:54:00.00, actual DEC: 26:53:58.00 +00:02:57.142 SyncToTarget INFO Slewed back to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 +00:02:57.156 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 +00:02:57.998 SyncToTarget INFO Synced to reversed sync position within 3648.6 arc seconds of expected RA: 11:40:35.24, actual RA: 11:36:32.00 +00:02:58.012 SyncToTarget INFO Synced to reversed sync position within 3603.0 arc seconds of expected DEC: 27:54:00.00, actual DEC: 26:53:57.00 +00:03:14.149 SyncToTarget INFO Slewed back to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 +00:03:14.164 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 +00:03:14.203 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +00:03:14.256 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +00:03:14.330 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +00:03:14.370 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +00:03:14.574 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -23:34:30.213 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +00:03:14.635 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -23:34:30.305 Mount Safety OK Tracking stopped to protect your mount. +00:03:14.732 Mount Safety OK Tracking stopped to protect your mount. Conformance test complete -Your driver had 0 errors, 1 warning and 0 issue +No errors, warnings or issues found: your driver passes ASCOM validation!! -Driver Hash Value: E1CEF5959BFC13BA7F63F73CE38558054C95A93AFE504B722E7EBCDB7DC403E36016216B81EE41CCFE368BC213DDAA8F952A53B3DC88D294D73445C25125D33D +Driver Hash Value: 88EE4EE52A4E10A920380EE086D799AFBE0C2BB4807C2DF0FB2287C6FD57128D1D7C20ABB38632BA09DE6E55E6194CB75C087939AAFF5A38ED0235858618BFE3 diff --git a/ASCOM.MeadeGeneric.focuser.Validation.txt b/ASCOM.MeadeGeneric.focuser.Validation.txt index d263ba5..94a4712 100644 --- a/ASCOM.MeadeGeneric.focuser.Validation.txt +++ b/ASCOM.MeadeGeneric.focuser.Validation.txt @@ -1,4 +1,4 @@ -Conform Report Hash (V1): 67092198F82F435D10580E3B3E3E460EC0B5E438532A7B5D83C09425222F097CA9A23C883D4238654F217FCA9801E46720811B7CDB982868C68843CCDA33E7FB +Conform Report Hash (V1): BCDD202E20EC71628DFE60620D4E1F9A119F72953DCC4F8107039D0C9872C4A2B2EC2A759AF57819C2A53FA56A4643B552778C53924B743D9C049027AC09FD20 ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 @@ -9,61 +9,62 @@ ConformanceCheck Driver ProgID: ASCOM.MeadeGeneric.focuser Error handling Error number for "Not Implemented" is: 80040400 Error number for "Invalid Value 1" is: 80040404 +Error number for "Invalid Value 3" is: 80040405 Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -23:25:52.259 Driver Access Checks OK -23:25:52.911 AccessChecks OK Successfully created driver using late binding -23:25:53.126 AccessChecks OK Successfully connected using late binding -23:25:53.131 AccessChecks INFO The driver is a .NET object -23:25:53.137 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Focuser, ASCOM.Meade.net.Focuser, Version=6.4.0.0, Culture=n -23:25:53.142 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 -23:25:53.793 AccessChecks INFO Device does not expose IFocuser interface -23:25:53.855 AccessChecks INFO Device does not expose IFocuserV2 interface -23:25:54.068 AccessChecks INFO Device exposes IFocuserV3 interface -23:25:54.190 AccessChecks OK Successfully created driver using driver access toolkit -23:25:54.344 AccessChecks OK Successfully connected using driver access toolkit -23:25:54.407 AccessChecks OK Successfully disconnected using driver access toolkit +00:05:33.087 Driver Access Checks OK +00:05:33.758 AccessChecks OK Successfully created driver using late binding +00:05:33.983 AccessChecks OK Successfully connected using late binding +00:05:33.987 AccessChecks INFO The driver is a .NET object +00:05:33.991 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Focuser, ASCOM.Meade.net.Focuser, Version=0.4.0.0, Culture=n +00:05:33.996 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +00:05:34.640 AccessChecks INFO Device does not expose IFocuser interface +00:05:34.700 AccessChecks INFO Device does not expose IFocuserV2 interface +00:05:34.951 AccessChecks INFO Device exposes IFocuserV3 interface +00:05:35.069 AccessChecks OK Successfully created driver using driver access toolkit +00:05:35.263 AccessChecks OK Successfully connected using driver access toolkit +00:05:35.324 AccessChecks OK Successfully disconnected using driver access toolkit Conform is using ASCOM.DriverAccess.Focuser to get a Focuser object -23:25:54.480 ConformanceCheck OK Driver instance created successfully -23:25:54.679 ConformanceCheck OK Connected OK +00:05:35.394 ConformanceCheck OK Driver instance created successfully +00:05:35.608 ConformanceCheck OK Connected OK Common Driver Methods -23:25:54.721 InterfaceVersion OK 3 -23:25:54.750 Connected OK True -23:25:54.779 Description OK Meade Generic -23:25:54.808 DriverInfo OK Information about the driver itself. Version: 6.4 -23:25:54.837 DriverVersion OK 6.4 -23:25:54.866 Name OK Meade Generic -23:25:54.895 CommandString INFO Conform cannot test the CommandString method -23:25:54.901 CommandBlind INFO Conform cannot test the CommandBlind method -23:25:54.908 CommandBool INFO Conform cannot test the CommandBool method -23:25:54.916 Action INFO Conform cannot test the Action method -23:25:54.924 SupportedActions OK Driver returned an empty action list +00:05:35.647 InterfaceVersion OK 3 +00:05:35.676 Connected OK True +00:05:35.704 Description OK Meade Generic +00:05:35.736 DriverInfo OK Information about the driver itself. Version: 0.4 +00:05:35.765 DriverVersion OK 0.4 +00:05:35.794 Name OK Meade Generic +00:05:35.823 CommandString INFO Conform cannot test the CommandString method +00:05:35.829 CommandBlind INFO Conform cannot test the CommandBlind method +00:05:35.836 CommandBool INFO Conform cannot test the CommandBool method +00:05:35.842 Action INFO Conform cannot test the Action method +00:05:35.850 SupportedActions OK Driver returned an empty action list Properties -23:25:55.035 Absolute OK False -23:25:55.043 IsMoving OK False -23:25:55.051 MaxStep OK 7000 -23:25:55.059 MaxIncrement OK 7000 -23:25:55.073 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected -23:25:55.084 StepSize OK Optional member threw a PropertyNotImplementedException exception. -23:25:55.091 TempCompAvailable OK False -23:25:55.100 TempComp Read OK False -23:25:55.108 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected -23:25:55.120 Temperature OK Optional member threw a PropertyNotImplementedException exception. +00:05:35.961 Absolute OK False +00:05:35.968 IsMoving OK False +00:05:35.976 MaxStep OK 7000 +00:05:35.983 MaxIncrement OK 7000 +00:05:35.992 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected +00:05:36.000 StepSize OK Optional member threw a PropertyNotImplementedException exception. +00:05:36.008 TempCompAvailable OK False +00:05:36.016 TempComp Read OK False +00:05:36.024 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected +00:05:36.032 Temperature OK Optional member threw a PropertyNotImplementedException exception. Methods -23:25:55.170 Halt OK Focuser halted OK -23:25:55.183 Move - TempComp False Moving by: 700 -23:25:55.895 Move - TempComp False Asynchronous move found -23:25:55.904 Move - TempComp False OK Relative move OK -23:25:55.915 Move - TempComp False INFO Returning to original position: 0 +00:05:36.080 Halt OK Focuser halted OK +00:05:36.092 Move - TempComp False Moving by: 700 +00:05:36.804 Move - TempComp False Asynchronous move found +00:05:36.812 Move - TempComp False OK Relative move OK +00:05:36.822 Move - TempComp False INFO Returning to original position: 0 Conformance test complete No errors, warnings or issues found: your driver passes ASCOM validation!! -Driver Hash Value: DE237CD97B3A95A514A5D7FD9B265F5F98174E67A28B44FF5CA2FC9A1CF355DA2C4DFB9416F3C40A8056334CC5339F0D8F8A39026A4BB5E3AE1FFC2BD8F55FBD +Driver Hash Value: A3C2D8D9708D2B157CF8BFC2F83BFE3666DA07AA75C592BD3969D42E0566A2F69E06BBE7C33BA78914D292EF3529B65AA22052AC34D13F6B521127072ACF366F diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 93f4eaf..11762d1 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -404,17 +404,17 @@ namespace ASCOM.Meade.net get { //todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! - //var result = SharedResources.SendString(":GA#"); - ////:GA# Get Telescope Altitude - ////Returns: sDD* MM# or sDD*MM’SS# - ////The current scope altitude. The returned format depending on the current precision setting. + var result = SharedResources.SendString(":GA#"); + //:GA# Get Telescope Altitude + //Returns: sDD* MM# or sDD*MM’SS# + //The current scope altitude. The returned format depending on the current precision setting. - //var alt = utilities.DMSToDegrees(result); - //tl.LogMessage("Altitude", $"{alt}"); - //return alt; + var alt = utilities.DMSToDegrees(result); + tl.LogMessage("Altitude", $"{alt}"); + return alt; - tl.LogMessage("Altitude Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Altitude", false); + //tl.LogMessage("Altitude Get", "Not implemented"); + //throw new ASCOM.PropertyNotImplementedException("Altitude", false); } } From cf28ecc7c29bc76e57a4dc2d0801a23e14e0ea4e Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 18 May 2019 23:50:55 +0100 Subject: [PATCH 041/109] Redesigned the Altitude and Azimuth readings to use the Right Ascension and Declination co-ordinates and perform the transformation using the date and site details from the scope. This will correct the problem of the Altitude reading from the handset being incorrect. --- .../AstroMath.UnitTests.csproj | 83 +++++++++ AstroMath.UnitTests/AstroMathsUnitTests.cs | 149 ++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++ AstroMath.UnitTests/packages.config | 8 + Meade.net.Telescope/AstroMaths.cs | 165 ++++++++++++++++++ .../Meade.net.Telescope.csproj | 1 + Meade.net.Telescope/Telescope.cs | 56 ++++-- Meade.net.sln | 17 +- TelescopeTestConsole/Program.cs | 10 +- 9 files changed, 506 insertions(+), 19 deletions(-) create mode 100644 AstroMath.UnitTests/AstroMath.UnitTests.csproj create mode 100644 AstroMath.UnitTests/AstroMathsUnitTests.cs create mode 100644 AstroMath.UnitTests/Properties/AssemblyInfo.cs create mode 100644 AstroMath.UnitTests/packages.config create mode 100644 Meade.net.Telescope/AstroMaths.cs diff --git a/AstroMath.UnitTests/AstroMath.UnitTests.csproj b/AstroMath.UnitTests/AstroMath.UnitTests.csproj new file mode 100644 index 0000000..2004ecf --- /dev/null +++ b/AstroMath.UnitTests/AstroMath.UnitTests.csproj @@ -0,0 +1,83 @@ + + + + + + Debug + AnyCPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95} + Library + Properties + AstroMath.UnitTests + AstroMath.UnitTests + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll + + + ..\packages\Moq.4.10.1\lib\net45\Moq.dll + + + ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll + + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + {64308775-bd4a-469c-bcab-3ed830b811af} + Meade.net.Telescope + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs new file mode 100644 index 0000000..f4792d3 --- /dev/null +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -0,0 +1,149 @@ +using System; +using ASCOM.Meade.net; +using NUnit.Framework; + +namespace AstroMath.UnitTests +{ + [TestFixture] + public class AstroMathsUnitTests + { + private AstroMaths _astroMath; + + [SetUp] + public void Setup() + { + _astroMath = new AstroMaths(); + } + + [Test] + public void DegreesToRadians() + { + var radians = _astroMath.DegreesToRadians(90); + Assert.That(radians, Is.EqualTo(1.5707963267948966)); + } + + [Test] + public void RadiansToDegrees() + { + var degrees = _astroMath.RadiansToDegrees(1.5707963267948966); + Assert.That(degrees, Is.EqualTo(90)); + } + + + [Test] + public void DateTimeToDecimalHours_book() + { + DateTime dateTime = new DateTime(2019, 05, 18, 18, 31, 27, DateTimeKind.Utc); + var decimalHours = _astroMath.DateTimeToDecimalHours(dateTime); + + Assert.That(decimalHours, Is.EqualTo(18.524166666666666)); + } + + [Test] + public void DateTimeToDecimalHours() + { + DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); + var decimalHours = _astroMath.DateTimeToDecimalHours(dateTime); + + Assert.That(decimalHours, Is.EqualTo(22.4375)); + } + + [Test] + public void UTtoGST_book() + { + DateTime dateTime = new DateTime(1980, 04, 22, 14, 36, 51, 670, DateTimeKind.Utc); + double gst = _astroMath.UTtoGST(dateTime); + + Assert.That(gst, Is.EqualTo(4.667932706211154)); + } + + [Test] + public void UTtoGST() + { + DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); + double gst = _astroMath.UTtoGST(dateTime); + + Assert.That(gst, Is.EqualTo(14.191879687876451)); + } + + [Test] + public void GSTtoLST_book() + { + double gst = 4.668119; + var longitude = -64; + var lst = _astroMath.GSTtoLST(gst, longitude); + Assert.That(lst, Is.EqualTo(0.4014523333333333)); + } + + [Test] + public void GSTtoLST() + { + double gst = 14.257589512545053; + var longitude = -1.7833333333333332; + var lst = _astroMath.GSTtoLST(gst, longitude); + Assert.That(lst, Is.EqualTo(14.138700623656163)); + } + + [Test] + public void RightAscensionToHourAngle_book() + { + DateTime dateTime = new DateTime(1980, 04, 22, 18, 36, 51,670, DateTimeKind.Utc); + var longitude = -64; + var rightAscension = 18.539166666666667;//18:32'21" + + //var declination = 30.0019444444444 + var hourAngle = _astroMath.RightAscensionToHourAngle(dateTime, longitude, rightAscension); + Assert.That(hourAngle, Is.EqualTo(9.8730510088778161)); + } + + [Test] + public void RightAscensionToHourAngle() + { + DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); + var longitude = -1.7833333333333332; + var rightAscension = 4.15361111111111; + + var hourAngle = _astroMath.RightAscensionToHourAngle(dateTime, longitude, rightAscension); + Assert.That(hourAngle, Is.EqualTo(9.9193796878764502)); + } + + + [Test] + public void ConvertEqToHoz_book() + { + DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); + var longitude = -1.7833333333333332; + var latitude = 52.0; + + EquatorialCoordinates equatorialCoordinates = new EquatorialCoordinates(); + equatorialCoordinates.RightAscension = 5.862222222222222;//5 51' 44" + equatorialCoordinates.Declination = 23.21944444444444;//23 13' 10" + + //var hourAngle = _astroMath.RightAscensionToHourAngle(dateTime, longitude, equatorialCoordinates.RightAscension); + var hourAngle = 5.682222; + + var altAz = _astroMath.ConvertEqToHoz(hourAngle, latitude, equatorialCoordinates); + + Assert.That(altAz.Altitude, Is.EqualTo(20.958562421092779)); + Assert.That(altAz.Azimuth, Is.EqualTo(281.2728706962269)); + } + + [Test] + public void ConvertEqToHoz() + { + DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); + var longitude = -1.7833333333333332; + var latitude = 52.0; + EquatorialCoordinates equatorialCoordinates = new EquatorialCoordinates(); + equatorialCoordinates.RightAscension = 4.15361111111111; + equatorialCoordinates.Declination = 30.0019444444444; + + var hourAngle = _astroMath.RightAscensionToHourAngle(dateTime, longitude, equatorialCoordinates.RightAscension); + var altaz = _astroMath.ConvertEqToHoz(hourAngle, latitude, equatorialCoordinates); + + Assert.That(altaz.Altitude, Is.EqualTo(-3.5534402923925872)); + Assert.That(altaz.Azimuth, Is.EqualTo(333.2819484462679)); + } + + } +} diff --git a/AstroMath.UnitTests/Properties/AssemblyInfo.cs b/AstroMath.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..11e0a8b --- /dev/null +++ b/AstroMath.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AstroMath.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("AstroMath.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ad4959dd-33d7-4c3f-8db0-7361d8e74a95")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/AstroMath.UnitTests/packages.config b/AstroMath.UnitTests/packages.config new file mode 100644 index 0000000..22d8680 --- /dev/null +++ b/AstroMath.UnitTests/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Telescope/AstroMaths.cs b/Meade.net.Telescope/AstroMaths.cs new file mode 100644 index 0000000..d9d224e --- /dev/null +++ b/Meade.net.Telescope/AstroMaths.cs @@ -0,0 +1,165 @@ +using System; +using ASCOM.Utilities; + +namespace ASCOM.Meade.net +{ + public class EquatorialCoordinates + { + public double RightAscension { get; set; } + public double Declination { get; set; } + } + + public class HorizonCoordinates + { + public double Altitude { get; set; } + public double Azimuth { get; set; } + } + + + public class AltitudeData + { + public DateTime UtcDateTime { get; set; } + public double SiteLatitude { get; set; } + public double SiteLongitude { get; set; } + public EquatorialCoordinates equatorialCoordinates { get; set; } + } + + public class AstroMaths + { + + //returns the decimal hour angle for given right ascension on a given datetime for a given logitude. + public double RightAscensionToHourAngle(DateTime utcDateTime, double longitude, double rightAscension) + { + var ut = DateTimeToDecimalHours( utcDateTime); + var gst = UTtoGST( utcDateTime); + var lst = GSTtoLST( gst, longitude); + var raHours = rightAscension; + var h1 = lst - raHours; + var h = h1; + + if (h < 0) + h = h + 24; + + return h; + } + + public HorizonCoordinates ConvertEqToHoz(double hourAngle, double latitude, EquatorialCoordinates raDec) + { + var h = hourAngle * 15; + var h1 = DegreesToRadians(h); + var d = DegreesToRadians(raDec.Declination); + var lat = DegreesToRadians(latitude); + var sinA = Math.Sin(d) * Math.Sin(lat) + Math.Cos(d) * Math.Cos(lat) * Math.Cos(h1); + + var y = -Math.Cos(d) * Math.Cos(lat) * Math.Sin(h1); + var x = Math.Sin(d) - Math.Sin(lat) * sinA; + var upperA = Math.Atan2(y, x); + var upperB = RadiansToDegrees(upperA); + + var horizonCoordinates = new HorizonCoordinates(); + horizonCoordinates.Altitude = RadiansToDegrees(Math.Asin(sinA)); + + horizonCoordinates.Azimuth = upperB; + + if (upperB < 0) + { + horizonCoordinates.Azimuth = 360 + horizonCoordinates.Azimuth; + } + + return horizonCoordinates; + } + + + //todo convert to extension method + public double DegreesToRadians(double degrees) + { + return (Math.PI / 180) * degrees; + } + + //todo convert to extension method + public double RadiansToDegrees(double radians) + { + double degrees = (180 / Math.PI) * radians; + return (degrees); + } + + //todo convert to extension method + public double DateTimeToDecimalHours( DateTime utcDateTime) + { + double sec = utcDateTime.Second; + double min = utcDateTime.Minute; + double hour = utcDateTime.Hour; + + var a = Math.Abs(sec) / 60; + var b = (Math.Abs(min) + a) / 60; + var c = Math.Abs(hour) + b; + + var d = c; + + if ((hour < 0) || (min < 0) || (sec < 0)) + d = -c; + + return d; + } + + //todo convert to extension method + public double UTtoGST(DateTime utcDateTime) + { + Util util = new Util(); + + var jd = util.DateUTCToJulian(utcDateTime) - 0.5; + if ((jd % 1) <= 0.5 ) + jd = Math.Floor( jd ); + else + jd = Math.Floor( jd ) + 0.5; + + var s = jd - 2451545.0; + var t = s / 36525.0; + var t0 = 6.697374558 + (2400.051336 * t ) +(0.000025862 * (t * t) ); + + while (t0 < 0) + { + t0 += 24; + } + + while (t0 >= 24) + { + t0 -= 24; + } + + var ut = DateTimeToDecimalHours(utcDateTime); + var a = ut * 1.002737909; + + var t1 = t0 + a; + + while (t1 < 0) + { + t1 += 24; + } + + while (t1 >= 24) + { + t1 -= 24; + } + + return t1; + } + + public double GSTtoLST(double gst, double longitude) + { + var l = longitude/ 15; + + var lst = gst + l; + while (lst < 0 ) + { + lst += 24; + } + while (lst >= 24) + { + lst -= 24; + } + + return lst; + } + } +} diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index dbf6b21..9e74b40 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -81,6 +81,7 @@ + diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 11762d1..2829e4e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -98,6 +98,8 @@ namespace ASCOM.Meade.net /// private AstroUtils astroUtilities; + private AstroMaths astroMaths; + /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) /// @@ -117,7 +119,9 @@ namespace ASCOM.Meade.net connectedState = false; // Initialise connected to false utilities = new Util(); //Initialise util object astroUtilities = new AstroUtils(); // Initialise astro utilities object + //TODO: Implement your additional construction here + astroMaths = new AstroMaths(); tl.LogMessage("Telescope", "Completed initialisation"); } @@ -403,21 +407,45 @@ namespace ASCOM.Meade.net { get { - //todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! - var result = SharedResources.SendString(":GA#"); - //:GA# Get Telescope Altitude - //Returns: sDD* MM# or sDD*MM’SS# - //The current scope altitude. The returned format depending on the current precision setting. + var altAz = CalcAltAzFromTelescopeEqData(); + tl.LogMessage("Altitude", $"{altAz.Altitude}"); + return altAz.Altitude; - var alt = utilities.DMSToDegrees(result); - tl.LogMessage("Altitude", $"{alt}"); - return alt; + ////todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! + //var result = SharedResources.SendString(":GA#"); + ////:GA# Get Telescope Altitude + ////Returns: sDD* MM# or sDD*MM’SS# + ////The current scope altitude. The returned format depending on the current precision setting. + + //var alt = utilities.DMSToDegrees(result); + //tl.LogMessage("Altitude", $"{alt}"); + //return alt; //tl.LogMessage("Altitude Get", "Not implemented"); //throw new ASCOM.PropertyNotImplementedException("Altitude", false); } } + private HorizonCoordinates CalcAltAzFromTelescopeEqData() + { + var altitudeData = SharedResources.Lock(() => new AltitudeData + { + UtcDateTime = this.UTCDate, + SiteLongitude = this.SiteLongitude, + SiteLatitude = this.SiteLatitude, + equatorialCoordinates = new EquatorialCoordinates() + { + RightAscension = this.RightAscension, + Declination = this.Declination + } + }); + + double hourAngle = astroMaths.RightAscensionToHourAngle(altitudeData.UtcDateTime, altitudeData.SiteLongitude, + altitudeData.equatorialCoordinates.RightAscension); + var altAz = astroMaths.ConvertEqToHoz(hourAngle, altitudeData.SiteLatitude, altitudeData.equatorialCoordinates); + return altAz; + } + public double ApertureArea { get @@ -467,15 +495,19 @@ namespace ASCOM.Meade.net { get { - var result = SharedResources.SendString(":GZ#"); + //var result = SharedResources.SendString(":GZ#"); //:GZ# Get telescope azimuth //Returns: DDD*MM#T or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. - double az = utilities.DMSToDegrees(result); + //double az = utilities.DMSToDegrees(result); - tl.LogMessage("Azimuth Get", $"{az}"); - return az; + //tl.LogMessage("Azimuth Get", $"{az}"); + //return az; + + var altAz = CalcAltAzFromTelescopeEqData(); + tl.LogMessage("Azimuth Get", $"{altAz.Azimuth}"); + return altAz.Azimuth; } } diff --git a/Meade.net.sln b/Meade.net.sln index 4ca39e2..1c77465 100644 --- a/Meade.net.sln +++ b/Meade.net.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.136 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.452 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meade.net", "Meade.net\Meade.net.csproj", "{3689A2CB-94C5-4012-A5CF-7E7D1DD27143}" EndProject @@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FocuserTestConsole", "Focus EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestConsoles", "TestConsoles", "{BF650D97-AF98-4638-9C55-21311C6D88DA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{0958D817-269C-44BE-BEFB-F3E6A409DE91}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AstroMath.UnitTests", "AstroMath.UnitTests\AstroMath.UnitTests.csproj", "{AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,6 +63,14 @@ Global {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|Any CPU.ActiveCfg = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.ActiveCfg = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.Build.0 = Release|x86 + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.Build.0 = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.Build.0 = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.ActiveCfg = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -66,6 +78,7 @@ Global GlobalSection(NestedProjects) = preSolution {D5207217-61C7-4E94-8097-91DBACE57D2A} = {BF650D97-AF98-4638-9C55-21311C6D88DA} {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49} = {BF650D97-AF98-4638-9C55-21311C6D88DA} + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95} = {0958D817-269C-44BE-BEFB-F3E6A409DE91} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3C0509DC-C7F5-48DC-920D-DCFD9C879BD2} diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 72b790c..a8de179 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -43,12 +43,12 @@ namespace ASCOM // TODO add more code to test the driver. device.Connected = true; - //Console.WriteLine($"Altitute {device.Altitude}"); - - //Console.WriteLine($"Dec {device.Declination}"); - - device.SlewToAltAz(30, 45); + Console.WriteLine($"Ra {device.RightAscension}"); + Console.WriteLine($"Dec {device.Declination}"); + Console.WriteLine($"Altitude {device.Altitude}"); + Console.WriteLine($"Azimuth {device.Azimuth}"); + device.Connected = false; Console.WriteLine("Press Enter to finish"); Console.ReadLine(); From d39846fa1878d66e9d2cfc084cf76c2d95e6f721 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 19 May 2019 00:59:21 +0100 Subject: [PATCH 042/109] Added code to make sure that the scope returns values in high precision mode. --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 3 -- Meade.net.Telescope/Telescope.cs | 35 +++++++++++++++++++--- TelescopeTestConsole/Program.cs | 7 +++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index f4792d3..392dd71 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -111,15 +111,12 @@ namespace AstroMath.UnitTests [Test] public void ConvertEqToHoz_book() { - DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); - var longitude = -1.7833333333333332; var latitude = 52.0; EquatorialCoordinates equatorialCoordinates = new EquatorialCoordinates(); equatorialCoordinates.RightAscension = 5.862222222222222;//5 51' 44" equatorialCoordinates.Declination = 23.21944444444444;//23 13' 10" - //var hourAngle = _astroMath.RightAscensionToHourAngle(dateTime, longitude, equatorialCoordinates.RightAscension); var hourAngle = 5.682222; var altAz = _astroMath.ConvertEqToHoz(hourAngle, latitude, equatorialCoordinates); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 2829e4e..d2e1ade 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -237,6 +237,7 @@ namespace ASCOM.Meade.net connectedState = true; SelectSite(1); + SetLongFormat(true); } else { @@ -247,6 +248,29 @@ namespace ASCOM.Meade.net } } + private void SetLongFormat(bool setLongFormat) + { + SharedResources.Lock(() => + { + var result = SharedResources.SendString(":GZ#"); + //:GZ# Get telescope azimuth + //Returns: DDD*MM#T or DDD*MM’SS# + //The current telescope Azimuth depending on the selected precision. + + bool isLongFormat = result.Length > 6; + + if (isLongFormat != setLongFormat) + { + utilities.WaitForMilliseconds(500); + SharedResources.SendBlind(":U#"); + //:U# Toggle between low/hi precision positions + //Low - RA displays and messages HH:MM.T sDD*MM + //High - Dec / Az / El displays and messages HH:MM: SS sDD*MM:SS + // Returns Nothing + } + }); + } + private void SelectSite(int site) { SharedResources.SendBlind($":W{site}#"); @@ -1173,9 +1197,10 @@ namespace ASCOM.Meade.net if (value < 0) throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + //todo this serial string does not work. Calculate the EQ version instead. - var dms = utilities.DegreesToDMS(value, "*", "'", ".", 2); - var s = value < 0 ? '-' : '+'; + var dms = utilities.DegreesToDMS(value, "*", "'", "",0); + var s = value < 0 ? "-" : "+"; var result = SharedResources.SendChar($":Sa{s}{dms}#"); //:SasDD*MM# @@ -1199,9 +1224,11 @@ namespace ASCOM.Meade.net if (value < 0) throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); - var dms = utilities.DegreesToDM(value, "*", ":", 2); + //todo this serial string does not work. Calculate the EQ version instead. - var result = SharedResources.SendChar($":Sd{dms}#"); + var dms = utilities.DegreesToDM(value, "*" ); + + var result = SharedResources.SendChar($":Sz{dms}#"); //:SzDDD*MM# //Sets the target Object Azimuth[LX 16” and Autostar II only] //Returns: diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index a8de179..5c626fa 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -43,8 +43,11 @@ namespace ASCOM // TODO add more code to test the driver. device.Connected = true; - Console.WriteLine($"Ra {device.RightAscension}"); - Console.WriteLine($"Dec {device.Declination}"); + device.CommandBlind(":Sa+30*00'00#", true); + device.CommandBlind(":Sz150*00#", true); + device.CommandBlind(":MS#", true); + //Console.WriteLine($"Ra {device.RightAscension}"); + //Console.WriteLine($"Dec {device.Declination}"); Console.WriteLine($"Altitude {device.Altitude}"); Console.WriteLine($"Azimuth {device.Azimuth}"); From 7cb50de30db7f65703ad9a5fc0f520d59b54d6d7 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 19 May 2019 19:25:43 +0100 Subject: [PATCH 043/109] Fixed problem where SlewToAltAz didn't work correctly. Now uses the RA/Dec slew for everything, and converts the values as needed. --- ASCOM.MeadeGeneric.Telescope.Validation.txt | 466 ++++++++++---------- ASCOM.MeadeGeneric.focuser.Validation.txt | 82 ++-- AstroMath.UnitTests/AstroMathsUnitTests.cs | 26 ++ Meade.net.Telescope/AstroMaths.cs | 49 +- Meade.net.Telescope/Telescope.cs | 35 +- TelescopeTestConsole/Program.cs | 9 +- 6 files changed, 384 insertions(+), 283 deletions(-) diff --git a/ASCOM.MeadeGeneric.Telescope.Validation.txt b/ASCOM.MeadeGeneric.Telescope.Validation.txt index 79c7484..19ba7a7 100644 --- a/ASCOM.MeadeGeneric.Telescope.Validation.txt +++ b/ASCOM.MeadeGeneric.Telescope.Validation.txt @@ -1,4 +1,4 @@ -Conform Report Hash (V1): E0EA1442C34B74A8386CB4D1755D11EA73FC54E7F9DC5CB5084F74C896E4979F909360686B70F44E734318AA35CB91C39347C5F65C93A03D420358D99DFCF5CE +Conform Report Hash (V1): EE943505837FAD1E4F4998D567C304701AB845611D748A5A9517BF10842F951F5DD946834D8E59B5E7B84C7C067D24F52AC1C4F7E4A879A7CDAF4AB7BFEF8BB4 ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 @@ -14,256 +14,256 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -23:59:11.344 Driver Access Checks OK -23:59:11.990 AccessChecks OK Successfully created driver using late binding -23:59:12.222 AccessChecks OK Successfully connected using late binding -23:59:12.226 AccessChecks INFO The driver is a .NET object -23:59:12.231 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Telescope, ASCOM.Meade.net.Telescope, Version=0.4.0.0, Cultu -23:59:12.235 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 -23:59:12.936 AccessChecks INFO Device does not expose interface ITelescopeV2 -23:59:13.747 AccessChecks INFO Device exposes interface ITelescopeV3 -23:59:15.062 AccessChecks OK Successfully created driver using driver access toolkit -23:59:15.233 AccessChecks OK Successfully connected using driver access toolkit +19:18:57.428 Driver Access Checks OK +19:18:58.079 AccessChecks OK Successfully created driver using late binding +19:18:58.893 AccessChecks OK Successfully connected using late binding +19:18:58.898 AccessChecks INFO The driver is a .NET object +19:18:58.903 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Telescope, ASCOM.Meade.net.Telescope, Version=0.4.0.0, Cultu +19:18:58.907 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ITelescopeV3 +19:18:59.617 AccessChecks INFO Device does not expose interface ITelescopeV2 +19:19:00.617 AccessChecks INFO Device exposes interface ITelescopeV3 +19:19:01.929 AccessChecks OK Successfully created driver using driver access toolkit +19:19:02.635 AccessChecks OK Successfully connected using driver access toolkit Conform is using ASCOM.DriverAccess.Telescope to get a Telescope object -23:59:16.556 ConformanceCheck OK Driver instance created successfully -23:59:16.766 ConformanceCheck OK Connected OK +19:19:03.962 ConformanceCheck OK Driver instance created successfully +19:19:04.542 ConformanceCheck OK Connected OK Common Driver Methods -23:59:16.808 InterfaceVersion OK 3 -23:59:16.837 Connected OK True -23:59:16.865 Description OK Meade Generic -23:59:16.894 DriverInfo OK Information about the driver itself. Version: 0.4 -23:59:16.923 DriverVersion OK 0.4 -23:59:16.952 Name OK Meade Generic -23:59:16.981 CommandString INFO Conform cannot test the CommandString method -23:59:16.987 CommandBlind INFO Conform cannot test the CommandBlind method -23:59:16.994 CommandBool INFO Conform cannot test the CommandBool method -23:59:17.001 Action INFO Conform cannot test the Action method -23:59:17.009 SupportedActions OK Driver returned an empty action list +19:19:04.582 InterfaceVersion OK 3 +19:19:04.611 Connected OK True +19:19:04.640 Description OK Meade Generic +19:19:04.668 DriverInfo OK Information about the driver itself. Version: 0.4 +19:19:04.696 DriverVersion OK 0.4 +19:19:04.724 Name OK Meade Generic +19:19:04.753 CommandString INFO Conform cannot test the CommandString method +19:19:04.758 CommandBlind INFO Conform cannot test the CommandBlind method +19:19:04.765 CommandBool INFO Conform cannot test the CommandBool method +19:19:04.771 Action INFO Conform cannot test the Action method +19:19:04.778 SupportedActions OK Driver returned an empty action list Can Properties -23:59:17.077 CanFindHome OK False -23:59:17.086 CanPark OK True -23:59:17.094 CanPulseGuide OK True -23:59:17.103 CanSetDeclinationRate OK False -23:59:17.111 CanSetGuideRates OK False -23:59:17.119 CanSetPark OK False -23:59:17.128 CanSetPierSide OK False -23:59:17.139 CanSetRightAscensionRate OK False -23:59:17.147 CanSetTracking OK True -23:59:17.156 CanSlew OK True -23:59:17.161 CanSlewltAz OK True -23:59:17.172 CanSlewAltAzAsync OK True -23:59:17.182 CanSlewAsync OK True -23:59:17.191 CanSync OK True -23:59:17.201 CanSyncAltAz OK False -23:59:17.210 CanUnPark OK False +19:19:04.843 CanFindHome OK False +19:19:04.850 CanPark OK True +19:19:04.858 CanPulseGuide OK True +19:19:04.866 CanSetDeclinationRate OK False +19:19:04.874 CanSetGuideRates OK False +19:19:04.881 CanSetPark OK False +19:19:04.889 CanSetPierSide OK False +19:19:04.923 CanSetRightAscensionRate OK False +19:19:04.932 CanSetTracking OK True +19:19:04.939 CanSlew OK True +19:19:04.947 CanSlewltAz OK True +19:19:04.954 CanSlewAltAzAsync OK True +19:19:04.962 CanSlewAsync OK True +19:19:04.971 CanSync OK True +19:19:04.979 CanSyncAltAz OK False +19:19:04.990 CanUnPark OK False Pre-run Checks -23:59:17.257 Mount Safety INFO Scope is not parked, continuing testing -23:59:17.288 Mount Safety INFO Scope tracking has been enabled -23:59:17.319 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. -23:59:17.327 TimeCheck INFO PC UTCDate: 17-May-2019 22:59:17.327 -23:59:17.449 TimeCheck INFO Mount UTCDate: 17-May-2019 22:59:16.000 +19:19:05.040 Mount Safety INFO Scope is not parked, continuing testing +19:19:05.070 Mount Safety INFO Scope tracking has been enabled +19:19:05.100 TimeCheck INFO PC Time Zone: GMT Summer Time, offset -1 hours. +19:19:05.108 TimeCheck INFO PC UTCDate: 19-May-2019 18:19:05.108 +19:19:05.604 TimeCheck INFO Mount UTCDate: 19-May-2019 18:18:16.000 Properties -23:59:17.513 AlignmentMode OK algPolar -23:59:17.564 Altitude OK 88.71 -23:59:17.602 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. -23:59:17.635 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. -23:59:17.667 AtHome OK False -23:59:17.699 AtPark OK False -23:59:17.746 Azimuth OK 0.00 -23:59:17.802 Declination OK 88:42:41.00 -23:59:17.834 DeclinationRate Read OK 0.00 -23:59:17.867 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected -23:59:17.902 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:17.935 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:17.968 EquatorialSystem OK equLocalTopocentric -23:59:18.002 FocalLength OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.043 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.054 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -23:59:18.087 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.099 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected -23:59:18.132 IsPulseGuiding OK False -23:59:18.179 RightAscension OK 14:41:52.00 -23:59:18.213 RightAscensionRate Read OK 0.00 -23:59:18.247 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected -23:59:18.281 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.316 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.327 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.338 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.394 SiteLatitude Read OK 53:48:00.00 -23:59:18.432 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees -23:59:18.444 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees -23:59:18.477 SiteLatitude Write OK Legal value 53:48:00.00 degrees written successfully -23:59:18.535 SiteLongitude Read OK -01:47:00.00 -23:59:18.570 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees -23:59:18.583 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees -23:59:18.621 SiteLongitude Write OK Legal value -01:47:00.00 degrees written successfully -23:59:18.667 Slewing OK False -23:59:18.704 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.739 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.752 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.786 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. -23:59:18.834 SiderealTime OK 14:33:34.37 -23:59:18.847 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 14:33:34.37, ASCOM: 14:33:35.47 -23:59:18.882 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write -23:59:18.917 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -23:59:18.929 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write -23:59:18.964 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. -23:59:18.976 Tracking Read OK True -23:59:20.035 Tracking Write OK False -23:59:21.100 TrackingRates Found drive rate: driveSidereal -23:59:21.112 TrackingRates Found drive rate: driveLunar -23:59:21.124 TrackingRates OK Drive rates read OK -23:59:21.139 TrackingRates OK Disposed tracking rates OK -23:59:21.174 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed -23:59:21.184 TrackingRate Read OK driveSidereal -23:59:21.223 TrackingRate Write OK Successfully set drive rate: driveSidereal -23:59:21.258 TrackingRate Write OK Successfully set drive rate: driveLunar -23:59:21.338 UTCDate Read OK 17-May-2019 22:59:20.000 -23:59:21.554 UTCDate Write OK New UTCDate written successfully: 17/05/2019 23:59:20 +19:19:05.689 AlignmentMode OK algPolar +19:19:06.820 Altitude OK 50.09 +19:19:06.854 ApertureArea OK Optional member threw a PropertyNotImplementedException exception. +19:19:06.886 ApertureDiameter OK Optional member threw a PropertyNotImplementedException exception. +19:19:06.920 AtHome OK False +19:19:06.952 AtPark OK False +19:19:07.636 Azimuth OK 150.49 +19:19:07.938 Declination OK 16:49:00.00 +19:19:07.971 DeclinationRate Read OK 0.00 +19:19:08.003 DeclinationRate Write OK CanSetDeclinationRate is False and a PropertyNotImplementedException exception was generated as expected +19:19:08.037 DoesRefraction Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.071 DoesRefraction Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.104 EquatorialSystem OK equLocalTopocentric +19:19:08.136 FocalLength OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.169 GuideRateDeclination Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.179 GuideRateDeclination Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +19:19:08.212 GuideRateRightAscension Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.223 GuideRateRightAscension Write OK CanSetGuideRates is False and a PropertyNotImplementedException exception was generated as expected +19:19:08.257 IsPulseGuiding OK False +19:19:08.539 RightAscension OK 11:16:48.00 +19:19:08.572 RightAscensionRate Read OK 0.00 +19:19:08.605 RightAscensionRate Write OK CanSetRightAscensionRate is False and a PropertyNotImplementedException exception was generated as expected +19:19:08.639 SiteElevation Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.675 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.687 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.698 SiteElevation Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:08.758 SiteLatitude Read OK 53:48:00.00 +19:19:08.793 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude < -90 degrees +19:19:08.808 SiteLatitude Write OK Invalid Value exception generated as expected on set site latitude > 90 degrees +19:19:08.973 SiteLatitude Write OK Legal value 53:48:00.00 degrees written successfully +19:19:09.052 SiteLongitude Read OK -01:47:00.00 +19:19:09.088 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude < -180 degrees +19:19:09.100 SiteLongitude Write OK Invalid Value exception generated as expected on set site longitude > 180 degrees +19:19:09.267 SiteLongitude Write OK Legal value -01:47:00.00 degrees written successfully +19:19:09.326 Slewing OK False +19:19:09.361 SlewSettleTime Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:09.400 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:09.413 SlewSettleTime Write OK Optional member threw a PropertyNotImplementedException exception. +19:19:09.447 SideOfPier Read OK Optional member threw a PropertyNotImplementedException exception. +19:19:09.493 SiderealTime OK 10:00:32.13 +19:19:09.505 SiderealTime OK Scope and ASCOM sidereal times agree to better than 2 seconds, Scope: 10:00:32.13, ASCOM: 10:00:33.22 +19:19:09.540 TargetDeclination Read OK .NET Not InvalidOperationException generated on read before write +19:19:09.575 TargetDeclination Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +19:19:09.588 TargetRightAscension Read OK .NET Not InvalidOperationException generated on read before write +19:19:09.623 TargetRightAscension Write INFO Tests moved after the SlewToCoordinates tests so that Conform can check they properly set target coordinates. +19:19:09.635 Tracking Read OK True +19:19:10.697 Tracking Write OK False +19:19:11.759 TrackingRates Found drive rate: driveSidereal +19:19:11.772 TrackingRates Found drive rate: driveLunar +19:19:11.784 TrackingRates OK Drive rates read OK +19:19:11.797 TrackingRates OK Disposed tracking rates OK +19:19:11.832 TrackingRates OK Successfully obtained a TrackingRates object after the previous TrackingRates object was disposed +19:19:11.858 TrackingRate Read OK driveSidereal +19:19:11.893 TrackingRate Write OK Successfully set drive rate: driveSidereal +19:19:11.928 TrackingRate Write OK Successfully set drive rate: driveLunar +19:19:12.073 UTCDate Read OK 19-May-2019 18:18:23.000 +19:19:13.628 UTCDate Write OK New UTCDate written successfully: 19/05/2019 19:18:23 Methods -23:59:21.831 CanMoveAxis:Primary OK CanMoveAxis:Primary True -23:59:21.868 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True -23:59:21.904 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False -23:59:21.940 Park/Unpark INFO Tests skipped -23:59:21.958 AbortSlew OK AbortSlew OK when not slewing -23:59:22.020 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 -23:59:22.037 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 -23:59:22.050 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 -23:59:22.062 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 -23:59:22.075 AxisRate:Primary OK No overlapping axis rates found -23:59:22.091 AxisRate:Primary OK No duplicate axis rates found -23:59:22.109 AxisRate:Primary OK Successfully disposed of rate 1 - 1 -23:59:22.122 AxisRate:Primary OK Successfully disposed of rate 2 - 2 -23:59:22.135 AxisRate:Primary OK Successfully disposed of rate 3 - 3 -23:59:22.147 AxisRate:Primary OK Successfully disposed of rate 4 - 4 -23:59:22.160 AxisRate:Primary OK Disposed axis rates OK -23:59:22.173 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 -23:59:22.185 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 -23:59:22.197 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 -23:59:22.209 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 -23:59:22.222 AxisRate:Secondary OK No overlapping axis rates found -23:59:22.234 AxisRate:Secondary OK No duplicate axis rates found -23:59:22.246 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 -23:59:22.258 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 -23:59:22.271 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 -23:59:22.283 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 -23:59:22.297 AxisRate:Secondary OK Disposed axis rates OK -23:59:22.311 AxisRate:Tertiary OK Empty axis rate returned -23:59:22.325 AxisRate:Tertiary OK Disposed axis rates OK -23:59:22.341 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected -23:59:22.386 MoveAxis Primary OK Can successfully set a movement rate of zero -23:59:22.405 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) -23:59:22.442 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) -23:59:26.654 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 -23:59:30.860 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 -23:59:35.034 MoveAxis Primary OK Tracking state correctly retained for both tracking states -23:59:35.050 MoveAxis Primary OK AxisRates object successfully disposed -23:59:35.110 MoveAxis Secondary OK Can successfully set a movement rate of zero -23:59:35.125 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) -23:59:35.164 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) -23:59:39.333 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 -23:59:43.535 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 -23:59:47.752 MoveAxis Secondary OK Tracking state correctly retained for both tracking states -23:59:47.770 MoveAxis Secondary OK AxisRates object successfully disposed -23:59:47.828 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected -23:59:49.867 PulseGuide OK Synchronous pulse guide found OK -00:00:19.740 SlewToCoordinates INFO Slewed within 23.9 arc seconds of expected RA: 13:34:05.59, actual RA: 13:34:04.00 -00:00:19.753 SlewToCoordinates OK Slewed OK. DEC: 01:00:00.00 -00:00:19.766 SlewToCoordinates OK The TargetRightAscension property 13:34:05.59 matches the expected RA OK. -00:00:19.782 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. -00:00:19.829 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -00:00:19.944 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -00:00:20.006 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -00:00:20.074 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -00:00:38.898 SlewToCoordinatesAsync INFO Slewed within 58.1 arc seconds of expected RA: 12:34:35.88, actual RA: 12:34:32.00 -00:00:38.914 SlewToCoordinatesAsync OK Slewed OK. DEC: 02:00:00.00 -00:00:38.927 SlewToCoordinatesAsync OK The TargetRightAscension property 12:34:35.88 matches the expected RA OK. -00:00:38.940 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. -00:00:38.979 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -00:00:39.077 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -00:00:39.137 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -00:00:39.205 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -00:01:00.519 SyncToCoordinates INFO Slewed to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 -00:01:00.532 SyncToCoordinates OK Slewed to start position OK. DEC: 26:54:00.00 -00:01:01.420 SyncToCoordinates INFO Synced to sync position within 3553.2 arc seconds of expected RA: 11:30:55.12, actual RA: 11:34:52.00 -00:01:01.434 SyncToCoordinates INFO Synced to sync position within 3597.0 arc seconds of expected DEC: 25:54:00.00, actual DEC: 26:53:57.00 -00:01:01.447 SyncToCoordinates OK The TargetRightAscension property 11:30:55.12 matches the expected RA OK. -00:01:01.461 SyncToCoordinates OK The TargetDeclination property 25:54:00.00 matches the expected Declination OK. -00:01:17.464 SyncToCoordinates INFO Slewed back to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 -00:01:17.481 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 -00:01:18.320 SyncToCoordinates INFO Synced to reversed sync position within 3646.8 arc seconds of expected RA: 11:38:55.12, actual RA: 11:34:52.00 -00:01:18.334 SyncToCoordinates INFO Synced to reversed sync position within 3603.0 arc seconds of expected DEC: 27:54:00.00, actual DEC: 26:53:57.00 -00:01:34.081 SyncToCoordinates INFO Slewed back to start position within 46.8 arc seconds of expected RA: 11:34:55.12, actual RA: 11:34:52.00 -00:01:34.095 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 -00:01:34.134 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 -00:01:34.238 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 -00:01:34.299 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 -00:01:34.373 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 -00:01:34.431 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours -00:01:34.450 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours -00:01:34.557 TargetRightAscension Write OK Legal value 10:35:50.41 HH:MM:SS written successfully -00:01:34.593 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -00:01:34.607 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees -00:01:34.659 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully -00:01:53.415 SlewToTarget INFO Slewed within 39.7 arc seconds of expected RA: 11:35:50.64, actual RA: 11:35:48.00 -00:01:53.430 SlewToTarget OK Slewed OK. DEC: 03:00:00.00 -00:01:53.444 SlewToTarget OK The TargetRightAscension property 11:35:50.64 matches the expected RA OK. -00:01:53.458 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. -00:01:53.499 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -00:01:53.590 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -00:01:53.651 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -00:01:53.698 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -00:02:12.772 SlewToTargetAsync INFO Slewed within 26.4 arc seconds of expected RA: 10:36:09.76, actual RA: 10:36:08.00 -00:02:12.789 SlewToTargetAsync OK Slewed OK. DEC: 04:00:00.00 -00:02:12.804 SlewToTargetAsync OK The TargetRightAscension property 10:36:09.76 matches the expected RA OK. -00:02:12.819 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. -00:02:12.859 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -00:02:12.896 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -00:02:12.972 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -00:02:13.070 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -00:02:13.133 DestinationSideOfPier Test skipped as AligmentMode is not German Polar -00:02:13.371 SlewToAltAz INFO Slewed to within 87:49:32.00 DD:MM:SS of expected Azimuth: 150:00:00.00 -00:02:13.387 SlewToAltAz INFO Slewed to within 46:00:03.00 DD:MM:SS of expected Altitude: 50:00:00.00 -00:02:13.430 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -00:02:13.473 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -00:02:13.538 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -00:02:13.575 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -00:02:18.862 SlewToAltAzAsync INFO Slewed to within 92:48:04.00 DD:MM:SS of expected Azimuth: 155:00:00.00 -00:02:18.876 SlewToAltAzAsync INFO Slewed to within 51:00:02.00 DD:MM:SS of expected Altitude: 55:00:00.00 -00:02:18.917 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 -00:02:18.960 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 -00:02:19.024 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 -00:02:19.064 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 -00:02:40.297 SyncToTarget INFO Slewed to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 -00:02:40.311 SyncToTarget OK Slewed to start position OK. DEC: 26:54:00.00 -00:02:41.176 SyncToTarget INFO Synced to sync position within 3551.4 arc seconds of expected RA: 11:32:35.24, actual RA: 11:36:32.00 -00:02:41.192 SyncToTarget INFO Synced to sync position within 3598.0 arc seconds of expected DEC: 25:54:00.00, actual DEC: 26:53:58.00 -00:02:57.142 SyncToTarget INFO Slewed back to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 -00:02:57.156 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 -00:02:57.998 SyncToTarget INFO Synced to reversed sync position within 3648.6 arc seconds of expected RA: 11:40:35.24, actual RA: 11:36:32.00 -00:02:58.012 SyncToTarget INFO Synced to reversed sync position within 3603.0 arc seconds of expected DEC: 27:54:00.00, actual DEC: 26:53:57.00 -00:03:14.149 SyncToTarget INFO Slewed back to start position within 48.6 arc seconds of expected RA: 11:36:35.24, actual RA: 11:36:32.00 -00:03:14.164 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 -00:03:14.203 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 -00:03:14.256 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 -00:03:14.330 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 -00:03:14.370 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 -00:03:14.574 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected +19:19:15.180 CanMoveAxis:Primary OK CanMoveAxis:Primary True +19:19:15.218 CanMoveAxis:Secondary OK CanMoveAxis:Secondary True +19:19:15.255 CanMoveAxis:Tertiary OK CanMoveAxis:Tertiary False +19:19:15.292 Park/Unpark INFO Tests skipped +19:19:15.311 AbortSlew OK AbortSlew OK when not slewing +19:19:15.376 AxisRate:Primary OK Axis rate minimum: 1 Axis rate maximum: 1 +19:19:15.390 AxisRate:Primary OK Axis rate minimum: 2 Axis rate maximum: 2 +19:19:15.404 AxisRate:Primary OK Axis rate minimum: 3 Axis rate maximum: 3 +19:19:15.417 AxisRate:Primary OK Axis rate minimum: 4 Axis rate maximum: 4 +19:19:15.430 AxisRate:Primary OK No overlapping axis rates found +19:19:15.442 AxisRate:Primary OK No duplicate axis rates found +19:19:15.454 AxisRate:Primary OK Successfully disposed of rate 1 - 1 +19:19:15.468 AxisRate:Primary OK Successfully disposed of rate 2 - 2 +19:19:15.480 AxisRate:Primary OK Successfully disposed of rate 3 - 3 +19:19:15.492 AxisRate:Primary OK Successfully disposed of rate 4 - 4 +19:19:15.505 AxisRate:Primary OK Disposed axis rates OK +19:19:15.518 AxisRate:Secondary OK Axis rate minimum: 1 Axis rate maximum: 1 +19:19:15.533 AxisRate:Secondary OK Axis rate minimum: 2 Axis rate maximum: 2 +19:19:15.546 AxisRate:Secondary OK Axis rate minimum: 3 Axis rate maximum: 3 +19:19:15.559 AxisRate:Secondary OK Axis rate minimum: 4 Axis rate maximum: 4 +19:19:15.571 AxisRate:Secondary OK No overlapping axis rates found +19:19:15.585 AxisRate:Secondary OK No duplicate axis rates found +19:19:15.599 AxisRate:Secondary OK Successfully disposed of rate 1 - 1 +19:19:15.612 AxisRate:Secondary OK Successfully disposed of rate 2 - 2 +19:19:15.625 AxisRate:Secondary OK Successfully disposed of rate 3 - 3 +19:19:15.638 AxisRate:Secondary OK Successfully disposed of rate 4 - 4 +19:19:15.652 AxisRate:Secondary OK Disposed axis rates OK +19:19:15.667 AxisRate:Tertiary OK Empty axis rate returned +19:19:15.680 AxisRate:Tertiary OK Disposed axis rates OK +19:19:15.697 FindHome OK CanFindHome is False and a MethodNotImplementedException exception was generated as expected +19:19:15.745 MoveAxis Primary OK Can successfully set a movement rate of zero +19:19:15.761 MoveAxis Primary OK Exception correctly generated when move axis is set below lowest rate (0.5) +19:19:15.800 MoveAxis Primary OK Exception correctly generated when move axis is set above highest rate (5) +19:19:19.972 MoveAxis Primary OK Successfully moved axis at minimum rate: 1 +19:19:24.750 MoveAxis Primary OK Successfully moved axis at maximum rate: 4 +19:19:28.925 MoveAxis Primary OK Tracking state correctly retained for both tracking states +19:19:28.941 MoveAxis Primary OK AxisRates object successfully disposed +19:19:29.002 MoveAxis Secondary OK Can successfully set a movement rate of zero +19:19:29.018 MoveAxis Secondary OK Exception correctly generated when move axis is set below lowest rate (0.5) +19:19:29.055 MoveAxis Secondary OK Exception correctly generated when move axis is set above highest rate (5) +19:19:33.266 MoveAxis Secondary OK Successfully moved axis at minimum rate: 1 +19:19:38.191 MoveAxis Secondary OK Successfully moved axis at maximum rate: 4 +19:19:42.366 MoveAxis Secondary OK Tracking state correctly retained for both tracking states +19:19:42.384 MoveAxis Secondary OK AxisRates object successfully disposed +19:19:42.447 MoveAxis Tertiary OK CanMoveAxis Tertiary is False and a MethodNotImplementedException exception was generated as expected +19:19:44.487 PulseGuide OK Synchronous pulse guide found OK +19:20:06.507 SlewToCoordinates INFO Slewed within 175.3 arc seconds of expected RA: 09:01:07.31, actual RA: 09:01:19.00 +19:20:06.522 SlewToCoordinates INFO Slewed within 82.0 arc seconds of expected DEC: 01:00:00.00, actual DEC: 01:01:22.00 +19:20:06.537 SlewToCoordinates OK The TargetRightAscension property 09:01:07.31 matches the expected RA OK. +19:20:06.550 SlewToCoordinates OK The TargetDeclination property 01:00:00.00 matches the expected Declination OK. +19:20:06.591 SlewToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +19:20:06.856 SlewToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +19:20:06.920 SlewToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +19:20:07.224 SlewToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +19:20:25.860 SlewToCoordinatesAsync INFO Slewed within 178.3 arc seconds of expected RA: 08:01:30.11, actual RA: 08:01:42.00 +19:20:25.876 SlewToCoordinatesAsync INFO Slewed within 64.0 arc seconds of expected DEC: 02:00:00.00, actual DEC: 01:58:56.00 +19:20:25.890 SlewToCoordinatesAsync OK The TargetRightAscension property 08:01:30.11 matches the expected RA OK. +19:20:25.904 SlewToCoordinatesAsync OK The TargetDeclination property 02:00:00.00 matches the expected Declination OK. +19:20:25.945 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +19:20:26.201 SlewToCoordinatesAsync (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +19:20:26.263 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +19:20:26.567 SlewToCoordinatesAsync (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +19:20:47.987 SyncToCoordinates INFO Slewed to start position within 25.3 arc seconds of expected RA: 07:01:49.69, actual RA: 07:01:48.00 +19:20:48.003 SyncToCoordinates OK Slewed to start position OK. DEC: 26:54:00.00 +19:20:49.265 SyncToCoordinates INFO Synced to sync position within 25.3 arc seconds of expected RA: 06:57:49.69, actual RA: 06:57:48.00 +19:20:49.282 SyncToCoordinates OK Synced to sync position OK. DEC: 25:54:00.00 +19:20:49.301 SyncToCoordinates OK The TargetRightAscension property 06:57:49.69 matches the expected RA OK. +19:20:49.316 SyncToCoordinates OK The TargetDeclination property 25:54:00.00 matches the expected Declination OK. +19:21:05.202 SyncToCoordinates INFO Slewed back to start position within 25.3 arc seconds of expected RA: 07:01:49.69, actual RA: 07:01:48.00 +19:21:05.217 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 +19:21:06.337 SyncToCoordinates INFO Synced to reversed sync position within 40.3 arc seconds of expected RA: 07:05:49.69, actual RA: 07:05:47.00 +19:21:06.353 SyncToCoordinates OK Synced to reversed sync position OK. DEC: 27:54:00.00 +19:21:22.444 SyncToCoordinates INFO Slewed back to start position within 25.3 arc seconds of expected RA: 07:01:49.69, actual RA: 07:01:48.00 +19:21:22.459 SyncToCoordinates OK Slewed back to start position OK. DEC: 26:54:00.00 +19:21:22.502 SyncToCoordinates (Bad L) OK Correctly rejected bad RA coordinate: -01:00:00.00 +19:21:22.620 SyncToCoordinates (Bad L) OK Correctly rejected bad Dec coordinate: -100:00:00.00 +19:21:22.682 SyncToCoordinates (Bad H) OK Correctly rejected bad RA coordinate: 25:00:00.00 +19:21:23.379 SyncToCoordinates (Bad H) OK Correctly rejected bad Dec coordinate: 100:00:00.00 +19:21:23.439 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension < 0 hours +19:21:23.454 TargetRightAscension Write OK Invalid Value exception generated as expected on set TargetRightAscension > 24 hours +19:21:23.670 TargetRightAscension Write OK Legal value 06:02:46.50 HH:MM:SS written successfully +19:21:23.709 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +19:21:23.724 TargetDeclination Write OK Invalid Value exception generated as expected on set TargetDeclination < -90 degrees +19:21:23.918 TargetDeclination Write OK Legal value 01:00:00.00 DD:MM:SS written successfully +19:21:44.377 SlewToTarget INFO Slewed within 44.9 arc seconds of expected RA: 07:02:46.99, actual RA: 07:02:44.00 +19:21:44.392 SlewToTarget OK Slewed OK. DEC: 03:00:00.00 +19:21:44.421 SlewToTarget OK The TargetRightAscension property 07:02:46.99 matches the expected RA OK. +19:21:44.435 SlewToTarget OK The TargetDeclination property 03:00:00.00 matches the expected Declination OK. +19:21:44.476 SlewToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +19:21:44.565 SlewToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +19:21:44.627 SlewToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +19:21:44.713 SlewToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +19:22:05.987 SlewToTargetAsync INFO Slewed within 58.0 arc seconds of expected RA: 06:03:07.87, actual RA: 06:03:04.00 +19:22:06.002 SlewToTargetAsync OK Slewed OK. DEC: 04:00:00.00 +19:22:06.016 SlewToTargetAsync OK The TargetRightAscension property 06:03:07.87 matches the expected RA OK. +19:22:06.030 SlewToTargetAsync OK The TargetDeclination property 04:00:00.00 matches the expected Declination OK. +19:22:06.071 SlewToTargetAsync (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +19:22:06.134 SlewToTargetAsync (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +19:22:06.200 SlewToTargetAsync (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +19:22:06.281 SlewToTargetAsync (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +19:22:06.341 DestinationSideOfPier Test skipped as AligmentMode is not German Polar +19:22:36.522 SlewToAltAz INFO Slewed to within 00:11:23.03 DD:MM:SS of expected Azimuth: 150:00:00.00 +19:22:36.539 SlewToAltAz INFO Slewed to within 00:02:05.06 DD:MM:SS of expected Altitude: 50:00:00.00 +19:22:36.581 SlewToAltAz (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +19:22:36.599 SlewToAltAz (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +19:22:36.662 SlewToAltAz (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +19:22:36.681 SlewToAltAz (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +19:22:57.713 SlewToAltAzAsync INFO Slewed to within 00:09:16.99 DD:MM:SS of expected Azimuth: 155:00:00.00 +19:22:57.728 SlewToAltAzAsync INFO Slewed to within 00:00:28.11 DD:MM:SS of expected Altitude: 55:00:00.00 +19:22:57.770 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Altitude coordinate: -100:00:00.00 +19:22:57.789 SlewToAltAzAsync (Bad L) OK Correctly rejected bad Azimuth coordinate: -10:00:00.00 +19:22:57.851 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Altitude coordinate: 100:00:00.00 +19:22:57.870 SlewToAltAzAsync (Bad H) OK Correctly rejected bad Azimuth coordinate: 370:00:00.00 +19:23:22.572 SyncToTarget OK Slewed to start position OK. RA: 07:04:21.38 +19:23:22.588 SyncToTarget OK Slewed to start position OK. DEC: 26:54:00.00 +19:23:24.332 SyncToTarget INFO Synced to sync position within 20.7 arc seconds of expected RA: 07:00:21.38, actual RA: 07:00:20.00 +19:23:24.347 SyncToTarget OK Synced to sync position OK. DEC: 25:54:00.00 +19:23:42.234 SyncToTarget INFO Slewed back to start position within 20.7 arc seconds of expected RA: 07:04:21.38, actual RA: 07:04:20.00 +19:23:42.250 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 +19:23:43.530 SyncToTarget INFO Synced to reversed sync position within 35.7 arc seconds of expected RA: 07:08:21.38, actual RA: 07:08:19.00 +19:23:43.546 SyncToTarget OK Synced to reversed sync position OK. DEC: 27:54:00.00 +19:23:59.445 SyncToTarget INFO Slewed back to start position within 20.7 arc seconds of expected RA: 07:04:21.38, actual RA: 07:04:20.00 +19:23:59.460 SyncToTarget OK Slewed back to start position OK. DEC: 26:54:00.00 +19:23:59.500 SyncToTarget (Bad L) OK Telescope.TargetRA correctly rejected bad RA coordinate: -01:00:00.00 +19:23:59.656 SyncToTarget (Bad L) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: -100:00:00.00 +19:23:59.716 SyncToTarget (Bad H) OK Telescope.TargetRA correctly rejected bad RA coordinate: 25:00:00.00 +19:23:59.997 SyncToTarget (Bad H) OK Telescope.TargetDeclination correctly rejected bad Dec coordinate: 100:00:00.00 +19:24:02.242 SyncToAltAz OK CanSyncAltAz is False and a MethodNotImplementedException exception was generated as expected SideOfPier Model Tests -00:03:14.635 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read +19:24:02.320 SideOfPier Model Tests INFO Tests skipped because this driver does Not support SideOfPier Read Post-run Checks -00:03:14.732 Mount Safety OK Tracking stopped to protect your mount. +19:24:02.417 Mount Safety OK Tracking stopped to protect your mount. Conformance test complete No errors, warnings or issues found: your driver passes ASCOM validation!! -Driver Hash Value: 88EE4EE52A4E10A920380EE086D799AFBE0C2BB4807C2DF0FB2287C6FD57128D1D7C20ABB38632BA09DE6E55E6194CB75C087939AAFF5A38ED0235858618BFE3 +Driver Hash Value: D41F95CA4DB76F4C2F9742455087821EB82915774F9D97EDF4DAB66B4D74932295DC665B8B90C3FC94AB1B5FA5BAC8009D715FF21C0620CB5F40D8DACFAE67D6 diff --git a/ASCOM.MeadeGeneric.focuser.Validation.txt b/ASCOM.MeadeGeneric.focuser.Validation.txt index 94a4712..8942c01 100644 --- a/ASCOM.MeadeGeneric.focuser.Validation.txt +++ b/ASCOM.MeadeGeneric.focuser.Validation.txt @@ -1,4 +1,4 @@ -Conform Report Hash (V1): BCDD202E20EC71628DFE60620D4E1F9A119F72953DCC4F8107039D0C9872C4A2B2EC2A759AF57819C2A53FA56A4643B552778C53924B743D9C049027AC09FD20 +Conform Report Hash (V1): B869A2DCAA7DACEB47895197B4418080943EDDCC3D1A49E9DDE97B9B22DF8F7B83DC95D595972C4345F53236103CE33045056F1A6BB068B32F72C080377A2FC1 ConformanceCheck ASCOM Device Conformance Checker Version 6.4.63.0, Build time: 18/12/2018 08:58:32 @@ -14,57 +14,55 @@ Error number for "Value Not Set 1" is: 80040402 Error number for "Value Not Set 2" is: 80040403 Error messages will not be interpreted to infer state. -00:05:33.087 Driver Access Checks OK -00:05:33.758 AccessChecks OK Successfully created driver using late binding -00:05:33.983 AccessChecks OK Successfully connected using late binding -00:05:33.987 AccessChecks INFO The driver is a .NET object -00:05:33.991 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Focuser, ASCOM.Meade.net.Focuser, Version=0.4.0.0, Culture=n -00:05:33.996 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 -00:05:34.640 AccessChecks INFO Device does not expose IFocuser interface -00:05:34.700 AccessChecks INFO Device does not expose IFocuserV2 interface -00:05:34.951 AccessChecks INFO Device exposes IFocuserV3 interface -00:05:35.069 AccessChecks OK Successfully created driver using driver access toolkit -00:05:35.263 AccessChecks OK Successfully connected using driver access toolkit -00:05:35.324 AccessChecks OK Successfully disconnected using driver access toolkit +19:18:30.690 Driver Access Checks OK +19:18:31.351 AccessChecks OK Successfully created driver using late binding +19:18:31.676 AccessChecks OK Successfully connected using late binding +19:18:31.682 AccessChecks INFO The driver is a .NET object +19:18:31.687 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.Meade.net.Focuser, ASCOM.Meade.net.Focuser, Version=0.4.0.0, Culture=n +19:18:31.692 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.IFocuserV3 +19:18:32.341 AccessChecks INFO Device does not expose IFocuser interface +19:18:32.405 AccessChecks INFO Device does not expose IFocuserV2 interface +19:18:32.675 AccessChecks INFO Device exposes IFocuserV3 interface +19:18:32.793 AccessChecks OK Successfully created driver using driver access toolkit +19:18:32.967 AccessChecks OK Successfully connected using driver access toolkit +19:18:33.031 AccessChecks OK Successfully disconnected using driver access toolkit Conform is using ASCOM.DriverAccess.Focuser to get a Focuser object -00:05:35.394 ConformanceCheck OK Driver instance created successfully -00:05:35.608 ConformanceCheck OK Connected OK +19:18:33.103 ConformanceCheck OK Driver instance created successfully +19:18:33.621 ConformanceCheck OK Connected OK Common Driver Methods -00:05:35.647 InterfaceVersion OK 3 -00:05:35.676 Connected OK True -00:05:35.704 Description OK Meade Generic -00:05:35.736 DriverInfo OK Information about the driver itself. Version: 0.4 -00:05:35.765 DriverVersion OK 0.4 -00:05:35.794 Name OK Meade Generic -00:05:35.823 CommandString INFO Conform cannot test the CommandString method -00:05:35.829 CommandBlind INFO Conform cannot test the CommandBlind method -00:05:35.836 CommandBool INFO Conform cannot test the CommandBool method -00:05:35.842 Action INFO Conform cannot test the Action method -00:05:35.850 SupportedActions OK Driver returned an empty action list +19:18:33.661 InterfaceVersion OK 3 +19:18:33.691 Connected OK True +19:18:33.719 Description OK Meade Generic +19:18:33.749 DriverInfo OK Information about the driver itself. Version: 0.4 +19:18:33.778 DriverVersion OK 0.4 +19:18:33.807 Name OK Meade Generic +19:18:33.836 CommandXXX INFO Tests skipped +19:18:33.842 Action INFO Conform cannot test the Action method +19:18:33.850 SupportedActions OK Driver returned an empty action list Properties -00:05:35.961 Absolute OK False -00:05:35.968 IsMoving OK False -00:05:35.976 MaxStep OK 7000 -00:05:35.983 MaxIncrement OK 7000 -00:05:35.992 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected -00:05:36.000 StepSize OK Optional member threw a PropertyNotImplementedException exception. -00:05:36.008 TempCompAvailable OK False -00:05:36.016 TempComp Read OK False -00:05:36.024 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected -00:05:36.032 Temperature OK Optional member threw a PropertyNotImplementedException exception. +19:18:33.962 Absolute OK False +19:18:33.970 IsMoving OK False +19:18:33.977 MaxStep OK 7000 +19:18:33.985 MaxIncrement OK 7000 +19:18:33.994 Position OK Position must not be implemented for a relative focuser and a PropertyNotImplementedException exception was generated as expected +19:18:34.003 StepSize OK Optional member threw a PropertyNotImplementedException exception. +19:18:34.011 TempCompAvailable OK False +19:18:34.019 TempComp Read OK False +19:18:34.027 TempComp Write OK Temperature compensation is not available and a PropertyNotImplementedException exception was generated as expected +19:18:34.036 Temperature OK Optional member threw a PropertyNotImplementedException exception. Methods -00:05:36.080 Halt OK Focuser halted OK -00:05:36.092 Move - TempComp False Moving by: 700 -00:05:36.804 Move - TempComp False Asynchronous move found -00:05:36.812 Move - TempComp False OK Relative move OK -00:05:36.822 Move - TempComp False INFO Returning to original position: 0 +19:18:34.085 Halt OK Focuser halted OK +19:18:34.096 Move - TempComp False Moving by: 700 +19:18:34.808 Move - TempComp False Asynchronous move found +19:18:34.818 Move - TempComp False OK Relative move OK +19:18:34.830 Move - TempComp False INFO Returning to original position: 0 Conformance test complete No errors, warnings or issues found: your driver passes ASCOM validation!! -Driver Hash Value: A3C2D8D9708D2B157CF8BFC2F83BFE3666DA07AA75C592BD3969D42E0566A2F69E06BBE7C33BA78914D292EF3529B65AA22052AC34D13F6B521127072ACF366F +Driver Hash Value: 1816E24C06CF16B84021B2B07D4629C3E46DCC5E738D9BACBD524BE5A969BCB07AB3704AB754BC5AA54F5A76F77721D6F7D756AC16DC0AC7DACDC9EA900FA3C8 diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index 392dd71..cdbe4ad 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -142,5 +142,31 @@ namespace AstroMath.UnitTests Assert.That(altaz.Azimuth, Is.EqualTo(333.2819484462679)); } + //[Test] + //public void ConvertHozToEq_book() + //{ + // HorizonCoordinates hc = new HorizonCoordinates(); + // hc.Altitude = 19.33434444; + // hc.Azimuth = 283.271028; + // var lat = 52; + // var raDec = _astroMath.ConvertHozToEq(lat, hc); + + // Assert.That(raDec.RightAscension, Is.EqualTo(5.8622222973512992)); + // Assert.That(raDec.Declination, Is.EqualTo(23.219444300552407)); + //} + + + //[Test] + //public void ConvertHozToEq() + //{ + // HorizonCoordinates hc = new HorizonCoordinates(); + // hc.Altitude = 50; + // hc.Azimuth = 150; + // var lat = 53.5; + // var raDec = _astroMath.ConvertHozToEq(lat, hc); + + // Assert.That(raDec.RightAscension, Is.EqualTo(22.69408899548845)); + // Assert.That(raDec.Declination, Is.EqualTo(16.539114529888948)); + //} } } diff --git a/Meade.net.Telescope/AstroMaths.cs b/Meade.net.Telescope/AstroMaths.cs index d9d224e..7123eaa 100644 --- a/Meade.net.Telescope/AstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths.cs @@ -43,6 +43,53 @@ namespace ASCOM.Meade.net return h; } + public double HourAngleToRightAscension(DateTime utcDateTime, double longitude, double hourAngle ) + { + var gst = UTtoGST(utcDateTime); + var lst = GSTtoLST( gst, longitude); + var raHours = hourAngle; + var h1 = lst - raHours; + var h = h1; + if (h1 < 0) + { + h += 24; + } + + return h; + } + + public EquatorialCoordinates ConvertHozToEq( DateTime utcDateTime, double latitude, double longitude, HorizonCoordinates altAz) + { + var az = DegreesToRadians(altAz.Azimuth); + var alt = DegreesToRadians(altAz.Altitude); + var lat = DegreesToRadians(latitude); + + var sinDec = Math.Sin(alt) * Math.Sin(lat) + Math.Cos(alt) * Math.Cos(lat) * Math.Cos(az); + var dec = RadiansToDegrees(Math.Asin(sinDec)); + + var y = -Math.Cos(alt) * Math.Cos(lat) * Math.Sin(az); + var x = Math.Sin(alt) - Math.Sin(lat) * sinDec; + var upperA = Math.Atan2(y,x); + var upperB = RadiansToDegrees(upperA); + + var ha = upperB; + + if (upperB < 0) + { + ha += 360; + } + + ha = ha / 15; + + EquatorialCoordinates equatorialCoordinates = new EquatorialCoordinates + { + RightAscension = HourAngleToRightAscension( utcDateTime, longitude, ha ), + Declination = dec + }; + + return equatorialCoordinates; + } + public HorizonCoordinates ConvertEqToHoz(double hourAngle, double latitude, EquatorialCoordinates raDec) { var h = hourAngle * 15; @@ -51,7 +98,7 @@ namespace ASCOM.Meade.net var lat = DegreesToRadians(latitude); var sinA = Math.Sin(d) * Math.Sin(lat) + Math.Cos(d) * Math.Cos(lat) * Math.Cos(h1); - var y = -Math.Cos(d) * Math.Cos(lat) * Math.Sin(h1); + var y = -Math.Cos(d) * Math.Cos(lat) * Math.Sin(h1); var x = Math.Sin(d) - Math.Sin(lat) * sinA; var upperA = Math.Atan2(y, x); var upperB = RadiansToDegrees(upperA); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index d2e1ade..de61521 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1243,14 +1243,41 @@ namespace ASCOM.Meade.net public void SlewToAltAzAsync(double azimuth, double altitude) { - tl.LogMessage("SlewToAltAzAsync", $"Az=~{azimuth} Alt={altitude}"); + if (altitude > 90) + throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); + + if (altitude < 0) + throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + + if (azimuth >= 360) + throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); + + if (azimuth < 0) + throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + + tl.LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); + + HorizonCoordinates altAz = new HorizonCoordinates(); + altAz.Azimuth = azimuth; + altAz.Altitude = altitude; + + var utcDateTime = UTCDate; + var latitude = SiteLatitude; + var longitude = SiteLongitude; SharedResources.Lock(() => { - TargetAltitude = altitude; - TargetAzimuth = azimuth; + var raDec = astroMaths.ConvertHozToEq(utcDateTime, latitude, longitude, altAz); - DoSlewAsync(false); + TargetRightAscension = raDec.RightAscension; + TargetDeclination = raDec.Declination; + + DoSlewAsync(true); + + //TargetAltitude = altitude; + //TargetAzimuth = azimuth; + + //DoSlewAsync(false); }); } diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 5c626fa..420046a 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -43,9 +43,12 @@ namespace ASCOM // TODO add more code to test the driver. device.Connected = true; - device.CommandBlind(":Sa+30*00'00#", true); - device.CommandBlind(":Sz150*00#", true); - device.CommandBlind(":MS#", true); + + device.SlewToAltAz(150, 50); + + //device.CommandBlind(":Sa+30*00'00#", true); + //device.CommandBlind(":Sz50*00#", true); + //device.CommandBlind(":MA#", true); //Console.WriteLine($"Ra {device.RightAscension}"); //Console.WriteLine($"Dec {device.Declination}"); From 678b5f1eced84b5dc3aa61d1fd428f92e246e25f Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 20 May 2019 17:06:53 +0100 Subject: [PATCH 044/109] Upgraded the error handling to ensure that all serial commands are executed after checking that there is a connection open. --- Meade.net.Telescope/Telescope.cs | 103 ++++++++++++++++++++++++++----- Meade.net.focuser/Focuser.cs | 8 ++- Meade.net/SharedResources.cs | 56 ++++++++--------- 3 files changed, 121 insertions(+), 46 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index de61521..275329a 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -86,7 +86,7 @@ namespace ASCOM.Meade.net /// /// Private variable to hold the connected state /// - private bool connectedState; + private bool _connectedState; /// /// Private variable to hold an ASCOM Utilities object @@ -98,7 +98,7 @@ namespace ASCOM.Meade.net /// private AstroUtils astroUtilities; - private AstroMaths astroMaths; + private readonly AstroMaths _astroMaths; /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) @@ -111,17 +111,17 @@ namespace ASCOM.Meade.net /// public Telescope() { - tl = new TraceLogger("", "Meade.net"); + tl = new TraceLogger("", "Meade.net.Telescope"); ReadProfile(); // Read device configuration from the ASCOM Profile store tl.LogMessage("Telescope", "Starting initialisation"); - connectedState = false; // Initialise connected to false + _connectedState = false; // Initialise connected to false utilities = new Util(); //Initialise util object astroUtilities = new AstroUtils(); // Initialise astro utilities object //TODO: Implement your additional construction here - astroMaths = new AstroMaths(); + _astroMaths = new AstroMaths(); tl.LogMessage("Telescope", "Completed initialisation"); } @@ -141,8 +141,10 @@ namespace ASCOM.Meade.net /// public void SetupDialog() { + tl.LogMessage("SetupDialog", "Opening setup dialog"); SharedResources.SetupDialog(); ReadProfile(); + tl.LogMessage("SetupDialog", "complete"); //// consider only showing the setup dialog if not connected //// or call a different dialog if connected //if (IsConnected) @@ -233,17 +235,32 @@ namespace ASCOM.Meade.net if (value) { LogMessage("Connected Set", "Connecting to port {0}", comPort); - SharedResources.Connect("Serial"); - connectedState = true; + try + { + SharedResources.Connect("Serial"); + try + { + SelectSite(1); + SetLongFormat(true); - SelectSite(1); - SetLongFormat(true); + _connectedState = true; + } + catch (Exception) + { + SharedResources.Disconnect("Serial"); + throw; + } + } + catch (Exception ex) + { + LogMessage("Connected Set", "Error connecting to port {0} - {1}", comPort, ex.Message); + } } else { LogMessage("Connected Set", "Disconnecting from port {0}", comPort); SharedResources.Disconnect("Serial"); - connectedState = false; + _connectedState = false; } } } @@ -352,6 +369,8 @@ namespace ASCOM.Meade.net public void AbortSlew() { + CheckConnected("AbortSlew"); + tl.LogMessage("AbortSlew", "Aborting slew"); SharedResources.SendBlind(":Q#"); //:Q# Halt all current slewing @@ -364,6 +383,8 @@ namespace ASCOM.Meade.net { tl.LogMessage("AlignmentMode Get", "Getting alignmode"); + CheckConnected("AlignmentMode Get"); + const char ack = (char) 6; var alignmentString = SharedResources.SendChar(ack.ToString()); @@ -405,6 +426,8 @@ namespace ASCOM.Meade.net } set { + CheckConnected("AlignmentMode Set"); + switch (value) { case AlignmentModes.algAltAz: @@ -431,6 +454,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("Altitude get"); + var altAz = CalcAltAzFromTelescopeEqData(); tl.LogMessage("Altitude", $"{altAz.Altitude}"); return altAz.Altitude; @@ -464,9 +489,9 @@ namespace ASCOM.Meade.net } }); - double hourAngle = astroMaths.RightAscensionToHourAngle(altitudeData.UtcDateTime, altitudeData.SiteLongitude, + double hourAngle = _astroMaths.RightAscensionToHourAngle(altitudeData.UtcDateTime, altitudeData.SiteLongitude, altitudeData.equatorialCoordinates.RightAscension); - var altAz = astroMaths.ConvertEqToHoz(hourAngle, altitudeData.SiteLatitude, altitudeData.equatorialCoordinates); + var altAz = _astroMaths.ConvertEqToHoz(hourAngle, altitudeData.SiteLatitude, altitudeData.equatorialCoordinates); return altAz; } @@ -519,6 +544,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("Azimuth get"); + //var result = SharedResources.SendString(":GZ#"); //:GZ# Get telescope azimuth //Returns: DDD*MM#T or DDD*MM’SS# @@ -695,6 +722,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("Declination Get"); + var result = SharedResources.SendString(":GD#"); //:GD# Get Telescope Declination. //Returns: sDD* MM# or sDD*MM’SS# @@ -811,6 +840,7 @@ namespace ASCOM.Meade.net public void MoveAxis(TelescopeAxes axis, double rate) { tl.LogMessage("MoveAxis", $"Axis={axis} rate={rate}"); + CheckConnected("MoveAxis"); var absRate = Math.Abs(rate); @@ -907,6 +937,7 @@ namespace ASCOM.Meade.net public void Park() { tl.LogMessage("Park", "Parking telescope"); + CheckConnected("Park"); if (AtPark) return; @@ -923,6 +954,8 @@ namespace ASCOM.Meade.net public void PulseGuide(GuideDirections direction, int duration) { tl.LogMessage("PulseGuide", $"pulse guide direction {direction} duration {duration}"); + CheckConnected("PulseGuide"); + string d = string.Empty; switch (direction) { @@ -988,6 +1021,7 @@ namespace ASCOM.Meade.net { get { + CheckConnected("RightAscension Get"); var result = SharedResources.SendString(":GR#"); //:GR# Get Telescope RA //Returns: HH: MM.T# or HH:MM:SS# @@ -1079,6 +1113,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("SiteLatitude Get"); + var latitude = SharedResources.SendString(":Gt#"); //:Gt# Get Current Site Latitude //Returns: sDD* MM# @@ -1092,6 +1128,8 @@ namespace ASCOM.Meade.net { tl.LogMessage("SiteLatitude Set", $"{utilities.DegreesToDMS(value)}"); + CheckConnected("SiteLatitude Set"); + if (value > 90) throw new InvalidValueException("Latitude cannot be greater than 90 degrees."); @@ -1117,6 +1155,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("SiteLongitude Get"); + var longitude = SharedResources.SendString(":Gg#"); //:Gg# Get Current Site Longitude //Returns: sDDD* MM# @@ -1136,6 +1176,9 @@ namespace ASCOM.Meade.net var newLongitude = value; tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(newLongitude)}"); + + CheckConnected("SiteLongitude Set"); + if (newLongitude > 180) throw new InvalidValueException("Longitude cannot be greater than 180 degrees."); @@ -1178,6 +1221,7 @@ namespace ASCOM.Meade.net public void SlewToAltAz(double azimuth, double altitude) { tl.LogMessage("SlewToAltAz", $"Az=~{azimuth} Alt={altitude}"); + CheckConnected("SlewToAltAz"); SlewToAltAzAsync(azimuth, altitude); @@ -1197,6 +1241,8 @@ namespace ASCOM.Meade.net if (value < 0) throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + CheckConnected("TargetAltitude Set"); + //todo this serial string does not work. Calculate the EQ version instead. var dms = utilities.DegreesToDMS(value, "*", "'", "",0); @@ -1224,6 +1270,8 @@ namespace ASCOM.Meade.net if (value < 0) throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + CheckConnected("TargetAzimuth Set"); + //todo this serial string does not work. Calculate the EQ version instead. var dms = utilities.DegreesToDM(value, "*" ); @@ -1256,6 +1304,7 @@ namespace ASCOM.Meade.net throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); tl.LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); + CheckConnected("SlewToAltAzAsync"); HorizonCoordinates altAz = new HorizonCoordinates(); altAz.Azimuth = azimuth; @@ -1267,7 +1316,7 @@ namespace ASCOM.Meade.net SharedResources.Lock(() => { - var raDec = astroMaths.ConvertHozToEq(utcDateTime, latitude, longitude, altAz); + var raDec = _astroMaths.ConvertHozToEq(utcDateTime, latitude, longitude, altAz); TargetRightAscension = raDec.RightAscension; TargetDeclination = raDec.Declination; @@ -1283,6 +1332,8 @@ namespace ASCOM.Meade.net private void DoSlewAsync(bool polar) { + CheckConnected("DoSlewAsync"); + SharedResources.Lock(() => { switch (polar) @@ -1335,6 +1386,8 @@ namespace ASCOM.Meade.net public void SlewToCoordinates(double rightAscension, double declination) { tl.LogMessage("SlewToCoordinates", $"Ra={rightAscension}, Dec={declination}"); + CheckConnected("SlewToCoordinates"); + SlewToCoordinatesAsync(rightAscension, declination); while (Slewing) //wait for slew to complete @@ -1346,6 +1399,7 @@ namespace ASCOM.Meade.net public void SlewToCoordinatesAsync(double rightAscension, double declination) { tl.LogMessage("SlewToCoordinatesAsync", $"Ra={rightAscension}, Dec={declination}"); + CheckConnected("SlewToCoordinatesAsync"); SharedResources.Lock(() => { @@ -1360,6 +1414,7 @@ namespace ASCOM.Meade.net public void SlewToTarget() { tl.LogMessage("SlewToTarget", "Executing"); + CheckConnected("SlewToTarget"); SlewToTargetAsync(); while (Slewing) @@ -1372,6 +1427,8 @@ namespace ASCOM.Meade.net public void SlewToTargetAsync() { + CheckConnected("SlewToTargetAsync"); + if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER) throw new ASCOM.InvalidOperationException("No target selected to slew to."); @@ -1393,6 +1450,8 @@ namespace ASCOM.Meade.net if (movingAxis()) return true; + CheckConnected("Slewing Get"); + var result = SharedResources.SendString(":D#"); //:D# Requests a string of bars indicating the distance to the current target location. //Returns: @@ -1414,6 +1473,7 @@ namespace ASCOM.Meade.net public void SyncToCoordinates(double rightAscension, double declination) { tl.LogMessage("SyncToCoordinates", $"RA={rightAscension} Dec={declination}"); + CheckConnected("SyncToCoordinates"); SharedResources.Lock(() => { @@ -1427,6 +1487,8 @@ namespace ASCOM.Meade.net public void SyncToTarget() { tl.LogMessage("SyncToTarget", "Executing"); + CheckConnected("SyncToTarget"); + var result = SharedResources.SendString(":CM#"); //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. //Returns: @@ -1460,7 +1522,7 @@ namespace ASCOM.Meade.net set { tl.LogMessage("TargetDeclination Set", $"{value}"); - + //todo implement low precision version of this. if (value > 90) throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); @@ -1468,6 +1530,7 @@ namespace ASCOM.Meade.net if (value < -90) throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); + CheckConnected("TargetDeclination Set"); var dms = utilities.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? '-' : '+'; @@ -1517,7 +1580,7 @@ namespace ASCOM.Meade.net if (value >= 24) throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); - + CheckConnected("TargetRightAscension Set"); //todo implement the low precision version var hms = utilities.HoursToHMS(value, ":", ":", ":", 2); @@ -1552,6 +1615,7 @@ namespace ASCOM.Meade.net } private DriveRates _trackingRate = DriveRates.driveSidereal; + public DriveRates TrackingRate { get @@ -1574,6 +1638,7 @@ namespace ASCOM.Meade.net set { tl.LogMessage("TrackingRate Set", $"{value}"); + CheckConnected("TrackingRate Set"); switch (value) { @@ -1620,6 +1685,8 @@ namespace ASCOM.Meade.net private TimeSpan GetUtcCorrection() { + CheckConnected("GetUtcCorrection"); + string utcOffSet = SharedResources.SendString(":GG#"); //:GG# Get UTC offset time //Returns: sHH# or sHH.H# @@ -1641,6 +1708,8 @@ namespace ASCOM.Meade.net { get { + CheckConnected("UTCDate Get"); + tl.LogMessage("UTCDate", "Get started"); TelescopeDateDetails telescopeDateDetails = SharedResources.Lock(() => @@ -1683,6 +1752,8 @@ namespace ASCOM.Meade.net { tl.LogMessage("UTCDate", "Set - " + value.ToString("MM/dd/yy HH:mm:ss")); + CheckConnected("UTCDate Set"); + SharedResources.Lock(() => { var utcCorrection = GetUtcCorrection(); @@ -1812,7 +1883,7 @@ namespace ASCOM.Meade.net get { // TODO check that the driver hardware connection exists and is connected to the hardware - return connectedState; + return _connectedState; } } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index aa50a5a..81d3aec 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -109,7 +109,7 @@ namespace ASCOM.Meade.net /// public Focuser() { - tl = new TraceLogger("", "Meade.net"); + tl = new TraceLogger("", "Meade.net.focusser"); ReadProfile(); // Read device configuration from the ASCOM Profile store tl.LogMessage("Focuser", "Starting initialisation"); @@ -136,8 +136,10 @@ namespace ASCOM.Meade.net /// public void SetupDialog() { + tl.LogMessage("SetupDialog", "Opening setup dialog"); SharedResources.SetupDialog(); ReadProfile(); + tl.LogMessage("SetupDialog", "complete"); } public ArrayList SupportedActions @@ -297,6 +299,9 @@ namespace ASCOM.Meade.net public void Halt() { tl.LogMessage("Halt", "Halting"); + + CheckConnected("Halt"); + SharedResources.SendBlind(":FQ#"); //:FQ# Halt Focuser Motion //Returns: Nothing @@ -348,6 +353,7 @@ namespace ASCOM.Meade.net public void Move(int Position) { tl.LogMessage("Move", Position.ToString()); + CheckConnected("Move"); //todo implement backlash compensation //todo implement direction reverse diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 342e56c..e7c8fa0 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -42,8 +42,7 @@ namespace ASCOM.Meade.net private static readonly object lockObject = new object(); // Shared serial port. This will allow multiple drivers to use one single serial port. - private static ASCOM.Utilities.Serial s_sharedSerial = new ASCOM.Utilities.Serial(); // Shared serial port - private static int s_z = 0; // counter for the number of connections to the serial port + private static ASCOM.Utilities.Serial s_sharedSerial; // Shared serial port // // Public access to shared resources @@ -68,19 +67,12 @@ namespace ASCOM.Meade.net /// /// Shared serial port /// - public static ASCOM.Utilities.Serial SharedSerial - { - get { return s_sharedSerial; } - } + public static ASCOM.Utilities.Serial SharedSerial => s_sharedSerial ?? (s_sharedSerial = new ASCOM.Utilities.Serial()); /// /// number of connections to the shared serial port /// - public static int connections - { - get { return s_z; } - set { s_z = value; } - } + public static int Connections { get; set; } = 0; public static void SendBlind(string message) { @@ -149,14 +141,14 @@ namespace ASCOM.Meade.net { if (value) { - if (s_z == 0) + if (Connections == 0) SharedSerial.Connected = true; - s_z++; + Connections++; } else { - s_z--; - if (s_z <= 0) + Connections--; + if (Connections <= 0) { SharedSerial.Connected = false; } @@ -178,11 +170,14 @@ namespace ASCOM.Meade.net public static void WriteProfile(ProfileProperties profileProperties) { - using (Profile driverProfile = new Profile()) + lock (lockObject) { - driverProfile.DeviceType = "Telescope"; - driverProfile.WriteValue(driverID, traceStateProfileName, profileProperties.TraceLogger.ToString()); - driverProfile.WriteValue(driverID, comPortProfileName, profileProperties.ComPort); + using (Profile driverProfile = new Profile()) + { + driverProfile.DeviceType = "Telescope"; + driverProfile.WriteValue(driverID, traceStateProfileName, profileProperties.TraceLogger.ToString()); + driverProfile.WriteValue(driverID, comPortProfileName, profileProperties.ComPort); + } } } @@ -191,17 +186,20 @@ namespace ASCOM.Meade.net public static ProfileProperties ReadProfile() { - ProfileProperties profileProperties = new ProfileProperties(); - using (Profile driverProfile = new Profile()) + lock (lockObject) { - driverProfile.DeviceType = "Telescope"; - profileProperties.ComPort = - driverProfile.GetValue(driverID, comPortProfileName, string.Empty, comPortDefault); - profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(driverID, - traceStateProfileName, string.Empty, traceStateDefault)); - } + ProfileProperties profileProperties = new ProfileProperties(); + using (Profile driverProfile = new Profile()) + { + driverProfile.DeviceType = "Telescope"; + profileProperties.ComPort = + driverProfile.GetValue(driverID, comPortProfileName, string.Empty, comPortDefault); + profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(driverID, + traceStateProfileName, string.Empty, traceStateDefault)); + } - return profileProperties; + return profileProperties; + } } #endregion @@ -212,7 +210,7 @@ namespace ASCOM.Meade.net { // consider only showing the setup dialog if not connected // or call a different dialog if connected - if (SharedSerial.Connected) + if (Connections > 0) { System.Windows.Forms.MessageBox.Show("Already connected, please disconnect before altering settings"); return; From 546d0bf7f40c22d3c6240784197df9475e3886f0 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 20 May 2019 18:48:53 +0100 Subject: [PATCH 045/109] Added some code to the focuser connect to make it consistent with the telescope connect in that it will now test that the connection is to an Autostar. Upgraded the move code to make it less unreliable. --- Meade.net.focuser/Focuser.cs | 68 ++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 81d3aec..14e8b26 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -216,9 +216,26 @@ namespace ASCOM.Meade.net if (value) { - LogMessage("Connected Set", "Connecting to port {0}", comPort); - SharedResources.Connect("Serial"); - connectedState = true; + try + { + SharedResources.Connect("Serial"); + try + { + SelectSite(1); + SetLongFormat(true); + + connectedState = true; + } + catch (Exception) + { + SharedResources.Disconnect("Serial"); + throw; + } + } + catch (Exception ex) + { + LogMessage("Connected Set", "Error connecting to port {0} - {1}", comPort, ex.Message); + } } else { @@ -229,6 +246,37 @@ namespace ASCOM.Meade.net } } + private void SetLongFormat(bool setLongFormat) + { + SharedResources.Lock(() => + { + var result = SharedResources.SendString(":GZ#"); + //:GZ# Get telescope azimuth + //Returns: DDD*MM#T or DDD*MM’SS# + //The current telescope Azimuth depending on the selected precision. + + bool isLongFormat = result.Length > 6; + + if (isLongFormat != setLongFormat) + { + utilities.WaitForMilliseconds(500); + SharedResources.SendBlind(":U#"); + //:U# Toggle between low/hi precision positions + //Low - RA displays and messages HH:MM.T sDD*MM + //High - Dec / Az / El displays and messages HH:MM: SS sDD*MM:SS + // Returns Nothing + } + }); + } + + private void SelectSite(int site) + { + SharedResources.SendBlind($":W{site}#"); + //:W# + //Set current site to, an ASCII digit in the range 1..4 + //Returns: Nothing + } + public string Description { // TODO customise this device description @@ -383,6 +431,18 @@ namespace ASCOM.Meade.net { SharedResources.Lock(() => { + SharedResources.SendBlind(":FF#"); + //:FF# Set Focus speed to fastest setting + //Returns: Nothing + + //:FS# Set Focus speed to slowest setting + //Returns: Nothing + + //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 + //Returns: Nothing + //All others – Not Supported + utilities.WaitForMilliseconds(100); + SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#"); //:F+# Start Focuser moving inward (toward objective) //Returns: None @@ -393,6 +453,8 @@ namespace ASCOM.Meade.net utilities.WaitForMilliseconds(steps); Halt(); + + utilities.WaitForMilliseconds(1000); }); } From d328c3ae4d07f0db9a0d89356376590e96b8590e Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 20 May 2019 21:11:16 +0100 Subject: [PATCH 046/109] Added localisation support --- Meade.net/Localization/LocalisationHelper.cs | 36 ++++ Meade.net/Meade.net.csproj | 2 + Meade.net/SetupDialogForm.designer.cs | 45 +--- Meade.net/SetupDialogForm.resx | 204 +++++++++++++++++++ 4 files changed, 251 insertions(+), 36 deletions(-) create mode 100644 Meade.net/Localization/LocalisationHelper.cs diff --git a/Meade.net/Localization/LocalisationHelper.cs b/Meade.net/Localization/LocalisationHelper.cs new file mode 100644 index 0000000..a8ac3a7 --- /dev/null +++ b/Meade.net/Localization/LocalisationHelper.cs @@ -0,0 +1,36 @@ +using System.Globalization; +using System.Threading; +using System.Resources; +using System.Reflection; + +namespace ASCOM.Meade.net.Localization +{ + internal class LocalisationHelper + { + private const string LocalizationNamespace = "LocalisationTest.Localization.Resources.Localization"; + ResourceManager _resourceManager; + + public LocalisationHelper() + { + _resourceManager = new ResourceManager(LocalizationNamespace, Assembly.GetExecutingAssembly()); + + SetLocalisation(CultureInfo.CurrentCulture.Name); + } + + internal void SetLocalisation(string name) + { + var cultureInfo = new CultureInfo(name); + + CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + + Thread.CurrentThread.CurrentCulture = cultureInfo; + Thread.CurrentThread.CurrentUICulture = cultureInfo; + } + + internal string GetString(string key) + { + return _resourceManager.GetString(key); + } + } +} diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 18957ff..fa3e6a1 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -81,6 +81,7 @@ frmMain.cs + @@ -136,6 +137,7 @@ true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/AscomLocalServer.wxs b/Meade.net.Setup/AscomLocalServer.wxs new file mode 100644 index 0000000..ccfc9c4 --- /dev/null +++ b/Meade.net.Setup/AscomLocalServer.wxs @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/AscomTelescopeDriver.wxs b/Meade.net.Setup/AscomTelescopeDriver.wxs new file mode 100644 index 0000000..f2d561e --- /dev/null +++ b/Meade.net.Setup/AscomTelescopeDriver.wxs @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi new file mode 100644 index 0000000..5111470 --- /dev/null +++ b/Meade.net.Setup/Config.wxi @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/Directories.wxs b/Meade.net.Setup/Directories.wxs new file mode 100644 index 0000000..435128a --- /dev/null +++ b/Meade.net.Setup/Directories.wxs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/FeatureTree.wxs b/Meade.net.Setup/FeatureTree.wxs new file mode 100644 index 0000000..602f994 --- /dev/null +++ b/Meade.net.Setup/FeatureTree.wxs @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/InstallationUI.wxs b/Meade.net.Setup/InstallationUI.wxs new file mode 100644 index 0000000..a52ab86 --- /dev/null +++ b/Meade.net.Setup/InstallationUI.wxs @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + "1"]]> + + 1 + + NOT Installed + Installed AND PATCH + + 1 + LicenseAccepted = "1" + + 1 + 1 + NOT WIXUI_DONTVALIDATEPATH + "1"]]> + WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1" + 1 + 1 + + NOT Installed + Installed AND NOT PATCH + Installed AND PATCH + + 1 + + 1 + 1 + 1 + + + + + + + diff --git a/Meade.net.Setup/Meade.net.Setup.wixproj b/Meade.net.Setup/Meade.net.Setup.wixproj new file mode 100644 index 0000000..9f6c619 --- /dev/null +++ b/Meade.net.Setup/Meade.net.Setup.wixproj @@ -0,0 +1,91 @@ + + + + Debug + x86 + 3.10 + 8eeb5c25-8394-4257-8e57-cded47cb6f1b + 2.0 + Meade.net.Setup + Package + + + bin\$(Platform)\$(Configuration)\ + obj\$(Configuration)\ + Debug + + + bin\$(Configuration)\ + obj\$(Configuration)\ + + + Debug + bin\$(Configuration)\$(Platform)\ + obj\$(Platform)\$(Configuration)\ + + + bin\$(Platform)\$(Configuration)\ + obj\$(Platform)\$(Configuration)\ + + + + + + + + + + + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + + + + Meade.net.focuser + {a97e3aec-f11d-49da-b259-de99da813a86} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + Meade.net.Telescope + {64308775-bd4a-469c-bcab-3ed830b811af} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + Meade.net + {3689a2cb-94c5-4012-a5cf-7e7d1dd27143} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Setup/Product.wxs b/Meade.net.Setup/Product.wxs new file mode 100644 index 0000000..bd324d6 --- /dev/null +++ b/Meade.net.Setup/Product.wxs @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + ="#461308"]]> + + + + + + + + VersionNT64 + + NOT VersionNT64 + + + + + + + + + + diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 9e74b40..2a4e587 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -46,7 +46,7 @@ prompt 4 true - x86 + AnyCPU false diff --git a/Meade.net.Telescope/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs index e395e18..8e8df09 100644 --- a/Meade.net.Telescope/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.4.0.0")] -[assembly: AssemblyFileVersion("0.4.0.0")] +[assembly: AssemblyVersion("0.5.0.0")] +[assembly: AssemblyFileVersion("0.5.0.0")] diff --git a/Meade.net.focuser/Meade.net.focuser.csproj b/Meade.net.focuser/Meade.net.focuser.csproj index a082801..a033b82 100644 --- a/Meade.net.focuser/Meade.net.focuser.csproj +++ b/Meade.net.focuser/Meade.net.focuser.csproj @@ -46,7 +46,7 @@ prompt 4 true - x86 + AnyCPU false diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs index 0fce7a9..a02a8e6 100644 --- a/Meade.net.focuser/Properties/AssemblyInfo.cs +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.4.0.0")] -[assembly: AssemblyFileVersion("0.4.0.0")] +[assembly: AssemblyVersion("0.5.0.0")] +[assembly: AssemblyFileVersion("0.5.0.0")] diff --git a/Meade.net.sln b/Meade.net.sln index 1c77465..03f950d 100644 --- a/Meade.net.sln +++ b/Meade.net.sln @@ -19,58 +19,92 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AstroMath.UnitTests", "AstroMath.UnitTests\AstroMath.UnitTests.csproj", "{AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}" EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Meade.net.Setup", "Meade.net.Setup\Meade.net.Setup.wixproj", "{8EEB5C25-8394-4257-8E57-CDED47CB6F1B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x64.ActiveCfg = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x64.Build.0 = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.ActiveCfg = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.Build.0 = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.ActiveCfg = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.Build.0 = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x64.ActiveCfg = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x64.Build.0 = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.ActiveCfg = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.Build.0 = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x64.ActiveCfg = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x64.Build.0 = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x64.ActiveCfg = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x64.Build.0 = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x64.ActiveCfg = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x64.Build.0 = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.ActiveCfg = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.Build.0 = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.ActiveCfg = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.Build.0 = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x64.ActiveCfg = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x64.Build.0 = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.ActiveCfg = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.Build.0 = Release|Any CPU {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x64.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x64.ActiveCfg = Release|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.ActiveCfg = Release|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x64.ActiveCfg = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.ActiveCfg = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.Build.0 = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|Any CPU.ActiveCfg = Release|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x64.ActiveCfg = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.ActiveCfg = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|x86.Build.0 = Release|x86 {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x64.ActiveCfg = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x64.Build.0 = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.ActiveCfg = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.Build.0 = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.Build.0 = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x64.ActiveCfg = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x64.Build.0 = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.ActiveCfg = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.Build.0 = Release|Any CPU + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.ActiveCfg = Debug|x64 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.Build.0 = Debug|x64 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x64.ActiveCfg = Debug|x64 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x64.Build.0 = Debug|x64 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x86.ActiveCfg = Debug|x86 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x86.Build.0 = Debug|x86 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|Any CPU.ActiveCfg = Release|x86 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x64.ActiveCfg = Release|x86 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x86.ActiveCfg = Release|x86 + {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index fa3e6a1..6b8ed95 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -40,9 +40,9 @@ DEBUG;TRACE prompt 4 - x86 + AnyCPU MinimumRecommendedRules.ruleset - false + true pdbonly diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs index af3da5d..9570023 100644 --- a/Meade.net/Properties/AssemblyInfo.cs +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -21,7 +21,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.4.0.0")] -[assembly: AssemblyFileVersion("0.4.0.0")] +[assembly: AssemblyVersion("0.5.0.0")] +[assembly: AssemblyFileVersion("0.5.0.0")] [assembly: ComVisibleAttribute(false)] diff --git a/TelescopeTestConsole/TelescopeTestConsole.csproj b/TelescopeTestConsole/TelescopeTestConsole.csproj index deb5415..61210c5 100644 --- a/TelescopeTestConsole/TelescopeTestConsole.csproj +++ b/TelescopeTestConsole/TelescopeTestConsole.csproj @@ -16,7 +16,7 @@ 512 - x86 + AnyCPU true full false From 8da41cad6fa66153dce9384174363b626f5931d9 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 24 May 2019 00:07:29 +0100 Subject: [PATCH 048/109] Sorted out the registry settings needed to get the driver working properly on install. --- Meade.net.Setup/AscomFocuserDriver.wxs | 9 +++++---- Meade.net.Setup/AscomTelescopeDriver.wxs | 9 +++++---- Meade.net.Setup/Config.wxi | 2 +- Meade.net.Setup/FeatureTree.wxs | 1 + 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Meade.net.Setup/AscomFocuserDriver.wxs b/Meade.net.Setup/AscomFocuserDriver.wxs index a3db5e1..67ae64a 100644 --- a/Meade.net.Setup/AscomFocuserDriver.wxs +++ b/Meade.net.Setup/AscomFocuserDriver.wxs @@ -7,11 +7,7 @@ --> - - + + + + + diff --git a/Meade.net.Setup/AscomTelescopeDriver.wxs b/Meade.net.Setup/AscomTelescopeDriver.wxs index f2d561e..86379d8 100644 --- a/Meade.net.Setup/AscomTelescopeDriver.wxs +++ b/Meade.net.Setup/AscomTelescopeDriver.wxs @@ -7,11 +7,7 @@ --> - - + + + + + diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi index 5111470..782ac1a 100644 --- a/Meade.net.Setup/Config.wxi +++ b/Meade.net.Setup/Config.wxi @@ -19,7 +19,7 @@ - + diff --git a/Meade.net.Setup/FeatureTree.wxs b/Meade.net.Setup/FeatureTree.wxs index 602f994..245385e 100644 --- a/Meade.net.Setup/FeatureTree.wxs +++ b/Meade.net.Setup/FeatureTree.wxs @@ -6,6 +6,7 @@ + From 675ed08425e9d8b374f292fa3e2da3774385d1e6 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 25 May 2019 02:26:06 +0100 Subject: [PATCH 049/109] Modified the solution to be able to create as 32-bit install that works on 64bit windows 10. --- .../AstroMath.UnitTests.csproj | 18 ++++++++++++++++++ Meade.net.Setup/Config.wxi | 6 +++--- Meade.net.Setup/Product.wxs | 4 ++-- .../Meade.net.Telescope.csproj | 3 +++ Meade.net.focuser/Meade.net.focuser.csproj | 19 +++++++++++++++++++ Meade.net.sln | 16 ++++++++-------- Meade.net/Meade.net.csproj | 19 +++++++++++++++++++ 7 files changed, 72 insertions(+), 13 deletions(-) diff --git a/AstroMath.UnitTests/AstroMath.UnitTests.csproj b/AstroMath.UnitTests/AstroMath.UnitTests.csproj index 009b162..cf9d11f 100644 --- a/AstroMath.UnitTests/AstroMath.UnitTests.csproj +++ b/AstroMath.UnitTests/AstroMath.UnitTests.csproj @@ -34,6 +34,24 @@ prompt 4 + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi index 782ac1a..ec90b40 100644 --- a/Meade.net.Setup/Config.wxi +++ b/Meade.net.Setup/Config.wxi @@ -30,17 +30,17 @@ - + - + diff --git a/Meade.net.Setup/Product.wxs b/Meade.net.Setup/Product.wxs index bd324d6..73b314e 100644 --- a/Meade.net.Setup/Product.wxs +++ b/Meade.net.Setup/Product.wxs @@ -25,13 +25,13 @@ --> - + diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 2a4e587..3fa86d7 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -60,6 +60,9 @@ false false + + ..\bin\Release\ + diff --git a/Meade.net.focuser/Meade.net.focuser.csproj b/Meade.net.focuser/Meade.net.focuser.csproj index a033b82..a1fd243 100644 --- a/Meade.net.focuser/Meade.net.focuser.csproj +++ b/Meade.net.focuser/Meade.net.focuser.csproj @@ -60,6 +60,25 @@ false false + + true + bin\x86\Debug\ + DEBUG;TRACE + true + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + ..\bin\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + diff --git a/Meade.net.sln b/Meade.net.sln index 03f950d..d8f177e 100644 --- a/Meade.net.sln +++ b/Meade.net.sln @@ -41,8 +41,8 @@ Global {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.Build.0 = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x64.ActiveCfg = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x64.Build.0 = Release|Any CPU - {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.ActiveCfg = Release|Any CPU - {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.Build.0 = Release|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.ActiveCfg = Release|x86 + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x86.Build.0 = Release|x86 {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -53,8 +53,8 @@ Global {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x64.ActiveCfg = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x64.Build.0 = Release|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|x86 + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|x86 {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.Build.0 = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -65,8 +65,8 @@ Global {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.Build.0 = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x64.ActiveCfg = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x64.Build.0 = Release|Any CPU - {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.ActiveCfg = Release|Any CPU - {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.Build.0 = Release|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.ActiveCfg = Release|x86 + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.Build.0 = Release|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x64.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 @@ -93,8 +93,8 @@ Global {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.Build.0 = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x64.ActiveCfg = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x64.Build.0 = Release|Any CPU - {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.ActiveCfg = Release|Any CPU - {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.Build.0 = Release|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.ActiveCfg = Release|x86 + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x86.Build.0 = Release|x86 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.ActiveCfg = Debug|x64 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.Build.0 = Debug|x64 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 6b8ed95..6be15b8 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -63,6 +63,25 @@ ASCOM.ico + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + ..\bin\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + From 5501e97b7e6c3a7f63f5a2978d8892f102253595 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 4 Jun 2019 19:52:44 +0100 Subject: [PATCH 050/109] Added a call to activate when the setup dialog is shown. --- Meade.net/SetupDialogForm.cs | 5 +++++ Meade.net/SetupDialogForm.designer.cs | 1 + Meade.net/SharedResources.cs | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Meade.net/SetupDialogForm.cs b/Meade.net/SetupDialogForm.cs index 79b1816..2a1dac3 100644 --- a/Meade.net/SetupDialogForm.cs +++ b/Meade.net/SetupDialogForm.cs @@ -63,5 +63,10 @@ namespace ASCOM.Meade.net return profileProperties; } + + private void SetupDialogForm_Shown(object sender, EventArgs e) + { + Activate(); + } } } \ No newline at end of file diff --git a/Meade.net/SetupDialogForm.designer.cs b/Meade.net/SetupDialogForm.designer.cs index 0c80d7c..11f868f 100644 --- a/Meade.net/SetupDialogForm.designer.cs +++ b/Meade.net/SetupDialogForm.designer.cs @@ -102,6 +102,7 @@ namespace ASCOM.Meade.net this.MinimizeBox = false; this.Name = "SetupDialogForm"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.Shown += new System.EventHandler(this.SetupDialogForm_Shown); ((System.ComponentModel.ISupportInitialize)(this.picASCOM)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index e7c8fa0..733506b 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -221,7 +221,7 @@ namespace ASCOM.Meade.net using (SetupDialogForm F = new SetupDialogForm()) { F.SetProfile(profileProperties); - + var result = F.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { From 22de5679b7864dbb41ada12ef4df09c327064fbb Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 8 Jun 2019 20:13:36 +0100 Subject: [PATCH 051/109] Downgraded required .net to v4.0. Added suppoer for "Handbox" custom action Changes how the focuser in and out functions. Now sends multiple :F+/-# and multiple stop commands to help get over problems with the #909 missing commands. Added support for checking for the older firmware that does not support the guiding commands, so uses guide rate slew instead. --- .../AstroMath.UnitTests.csproj | 2 +- .../Properties/AssemblyInfo.cs | 4 +- FocuserTestConsole/FocuserTestConsole.csproj | 4 +- FocuserTestConsole/Properties/AssemblyInfo.cs | 4 +- FocuserTestConsole/app.config | 2 +- Meade.net.Setup/Config.wxi | 2 +- Meade.net.Setup/Product.wxs | 5 +- .../Meade.net.Telescope.csproj | 8 +- .../Properties/AssemblyInfo.cs | 4 +- .../Properties/Resources.Designer.cs | 2 +- .../Properties/Settings.Designer.cs | 2 +- Meade.net.Telescope/Telescope.cs | 114 ++++++++++++++++-- Meade.net.Telescope/app.config | 2 +- Meade.net.focuser/Focuser.cs | 33 +++-- Meade.net.focuser/Meade.net.focuser.csproj | 4 +- Meade.net.focuser/Properties/AssemblyInfo.cs | 4 +- .../Properties/Resources.Designer.cs | 2 +- .../Properties/Settings.Designer.cs | 2 +- Meade.net.focuser/app.config | 2 +- Meade.net.sln | 19 +-- Meade.net/Localization/LocalisationHelper.cs | 4 +- Meade.net/Meade.net.csproj | 4 +- Meade.net/Properties/AssemblyInfo.cs | 4 +- Meade.net/Properties/Resources.Designer.cs | 2 +- Meade.net/SharedResources.cs | 14 ++- Meade.net/app.config | 2 +- TelescopeTestConsole/Program.cs | 4 +- .../Properties/AssemblyInfo.cs | 4 +- .../TelescopeTestConsole.csproj | 4 +- TelescopeTestConsole/app.config | 2 +- 30 files changed, 196 insertions(+), 69 deletions(-) diff --git a/AstroMath.UnitTests/AstroMath.UnitTests.csproj b/AstroMath.UnitTests/AstroMath.UnitTests.csproj index cf9d11f..d066d8f 100644 --- a/AstroMath.UnitTests/AstroMath.UnitTests.csproj +++ b/AstroMath.UnitTests/AstroMath.UnitTests.csproj @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - AnyCPU + x86 pdbonly diff --git a/AstroMath.UnitTests/Properties/AssemblyInfo.cs b/AstroMath.UnitTests/Properties/AssemblyInfo.cs index 11e0a8b..1ebc9b6 100644 --- a/AstroMath.UnitTests/Properties/AssemblyInfo.cs +++ b/AstroMath.UnitTests/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] diff --git a/FocuserTestConsole/FocuserTestConsole.csproj b/FocuserTestConsole/FocuserTestConsole.csproj index 207d96f..09329fa 100644 --- a/FocuserTestConsole/FocuserTestConsole.csproj +++ b/FocuserTestConsole/FocuserTestConsole.csproj @@ -10,7 +10,7 @@ Properties ASCOM.MeadeGeneric ASCOM.MeadeGeneric.Test - v4.7.1 + v4.0 512 @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - false + true x86 diff --git a/FocuserTestConsole/Properties/AssemblyInfo.cs b/FocuserTestConsole/Properties/AssemblyInfo.cs index 5100d4b..b979463 100644 --- a/FocuserTestConsole/Properties/AssemblyInfo.cs +++ b/FocuserTestConsole/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("6.4.0.0")] -[assembly: AssemblyFileVersion("6.4.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] diff --git a/FocuserTestConsole/app.config b/FocuserTestConsole/app.config index 70dcdba..e365603 100644 --- a/FocuserTestConsole/app.config +++ b/FocuserTestConsole/app.config @@ -1,3 +1,3 @@ - + diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi index ec90b40..0040fe9 100644 --- a/Meade.net.Setup/Config.wxi +++ b/Meade.net.Setup/Config.wxi @@ -44,5 +44,5 @@ - + \ No newline at end of file diff --git a/Meade.net.Setup/Product.wxs b/Meade.net.Setup/Product.wxs index 73b314e..7a36ccd 100644 --- a/Meade.net.Setup/Product.wxs +++ b/Meade.net.Setup/Product.wxs @@ -15,9 +15,8 @@ - - - ="#461308"]]> + + diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 3fa86d7..35f9b0b 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -15,7 +15,7 @@ 3.5 - v4.7.1 + v4.0 ASCOM.ico true ASCOMDriverTemplate.snk @@ -46,7 +46,7 @@ prompt 4 true - AnyCPU + x86 false @@ -63,6 +63,10 @@ ..\bin\Release\ + + ..\bin\Debug\ + x86 + diff --git a/Meade.net.Telescope/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs index 8e8df09..dcf1e41 100644 --- a/Meade.net.Telescope/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.5.0.0")] -[assembly: AssemblyFileVersion("0.5.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] diff --git a/Meade.net.Telescope/Properties/Resources.Designer.cs b/Meade.net.Telescope/Properties/Resources.Designer.cs index 67f90ec..7df2b0c 100644 --- a/Meade.net.Telescope/Properties/Resources.Designer.cs +++ b/Meade.net.Telescope/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace ASCOM.Meade.net.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/Meade.net.Telescope/Properties/Settings.Designer.cs b/Meade.net.Telescope/Properties/Settings.Designer.cs index f1cc444..67ea42d 100644 --- a/Meade.net.Telescope/Properties/Settings.Designer.cs +++ b/Meade.net.Telescope/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace ASCOM.Meade.net.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 275329a..da76b38 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -165,15 +165,92 @@ namespace ASCOM.Meade.net get { tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); - return new ArrayList(); + var supportedActions = new ArrayList(); + supportedActions.Add("handbox"); + return supportedActions; } } public string Action(string actionName, string actionParameters) { - LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException("Action " + actionName + - " is not implemented by this driver"); + switch (actionName.ToLower()) + { + case "handbox": + switch (actionParameters.ToLower()) + { + //Read the screen + case "readdisplay": + var output = SharedResources.SendString(":ED#"); + return output; + + //top row of buttons + case "enter": + SharedResources.SendBlind(":EK13#"); + break; + case "mode": + SharedResources.SendBlind(":EK9#"); + break; + case "goto": + SharedResources.SendBlind(":EK24#"); + break; + + case "0": //light and 0 + SharedResources.SendBlind(":EK48#"); + break; + case "1": + SharedResources.SendBlind(":EK49#"); + break; + case "2": + SharedResources.SendBlind(":EK50#"); + break; + case "3": + SharedResources.SendBlind(":EK51#"); + break; + case "4": + SharedResources.SendBlind(":EK52#"); + break; + case "5": + SharedResources.SendBlind(":EK53#"); + break; + case "6": + SharedResources.SendBlind(":EK54#"); + break; + case "7": + SharedResources.SendBlind(":EK55#"); + break; + case "8": + SharedResources.SendBlind(":EK56#"); + break; + case "9": + SharedResources.SendBlind(":EK57#"); + break; + + case "up": + SharedResources.SendBlind(":EK94#"); + break; + case "down": + SharedResources.SendBlind(":EK118#"); + break; + case "back": + SharedResources.SendBlind(":EK87#"); + break; + case "forward": + SharedResources.SendBlind(":EK69#"); + break; + case "?": + SharedResources.SendBlind(":EK63#"); + break; + default: + LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); + throw new ASCOM.ActionNotImplementedException($"Action {actionName}({actionParameters}) is not implemented by this driver"); + } + break; + default: + LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); + throw new ASCOM.ActionNotImplementedException($"Action {actionName} is not implemented by this driver"); + } + + return string.Empty; } public void CommandBlind(string command, bool raw) @@ -240,9 +317,15 @@ namespace ASCOM.Meade.net SharedResources.Connect("Serial"); try { + LogMessage("Connected Set", $"Commented to port {comPort}. Product: {SharedResources.ProductName} Version:{SharedResources.FirmwareVersion}"); + + SelectSite(1); SetLongFormat(true); + + _userNewerPulseGuiding = IsNewPulseGuidingSupported(); + _connectedState = true; } catch (Exception) @@ -265,6 +348,23 @@ namespace ASCOM.Meade.net } } + private bool IsNewPulseGuidingSupported() + { + if (SharedResources.ProductName == SharedResources.AUTOSTAR497) + { + return FirmwareIsGreaterThan(SharedResources.AUTOSTAR497_31EE); + } + + return false; + } + + private bool FirmwareIsGreaterThan(string minVersion) + { + var currentVersion = SharedResources.FirmwareVersion; + var comparison = currentVersion.CompareTo(minVersion); + return (comparison >= 0); + } + private void SetLongFormat(bool setLongFormat) { SharedResources.Lock(() => @@ -312,8 +412,7 @@ namespace ASCOM.Meade.net { Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; // TODO customise this driver description - string driverInfo = "Information about the driver itself. Version: " + - String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, + string driverInfo = "Meade Generic .net driver. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); tl.LogMessage("DriverInfo Get", driverInfo); return driverInfo; @@ -948,8 +1047,7 @@ namespace ASCOM.Meade.net AtPark = true; } - private readonly bool - _userNewerPulseGuiding = true; //todo make this a device setting based on firmware revision + private bool _userNewerPulseGuiding = true; public void PulseGuide(GuideDirections direction, int duration) { diff --git a/Meade.net.Telescope/app.config b/Meade.net.Telescope/app.config index 56895a9..762f9a3 100644 --- a/Meade.net.Telescope/app.config +++ b/Meade.net.Telescope/app.config @@ -5,4 +5,4 @@
    - + diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 14e8b26..2939517 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -350,9 +350,16 @@ namespace ASCOM.Meade.net CheckConnected("Halt"); - SharedResources.SendBlind(":FQ#"); - //:FQ# Halt Focuser Motion - //Returns: Nothing + //A single halt command is sometimes missed by the #909 apm, so let's do it a few times to be safe. + Stopwatch stopwatch = Stopwatch.StartNew(); + while (stopwatch.ElapsedMilliseconds < 200) + { + SharedResources.SendBlind(":FQ#"); + //:FQ# Halt Focuser Motion + //Returns: Nothing + + utilities.WaitForMilliseconds(50); + } } public bool IsMoving @@ -431,7 +438,7 @@ namespace ASCOM.Meade.net { SharedResources.Lock(() => { - SharedResources.SendBlind(":FF#"); + //SharedResources.SendBlind(":FF#"); //:FF# Set Focus speed to fastest setting //Returns: Nothing @@ -443,17 +450,23 @@ namespace ASCOM.Meade.net //All others – Not Supported utilities.WaitForMilliseconds(100); - SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#"); - //:F+# Start Focuser moving inward (toward objective) - //Returns: None + //A Single focus command sometimes gets lost on the #909, so sending lots of them solves the issue. + Stopwatch stopwatch = Stopwatch.StartNew(); + while (stopwatch.ElapsedMilliseconds < steps) + { + SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#"); + //:F+# Start Focuser moving inward (toward objective) + //Returns: None - //:F-# Start Focuser moving outward (away from objective) - //Returns: None + //:F-# Start Focuser moving outward (away from objective) + //Returns: None - utilities.WaitForMilliseconds(steps); + utilities.WaitForMilliseconds(50); + } Halt(); + //This gives the focuser time to physically stop. utilities.WaitForMilliseconds(1000); }); } diff --git a/Meade.net.focuser/Meade.net.focuser.csproj b/Meade.net.focuser/Meade.net.focuser.csproj index a1fd243..bafde48 100644 --- a/Meade.net.focuser/Meade.net.focuser.csproj +++ b/Meade.net.focuser/Meade.net.focuser.csproj @@ -15,7 +15,7 @@ 3.5 - v4.7.1 + v4.0 ASCOM.ico true ASCOMDriverTemplate.snk @@ -62,7 +62,7 @@ true - bin\x86\Debug\ + ..\bin\Debug\ DEBUG;TRACE true full diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs index a02a8e6..c0f0c5b 100644 --- a/Meade.net.focuser/Properties/AssemblyInfo.cs +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.5.0.0")] -[assembly: AssemblyFileVersion("0.5.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] diff --git a/Meade.net.focuser/Properties/Resources.Designer.cs b/Meade.net.focuser/Properties/Resources.Designer.cs index 67f90ec..7df2b0c 100644 --- a/Meade.net.focuser/Properties/Resources.Designer.cs +++ b/Meade.net.focuser/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace ASCOM.Meade.net.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/Meade.net.focuser/Properties/Settings.Designer.cs b/Meade.net.focuser/Properties/Settings.Designer.cs index f1cc444..67ea42d 100644 --- a/Meade.net.focuser/Properties/Settings.Designer.cs +++ b/Meade.net.focuser/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace ASCOM.Meade.net.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/Meade.net.focuser/app.config b/Meade.net.focuser/app.config index 56895a9..762f9a3 100644 --- a/Meade.net.focuser/app.config +++ b/Meade.net.focuser/app.config @@ -5,4 +5,4 @@
    - + diff --git a/Meade.net.sln b/Meade.net.sln index d8f177e..96aacec 100644 --- a/Meade.net.sln +++ b/Meade.net.sln @@ -35,8 +35,8 @@ Global {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|Any CPU.Build.0 = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x64.ActiveCfg = Debug|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x64.Build.0 = Debug|Any CPU - {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.ActiveCfg = Debug|Any CPU - {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.Build.0 = Debug|Any CPU + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.ActiveCfg = Debug|x86 + {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Debug|x86.Build.0 = Debug|x86 {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.ActiveCfg = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|Any CPU.Build.0 = Release|Any CPU {3689A2CB-94C5-4012-A5CF-7E7D1DD27143}.Release|x64.ActiveCfg = Release|Any CPU @@ -47,8 +47,8 @@ Global {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x64.ActiveCfg = Debug|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x64.Build.0 = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU - {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|x86 + {64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|x86 {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU {64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x64.ActiveCfg = Release|Any CPU @@ -59,8 +59,8 @@ Global {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|Any CPU.Build.0 = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x64.ActiveCfg = Debug|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x64.Build.0 = Debug|Any CPU - {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.ActiveCfg = Debug|Any CPU - {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.Build.0 = Debug|Any CPU + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.ActiveCfg = Debug|x86 + {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Debug|x86.Build.0 = Debug|x86 {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.ActiveCfg = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|Any CPU.Build.0 = Release|Any CPU {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x64.ActiveCfg = Release|Any CPU @@ -69,6 +69,7 @@ Global {A97E3AEC-F11D-49DA-B259-DE99DA813A86}.Release|x86.Build.0 = Release|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x64.ActiveCfg = Debug|x86 + {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x64.Build.0 = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86 {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86 @@ -77,6 +78,7 @@ Global {D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|Any CPU.ActiveCfg = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x64.ActiveCfg = Debug|x86 + {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x64.Build.0 = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.ActiveCfg = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Debug|x86.Build.0 = Debug|x86 {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49}.Release|Any CPU.ActiveCfg = Release|x86 @@ -87,8 +89,8 @@ Global {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x64.ActiveCfg = Debug|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x64.Build.0 = Debug|Any CPU - {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.ActiveCfg = Debug|Any CPU - {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.Build.0 = Debug|Any CPU + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.ActiveCfg = Debug|x86 + {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Debug|x86.Build.0 = Debug|x86 {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|Any CPU.Build.0 = Release|Any CPU {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95}.Release|x64.ActiveCfg = Release|Any CPU @@ -98,7 +100,6 @@ Global {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.ActiveCfg = Debug|x64 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|Any CPU.Build.0 = Debug|x64 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x64.ActiveCfg = Debug|x64 - {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x64.Build.0 = Debug|x64 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x86.ActiveCfg = Debug|x86 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Debug|x86.Build.0 = Debug|x86 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|Any CPU.ActiveCfg = Release|x86 diff --git a/Meade.net/Localization/LocalisationHelper.cs b/Meade.net/Localization/LocalisationHelper.cs index a8ac3a7..9c4b4bf 100644 --- a/Meade.net/Localization/LocalisationHelper.cs +++ b/Meade.net/Localization/LocalisationHelper.cs @@ -21,8 +21,8 @@ namespace ASCOM.Meade.net.Localization { var cultureInfo = new CultureInfo(name); - CultureInfo.DefaultThreadCurrentCulture = cultureInfo; - CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; + //CultureInfo.DefaultThreadCurrentCulture = cultureInfo; + //CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; Thread.CurrentThread.CurrentCulture = cultureInfo; Thread.CurrentThread.CurrentUICulture = cultureInfo; diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 6be15b8..e1d415b 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -10,7 +10,7 @@ Properties ASCOM.Meade.net ASCOM.Meade.net.Server - v4.7.1 + v4.0 2.0 @@ -65,7 +65,7 @@ true - bin\x86\Debug\ + ..\bin\Debug\ DEBUG;TRACE full x86 diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs index 9570023..cb667c7 100644 --- a/Meade.net/Properties/AssemblyInfo.cs +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -21,7 +21,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.5.0.0")] -[assembly: AssemblyFileVersion("0.5.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] [assembly: ComVisibleAttribute(false)] diff --git a/Meade.net/Properties/Resources.Designer.cs b/Meade.net/Properties/Resources.Designer.cs index 0255290..67c41c7 100644 --- a/Meade.net/Properties/Resources.Designer.cs +++ b/Meade.net/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace ASCOM.Meade.net.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 733506b..6afc65e 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -234,8 +234,19 @@ namespace ASCOM.Meade.net #endregion + #region AutostarProducts + + public const string AUTOSTAR497 = "Autostar"; + + public const string AUTOSTAR497_31EE = "31Ee"; + + #endregion + #region Multi Driver handling + public static string ProductName { get; private set; } = string.Empty; + public static string FirmwareVersion { get; private set; } = string.Empty; + // this section illustrates how multiple drivers could be handled, // it's for drivers where multiple connections to the hardware can be made and ensures that the // hardware is only disconnected from when all the connected devices have disconnected. @@ -280,7 +291,8 @@ namespace ASCOM.Meade.net SharedResources.SharedSerial.Handshake = SerialHandshake.None; SharedResources.SharedSerial.Connected = true; - string firmware = SendString(":GVN#"); + ProductName = SendString(":GVP#"); + FirmwareVersion = SendString(":GVN#"); } } } diff --git a/Meade.net/app.config b/Meade.net/app.config index 70dcdba..e365603 100644 --- a/Meade.net/app.config +++ b/Meade.net/app.config @@ -1,3 +1,3 @@ - + diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 420046a..98c8e2b 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -22,7 +22,7 @@ namespace ASCOM // Uncomment the code that's required #if UseChooser // choose the device - string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.Meade.net.Telescope"); + string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.MeadeGeneric.Telescope"); if (string.IsNullOrEmpty(id)) return; // create this device @@ -44,7 +44,7 @@ namespace ASCOM device.Connected = true; - device.SlewToAltAz(150, 50); + //device.SlewToAltAz(150, 50); //device.CommandBlind(":Sa+30*00'00#", true); //device.CommandBlind(":Sz50*00#", true); diff --git a/TelescopeTestConsole/Properties/AssemblyInfo.cs b/TelescopeTestConsole/Properties/AssemblyInfo.cs index 2b89b32..6db7d58 100644 --- a/TelescopeTestConsole/Properties/AssemblyInfo.cs +++ b/TelescopeTestConsole/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("6.4.0.0")] -[assembly: AssemblyFileVersion("6.4.0.0")] +[assembly: AssemblyVersion("0.6.0.0")] +[assembly: AssemblyFileVersion("0.6.0.0")] diff --git a/TelescopeTestConsole/TelescopeTestConsole.csproj b/TelescopeTestConsole/TelescopeTestConsole.csproj index 61210c5..7fb2a6a 100644 --- a/TelescopeTestConsole/TelescopeTestConsole.csproj +++ b/TelescopeTestConsole/TelescopeTestConsole.csproj @@ -10,7 +10,7 @@ Properties ASCOM.Meade.net ASCOM.Meade.net.Test - v4.7.1 + v4.0 512 @@ -24,7 +24,7 @@ DEBUG;TRACE prompt 4 - false + true x86 diff --git a/TelescopeTestConsole/app.config b/TelescopeTestConsole/app.config index 70dcdba..e365603 100644 --- a/TelescopeTestConsole/app.config +++ b/TelescopeTestConsole/app.config @@ -1,3 +1,3 @@ - + From 4c92bf13c21a3c97ede6612475f77c9c7aaeba3c Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 8 Jun 2019 20:34:54 +0100 Subject: [PATCH 052/109] Slight modification to make sure that the focuser is poked less often --- Meade.net.Setup/Product.wxs | 3 ++- Meade.net.focuser/Focuser.cs | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Meade.net.Setup/Product.wxs b/Meade.net.Setup/Product.wxs index 7a36ccd..d9d14de 100644 --- a/Meade.net.Setup/Product.wxs +++ b/Meade.net.Setup/Product.wxs @@ -15,8 +15,9 @@ + - + diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 2939517..75a6f18 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -352,13 +352,13 @@ namespace ASCOM.Meade.net //A single halt command is sometimes missed by the #909 apm, so let's do it a few times to be safe. Stopwatch stopwatch = Stopwatch.StartNew(); - while (stopwatch.ElapsedMilliseconds < 200) + while (stopwatch.ElapsedMilliseconds < 1000) { SharedResources.SendBlind(":FQ#"); //:FQ# Halt Focuser Motion //Returns: Nothing - utilities.WaitForMilliseconds(50); + utilities.WaitForMilliseconds(250); } } @@ -461,7 +461,7 @@ namespace ASCOM.Meade.net //:F-# Start Focuser moving outward (away from objective) //Returns: None - utilities.WaitForMilliseconds(50); + utilities.WaitForMilliseconds(250); } Halt(); From 8e1188ac493aca953671c732260e10397d8f44d2 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 8 Jun 2019 21:01:57 +0100 Subject: [PATCH 053/109] Moved develop onto version 0.7.0.0 --- AstroMath.UnitTests/Properties/AssemblyInfo.cs | 4 ++-- FocuserTestConsole/Properties/AssemblyInfo.cs | 4 ++-- Meade.net.Setup/Config.wxi | 2 +- Meade.net.Telescope/Properties/AssemblyInfo.cs | 4 ++-- Meade.net.focuser/Properties/AssemblyInfo.cs | 4 ++-- Meade.net/Properties/AssemblyInfo.cs | 4 ++-- TelescopeTestConsole/Properties/AssemblyInfo.cs | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/AstroMath.UnitTests/Properties/AssemblyInfo.cs b/AstroMath.UnitTests/Properties/AssemblyInfo.cs index 1ebc9b6..2c0f1a3 100644 --- a/AstroMath.UnitTests/Properties/AssemblyInfo.cs +++ b/AstroMath.UnitTests/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] diff --git a/FocuserTestConsole/Properties/AssemblyInfo.cs b/FocuserTestConsole/Properties/AssemblyInfo.cs index b979463..1349406 100644 --- a/FocuserTestConsole/Properties/AssemblyInfo.cs +++ b/FocuserTestConsole/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi index 0040fe9..8e64544 100644 --- a/Meade.net.Setup/Config.wxi +++ b/Meade.net.Setup/Config.wxi @@ -44,5 +44,5 @@ - + \ No newline at end of file diff --git a/Meade.net.Telescope/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs index dcf1e41..5376198 100644 --- a/Meade.net.Telescope/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs index c0f0c5b..d74c566 100644 --- a/Meade.net.focuser/Properties/AssemblyInfo.cs +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs index cb667c7..502789e 100644 --- a/Meade.net/Properties/AssemblyInfo.cs +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -21,7 +21,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] [assembly: ComVisibleAttribute(false)] diff --git a/TelescopeTestConsole/Properties/AssemblyInfo.cs b/TelescopeTestConsole/Properties/AssemblyInfo.cs index 6db7d58..a358cd7 100644 --- a/TelescopeTestConsole/Properties/AssemblyInfo.cs +++ b/TelescopeTestConsole/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.6.0.0")] -[assembly: AssemblyFileVersion("0.6.0.0")] +[assembly: AssemblyVersion("0.7.0.0")] +[assembly: AssemblyFileVersion("0.7.0.0")] From 621b7dc2dac119c38757f24c8b2aeed41e2e74dd Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 9 Jun 2019 15:45:52 +0100 Subject: [PATCH 054/109] Added check for Ascom platform 6.4 SP 1 or higher. --- Meade.net.Setup/Product.wxs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Meade.net.Setup/Product.wxs b/Meade.net.Setup/Product.wxs index d9d14de..ce95dc0 100644 --- a/Meade.net.Setup/Product.wxs +++ b/Meade.net.Setup/Product.wxs @@ -12,8 +12,18 @@ - - + + + + + + + = "6.4.1"]]> + From 71bc7fd49ad4c7aa86baf0d8d99d170872fac1be Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 7 Jul 2019 14:52:06 +0100 Subject: [PATCH 055/109] Fixed issue with slew to RA/Dec not applying negative declinations properly. --- Meade.net.Telescope/Telescope.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index da76b38..bc7af47 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -190,6 +190,9 @@ namespace ASCOM.Meade.net case "mode": SharedResources.SendBlind(":EK9#"); break; + case "longMode": + SharedResources.SendBlind(":EK11#"); + break; case "goto": SharedResources.SendBlind(":EK24#"); break; @@ -1448,16 +1451,20 @@ namespace ASCOM.Meade.net { case "0": //We're slewing everything should be working just fine. + tl.LogMessage("DoSlewAsync", "Slewing to target"); break; case "1": //Below Horizon string belowHorizonMessage = SharedResources.ReadTerminated(); + tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowHorizonMessage}\""); throw new ASCOM.InvalidOperationException(belowHorizonMessage); case "2": //Below Horizon string belowMinimumElevationMessage = SharedResources.ReadTerminated(); + tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowMinimumElevationMessage}\""); throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); default: + tl.LogMessage("DoSlewAsync", $"Slew failed - unknown response \"{response}\""); throw new ASCOM.DriverException("This error should not happen"); } @@ -1492,6 +1499,8 @@ namespace ASCOM.Meade.net { utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); } + + tl.LogMessage("SlewToCoordinates", $"Slewing completed new coordinates Ra={RightAscension}, Dec={Declination}"); } public void SlewToCoordinatesAsync(double rightAscension, double declination) @@ -1631,9 +1640,12 @@ namespace ASCOM.Meade.net CheckConnected("TargetDeclination Set"); var dms = utilities.DegreesToDMS(value, "*", ":", ":", 2); - var s = value < 0 ? '-' : '+'; + var s = value < 0 ? string.Empty : "+"; - var result = SharedResources.SendChar($":Sd{s}{dms}#"); + var command = $":Sd{s}{dms}#"; + + tl.LogMessage("TargetDeclination Set", $"{command}"); + var result = SharedResources.SendChar(command); //:SdsDD*MM# //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting //Returns: From a0a908d67d4ffbb87ee8ee8f5db5eaef97ca60a7 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 7 Jul 2019 18:26:58 +0100 Subject: [PATCH 056/109] Fixed issue when seeing target altitude to a negative value. --- Meade.net.Telescope/Telescope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index bc7af47..5d59eb1 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1347,7 +1347,7 @@ namespace ASCOM.Meade.net //todo this serial string does not work. Calculate the EQ version instead. var dms = utilities.DegreesToDMS(value, "*", "'", "",0); - var s = value < 0 ? "-" : "+"; + var s = value < 0 ? string.Empty : "+"; var result = SharedResources.SendChar($":Sa{s}{dms}#"); //:SasDD*MM# From bc90049798a7e0b172b50a499b7abd7a80bf43c8 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 8 Jul 2019 17:15:01 +0100 Subject: [PATCH 057/109] Switched over the Telescope and focuser to access the SharedResources via a wrapper with an interface to help with unit testing --- Meade.net.Telescope/Telescope.cs | 190 ++++++++++---------- Meade.net.focuser/Focuser.cs | 34 ++-- Meade.net/Meade.net.csproj | 1 + Meade.net/SharedResources.cs | 10 +- Meade.net/Wrapper/SharedResourcesWrapper.cs | 98 ++++++++++ 5 files changed, 216 insertions(+), 117 deletions(-) create mode 100644 Meade.net/Wrapper/SharedResourcesWrapper.cs diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 5d59eb1..b2b1e0e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -40,6 +40,7 @@ using ASCOM.DeviceInterface; using System.Globalization; using System.Collections; using System.Reflection; +using ASCOM.Meade.net.Wrapper; namespace ASCOM.Meade.net { @@ -105,6 +106,8 @@ namespace ASCOM.Meade.net /// internal static TraceLogger tl; + private readonly ISharedResourcesWrapper _sharedResourcesWrapper; + /// /// Initializes a new instance of the class. /// Must be public for COM registration. @@ -119,6 +122,7 @@ namespace ASCOM.Meade.net _connectedState = false; // Initialise connected to false utilities = new Util(); //Initialise util object astroUtilities = new AstroUtils(); // Initialise astro utilities object + _sharedResourcesWrapper = new SharedResourcesWrapper(); //TODO: Implement your additional construction here _astroMaths = new AstroMaths(); @@ -142,7 +146,7 @@ namespace ASCOM.Meade.net public void SetupDialog() { tl.LogMessage("SetupDialog", "Opening setup dialog"); - SharedResources.SetupDialog(); + _sharedResourcesWrapper.SetupDialog(); ReadProfile(); tl.LogMessage("SetupDialog", "complete"); //// consider only showing the setup dialog if not connected @@ -180,68 +184,68 @@ namespace ASCOM.Meade.net { //Read the screen case "readdisplay": - var output = SharedResources.SendString(":ED#"); + var output = _sharedResourcesWrapper.SendString(":ED#"); return output; //top row of buttons case "enter": - SharedResources.SendBlind(":EK13#"); + _sharedResourcesWrapper.SendBlind(":EK13#"); break; case "mode": - SharedResources.SendBlind(":EK9#"); + _sharedResourcesWrapper.SendBlind(":EK9#"); break; case "longMode": - SharedResources.SendBlind(":EK11#"); + _sharedResourcesWrapper.SendBlind(":EK11#"); break; case "goto": - SharedResources.SendBlind(":EK24#"); + _sharedResourcesWrapper.SendBlind(":EK24#"); break; case "0": //light and 0 - SharedResources.SendBlind(":EK48#"); + _sharedResourcesWrapper.SendBlind(":EK48#"); break; case "1": - SharedResources.SendBlind(":EK49#"); + _sharedResourcesWrapper.SendBlind(":EK49#"); break; case "2": - SharedResources.SendBlind(":EK50#"); + _sharedResourcesWrapper.SendBlind(":EK50#"); break; case "3": - SharedResources.SendBlind(":EK51#"); + _sharedResourcesWrapper.SendBlind(":EK51#"); break; case "4": - SharedResources.SendBlind(":EK52#"); + _sharedResourcesWrapper.SendBlind(":EK52#"); break; case "5": - SharedResources.SendBlind(":EK53#"); + _sharedResourcesWrapper.SendBlind(":EK53#"); break; case "6": - SharedResources.SendBlind(":EK54#"); + _sharedResourcesWrapper.SendBlind(":EK54#"); break; case "7": - SharedResources.SendBlind(":EK55#"); + _sharedResourcesWrapper.SendBlind(":EK55#"); break; case "8": - SharedResources.SendBlind(":EK56#"); + _sharedResourcesWrapper.SendBlind(":EK56#"); break; case "9": - SharedResources.SendBlind(":EK57#"); + _sharedResourcesWrapper.SendBlind(":EK57#"); break; case "up": - SharedResources.SendBlind(":EK94#"); + _sharedResourcesWrapper.SendBlind(":EK94#"); break; case "down": - SharedResources.SendBlind(":EK118#"); + _sharedResourcesWrapper.SendBlind(":EK118#"); break; case "back": - SharedResources.SendBlind(":EK87#"); + _sharedResourcesWrapper.SendBlind(":EK87#"); break; case "forward": - SharedResources.SendBlind(":EK69#"); + _sharedResourcesWrapper.SendBlind(":EK69#"); break; case "?": - SharedResources.SendBlind(":EK63#"); + _sharedResourcesWrapper.SendBlind(":EK63#"); break; default: LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); @@ -261,7 +265,7 @@ namespace ASCOM.Meade.net CheckConnected("CommandBlind"); // Call CommandString and return as soon as it finishes //this.CommandString(command, raw); - SharedResources.SendBlind(command); + _sharedResourcesWrapper.SendBlind(command); // or //throw new ASCOM.MethodNotImplementedException("CommandBlind"); // DO NOT have both these sections! One or the other @@ -283,7 +287,7 @@ namespace ASCOM.Meade.net // it's a good idea to put all the low level communication with the device here, // then all communication calls this function // you need something to ensure that only one command is in progress at a time - return SharedResources.SendString(command); + return _sharedResourcesWrapper.SendString(command); //throw new ASCOM.MethodNotImplementedException("CommandString"); } @@ -317,10 +321,10 @@ namespace ASCOM.Meade.net LogMessage("Connected Set", "Connecting to port {0}", comPort); try { - SharedResources.Connect("Serial"); + _sharedResourcesWrapper.Connect("Serial"); try { - LogMessage("Connected Set", $"Commented to port {comPort}. Product: {SharedResources.ProductName} Version:{SharedResources.FirmwareVersion}"); + LogMessage("Connected Set", $"Commented to port {comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); SelectSite(1); @@ -333,7 +337,7 @@ namespace ASCOM.Meade.net } catch (Exception) { - SharedResources.Disconnect("Serial"); + _sharedResourcesWrapper.Disconnect("Serial"); throw; } } @@ -345,7 +349,7 @@ namespace ASCOM.Meade.net else { LogMessage("Connected Set", "Disconnecting from port {0}", comPort); - SharedResources.Disconnect("Serial"); + _sharedResourcesWrapper.Disconnect("Serial"); _connectedState = false; } } @@ -353,9 +357,9 @@ namespace ASCOM.Meade.net private bool IsNewPulseGuidingSupported() { - if (SharedResources.ProductName == SharedResources.AUTOSTAR497) + if (_sharedResourcesWrapper.ProductName == _sharedResourcesWrapper.AUTOSTAR497) { - return FirmwareIsGreaterThan(SharedResources.AUTOSTAR497_31EE); + return FirmwareIsGreaterThan(_sharedResourcesWrapper.AUTOSTAR497_31EE); } return false; @@ -363,16 +367,16 @@ namespace ASCOM.Meade.net private bool FirmwareIsGreaterThan(string minVersion) { - var currentVersion = SharedResources.FirmwareVersion; + var currentVersion = _sharedResourcesWrapper.FirmwareVersion; var comparison = currentVersion.CompareTo(minVersion); return (comparison >= 0); } private void SetLongFormat(bool setLongFormat) { - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { - var result = SharedResources.SendString(":GZ#"); + var result = _sharedResourcesWrapper.SendString(":GZ#"); //:GZ# Get telescope azimuth //Returns: DDD*MM#T or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. @@ -382,7 +386,7 @@ namespace ASCOM.Meade.net if (isLongFormat != setLongFormat) { utilities.WaitForMilliseconds(500); - SharedResources.SendBlind(":U#"); + _sharedResourcesWrapper.SendBlind(":U#"); //:U# Toggle between low/hi precision positions //Low - RA displays and messages HH:MM.T sDD*MM //High - Dec / Az / El displays and messages HH:MM: SS sDD*MM:SS @@ -393,7 +397,7 @@ namespace ASCOM.Meade.net private void SelectSite(int site) { - SharedResources.SendBlind($":W{site}#"); + _sharedResourcesWrapper.SendBlind($":W{site}#"); //:W# //Set current site to, an ASCII digit in the range 1..4 //Returns: Nothing @@ -450,11 +454,11 @@ namespace ASCOM.Meade.net { //string name = "Short driver name - please customise"; - //var telescopeProduceName = SharedResources.SendString(":GVP#"); + //var telescopeProduceName = _sharedResourcesWrapper.SendString(":GVP#"); ////:GVP# Get Telescope Product Name ////Returns: # - //var firmwareVersion = SharedResources.SendString(":GVN#"); + //var firmwareVersion = _sharedResourcesWrapper.SendString(":GVN#"); ////:GVN# Get Telescope Firmware Number ////Returns: dd.d# @@ -474,7 +478,7 @@ namespace ASCOM.Meade.net CheckConnected("AbortSlew"); tl.LogMessage("AbortSlew", "Aborting slew"); - SharedResources.SendBlind(":Q#"); + _sharedResourcesWrapper.SendBlind(":Q#"); //:Q# Halt all current slewing //Returns:Nothing } @@ -489,7 +493,7 @@ namespace ASCOM.Meade.net const char ack = (char) 6; - var alignmentString = SharedResources.SendChar(ack.ToString()); + var alignmentString = _sharedResourcesWrapper.SendChar(ack.ToString()); //ACK <0x06> Query of alignment mounting mode. //Returns: //A If scope in AltAz Mode @@ -533,13 +537,13 @@ namespace ASCOM.Meade.net switch (value) { case AlignmentModes.algAltAz: - SharedResources.SendBlind(":AA#"); + _sharedResourcesWrapper.SendBlind(":AA#"); //:AA# Sets telescope the AltAz alignment mode //Returns: nothing break; case AlignmentModes.algPolar: case AlignmentModes.algGermanPolar: - SharedResources.SendBlind(":AP#"); + _sharedResourcesWrapper.SendBlind(":AP#"); //:AP# Sets telescope to Polar alignment mode //Returns: nothing break; @@ -563,7 +567,7 @@ namespace ASCOM.Meade.net return altAz.Altitude; ////todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! - //var result = SharedResources.SendString(":GA#"); + //var result = _sharedResourcesWrapper.SendString(":GA#"); ////:GA# Get Telescope Altitude ////Returns: sDD* MM# or sDD*MM’SS# ////The current scope altitude. The returned format depending on the current precision setting. @@ -579,7 +583,7 @@ namespace ASCOM.Meade.net private HorizonCoordinates CalcAltAzFromTelescopeEqData() { - var altitudeData = SharedResources.Lock(() => new AltitudeData + var altitudeData = _sharedResourcesWrapper.Lock(() => new AltitudeData { UtcDateTime = this.UTCDate, SiteLongitude = this.SiteLongitude, @@ -648,7 +652,7 @@ namespace ASCOM.Meade.net { CheckConnected("Azimuth get"); - //var result = SharedResources.SendString(":GZ#"); + //var result = _sharedResourcesWrapper.SendString(":GZ#"); //:GZ# Get telescope azimuth //Returns: DDD*MM#T or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. @@ -826,7 +830,7 @@ namespace ASCOM.Meade.net { CheckConnected("Declination Get"); - var result = SharedResources.SendString(":GD#"); + var result = _sharedResourcesWrapper.SendString(":GD#"); //:GD# Get Telescope Declination. //Returns: sDD* MM# or sDD*MM’SS# //Depending upon the current precision setting for the telescope. @@ -952,22 +956,22 @@ namespace ASCOM.Meade.net //do nothing, it's ok this time as we're halting the slew. break; case 1: - SharedResources.SendBlind(":RG#"); + _sharedResourcesWrapper.SendBlind(":RG#"); //:RG# Set Slew rate to Guiding Rate (slowest) //Returns: Nothing break; case 2: - SharedResources.SendBlind(":RC#"); + _sharedResourcesWrapper.SendBlind(":RC#"); //:RC# Set Slew rate to Centering rate (2nd slowest) //Returns: Nothing break; case 3: - SharedResources.SendBlind(":RM#"); + _sharedResourcesWrapper.SendBlind(":RM#"); //:RM# Set Slew rate to Find Rate (2nd Fastest) //Returns: Nothing break; case 4: - SharedResources.SendBlind(":RS#"); + _sharedResourcesWrapper.SendBlind(":RS#"); //:RS# Set Slew rate to max (fastest) //Returns: Nothing break; @@ -981,23 +985,23 @@ namespace ASCOM.Meade.net if (rate == 0) { _movingPrimary = false; - SharedResources.SendBlind(":Qe#"); + _sharedResourcesWrapper.SendBlind(":Qe#"); //:Qe# Halt eastward Slews //Returns: Nothing - SharedResources.SendBlind(":Qw#"); + _sharedResourcesWrapper.SendBlind(":Qw#"); //:Qw# Halt westward Slews //Returns: Nothing } else if (rate > 0) { - SharedResources.SendBlind(":Me#"); + _sharedResourcesWrapper.SendBlind(":Me#"); //:Me# Move Telescope East at current slew rate //Returns: Nothing _movingPrimary = true; } else { - SharedResources.SendBlind(":Mw#"); + _sharedResourcesWrapper.SendBlind(":Mw#"); //:Mw# Move Telescope West at current slew rate //Returns: Nothing _movingPrimary = true; @@ -1008,23 +1012,23 @@ namespace ASCOM.Meade.net if (rate == 0) { _movingSecondary = false; - SharedResources.SendBlind(":Qn#"); + _sharedResourcesWrapper.SendBlind(":Qn#"); //:Qn# Halt northward Slews //Returns: Nothing - SharedResources.SendBlind(":Qs#"); + _sharedResourcesWrapper.SendBlind(":Qs#"); //:Qs# Halt southward Slews //Returns: Nothing } else if (rate > 0) { - SharedResources.SendBlind(":Mn#"); + _sharedResourcesWrapper.SendBlind(":Mn#"); //:Mn# Move Telescope North at current slew rate //Returns: Nothing _movingSecondary = true; } else { - SharedResources.SendBlind(":Ms#"); + _sharedResourcesWrapper.SendBlind(":Ms#"); //:Ms# Move Telescope South at current slew rate //Returns: Nothing _movingSecondary = true; @@ -1044,7 +1048,7 @@ namespace ASCOM.Meade.net if (AtPark) return; - SharedResources.SendBlind(":hP#"); + _sharedResourcesWrapper.SendBlind(":hP#"); //:hP# Autostar, Autostar II and LX 16”Slew to Park Position //Returns: Nothing AtPark = true; @@ -1076,7 +1080,7 @@ namespace ASCOM.Meade.net if (_userNewerPulseGuiding) { - SharedResources.SendBlind($":Mg{d}{duration:0000}#"); + _sharedResourcesWrapper.SendBlind($":Mg{d}{duration:0000}#"); //:MgnDDDD# //:MgsDDDD# //:MgeDDDD# @@ -1090,12 +1094,12 @@ namespace ASCOM.Meade.net } else { - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { - SharedResources.SendBlind(":RG#"); //Make sure we are at guide rate + _sharedResourcesWrapper.SendBlind(":RG#"); //Make sure we are at guide rate //:RG# Set Slew rate to Guiding Rate (slowest) //Returns: Nothing - SharedResources.SendBlind($":M{d}#"); + _sharedResourcesWrapper.SendBlind($":M{d}#"); //:Me# Move Telescope East at current slew rate //Returns: Nothing //:Mn# Move Telescope North at current slew rate @@ -1105,7 +1109,7 @@ namespace ASCOM.Meade.net //:Mw# Move Telescope West at current slew rate //Returns: Nothing utilities.WaitForMilliseconds(duration); - SharedResources.SendBlind($":Q{d}#"); + _sharedResourcesWrapper.SendBlind($":Q{d}#"); //:Qe# Halt eastward Slews //Returns: Nothing //:Qn# Halt northward Slews @@ -1123,7 +1127,7 @@ namespace ASCOM.Meade.net get { CheckConnected("RightAscension Get"); - var result = SharedResources.SendString(":GR#"); + var result = _sharedResourcesWrapper.SendString(":GR#"); //:GR# Get Telescope RA //Returns: HH: MM.T# or HH:MM:SS# //Depending which precision is set for the telescope @@ -1216,7 +1220,7 @@ namespace ASCOM.Meade.net { CheckConnected("SiteLatitude Get"); - var latitude = SharedResources.SendString(":Gt#"); + var latitude = _sharedResourcesWrapper.SendString(":Gt#"); //:Gt# Get Current Site Latitude //Returns: sDD* MM# //The latitude of the current site. Positive inplies North latitude. @@ -1241,7 +1245,7 @@ namespace ASCOM.Meade.net int d = Convert.ToInt32(Math.Floor(value)); int m = Convert.ToInt32(60 * (value - d)); - var result = SharedResources.SendChar($":St{sign}{d:00}*{m:00}#"); + var result = _sharedResourcesWrapper.SendChar($":St{sign}{d:00}*{m:00}#"); //:StsDD*MM# //Sets the current site latitude to sDD* MM# //Returns: @@ -1258,7 +1262,7 @@ namespace ASCOM.Meade.net { CheckConnected("SiteLongitude Get"); - var longitude = SharedResources.SendString(":Gg#"); + var longitude = _sharedResourcesWrapper.SendString(":Gg#"); //:Gg# Get Current Site Longitude //Returns: sDDD* MM# //The current site Longitude. East Longitudes are expressed as negative @@ -1294,7 +1298,7 @@ namespace ASCOM.Meade.net int d = Convert.ToInt32(Math.Floor(newLongitude)); int m = Convert.ToInt32(60 * (newLongitude - d)); - var result = SharedResources.SendChar($":Sg{d:000}*{m:00}#"); + var result = _sharedResourcesWrapper.SendChar($":Sg{d:000}*{m:00}#"); //:SgDDD*MM# //Set current site’s longitude to DDD*MM an ASCII position string //Returns: @@ -1349,7 +1353,7 @@ namespace ASCOM.Meade.net var dms = utilities.DegreesToDMS(value, "*", "'", "",0); var s = value < 0 ? string.Empty : "+"; - var result = SharedResources.SendChar($":Sa{s}{dms}#"); + var result = _sharedResourcesWrapper.SendChar($":Sa{s}{dms}#"); //:SasDD*MM# //Set target object altitude to sDD*MM# or sDD*MM’SS# [LX 16”, Autostar, Autostar II] //Returns: @@ -1377,7 +1381,7 @@ namespace ASCOM.Meade.net var dms = utilities.DegreesToDM(value, "*" ); - var result = SharedResources.SendChar($":Sz{dms}#"); + var result = _sharedResourcesWrapper.SendChar($":Sz{dms}#"); //:SzDDD*MM# //Sets the target Object Azimuth[LX 16” and Autostar II only] //Returns: @@ -1415,7 +1419,7 @@ namespace ASCOM.Meade.net var latitude = SiteLatitude; var longitude = SiteLongitude; - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { var raDec = _astroMaths.ConvertHozToEq(utcDateTime, latitude, longitude, altAz); @@ -1435,12 +1439,12 @@ namespace ASCOM.Meade.net { CheckConnected("DoSlewAsync"); - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { switch (polar) { case true: - var response = SharedResources.SendChar(":MS#"); + var response = _sharedResourcesWrapper.SendChar(":MS#"); //:MS# Slew to Target Object //Returns: //0 Slew is Possible @@ -1455,12 +1459,12 @@ namespace ASCOM.Meade.net break; case "1": //Below Horizon - string belowHorizonMessage = SharedResources.ReadTerminated(); + string belowHorizonMessage = _sharedResourcesWrapper.ReadTerminated(); tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowHorizonMessage}\""); throw new ASCOM.InvalidOperationException(belowHorizonMessage); case "2": //Below Horizon - string belowMinimumElevationMessage = SharedResources.ReadTerminated(); + string belowMinimumElevationMessage = _sharedResourcesWrapper.ReadTerminated(); tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowMinimumElevationMessage}\""); throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); default: @@ -1471,7 +1475,7 @@ namespace ASCOM.Meade.net break; case false: - var maResponse = SharedResources.SendChar(":MA#"); + var maResponse = _sharedResourcesWrapper.SendChar(":MA#"); //:MA# Autostar, LX 16”, Autostar II – Slew to target Alt and Az //Returns: //0 - No fault @@ -1508,7 +1512,7 @@ namespace ASCOM.Meade.net tl.LogMessage("SlewToCoordinatesAsync", $"Ra={rightAscension}, Dec={declination}"); CheckConnected("SlewToCoordinatesAsync"); - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { TargetRightAscension = rightAscension; TargetDeclination = declination; @@ -1559,7 +1563,7 @@ namespace ASCOM.Meade.net CheckConnected("Slewing Get"); - var result = SharedResources.SendString(":D#"); + var result = _sharedResourcesWrapper.SendString(":D#"); //:D# Requests a string of bars indicating the distance to the current target location. //Returns: //LX200's – a string of bar characters indicating the distance. @@ -1582,7 +1586,7 @@ namespace ASCOM.Meade.net tl.LogMessage("SyncToCoordinates", $"RA={rightAscension} Dec={declination}"); CheckConnected("SyncToCoordinates"); - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { TargetRightAscension = rightAscension; TargetDeclination = declination; @@ -1596,7 +1600,7 @@ namespace ASCOM.Meade.net tl.LogMessage("SyncToTarget", "Executing"); CheckConnected("SyncToTarget"); - var result = SharedResources.SendString(":CM#"); + var result = _sharedResourcesWrapper.SendString(":CM#"); //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. //Returns: //LX200's - a "#" terminated string with the name of the object that was synced. @@ -1645,7 +1649,7 @@ namespace ASCOM.Meade.net var command = $":Sd{s}{dms}#"; tl.LogMessage("TargetDeclination Set", $"{command}"); - var result = SharedResources.SendChar(command); + var result = _sharedResourcesWrapper.SendChar(command); //:SdsDD*MM# //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting //Returns: @@ -1694,7 +1698,7 @@ namespace ASCOM.Meade.net //todo implement the low precision version var hms = utilities.HoursToHMS(value, ":", ":", ":", 2); - var response = SharedResources.SendChar($":Sr{hms}#"); + var response = _sharedResourcesWrapper.SendChar($":Sr{hms}#"); //:SrHH:MM.T# //:SrHH:MM:SS# //Set target object RA to HH:MM.T or HH: MM: SS depending on the current precision setting. @@ -1753,12 +1757,12 @@ namespace ASCOM.Meade.net switch (value) { case DriveRates.driveSidereal: - SharedResources.SendBlind(":TQ#"); + _sharedResourcesWrapper.SendBlind(":TQ#"); //:TQ# Selects sidereal tracking rate //Returns: Nothing break; case DriveRates.driveLunar: - SharedResources.SendBlind(":TL#"); + _sharedResourcesWrapper.SendBlind(":TL#"); //:TL# Set Lunar Tracking Rage //Returns: Nothing break; @@ -1797,7 +1801,7 @@ namespace ASCOM.Meade.net { CheckConnected("GetUtcCorrection"); - string utcOffSet = SharedResources.SendString(":GG#"); + string utcOffSet = _sharedResourcesWrapper.SendString(":GG#"); //:GG# Get UTC offset time //Returns: sHH# or sHH.H# //The number of decimal hours to add to local time to convert it to UTC. If the number is a whole number the @@ -1822,14 +1826,14 @@ namespace ASCOM.Meade.net tl.LogMessage("UTCDate", "Get started"); - TelescopeDateDetails telescopeDateDetails = SharedResources.Lock(() => + TelescopeDateDetails telescopeDateDetails = _sharedResourcesWrapper.Lock(() => { TelescopeDateDetails tdd = new TelescopeDateDetails(); - tdd.telescopeDate = SharedResources.SendString(":GC#"); + tdd.telescopeDate = _sharedResourcesWrapper.SendString(":GC#"); //:GC# Get current date. //Returns: MM / DD / YY# //The current local calendar date for the telescope. - tdd.telescopeTime = SharedResources.SendString(":GL#"); + tdd.telescopeTime = _sharedResourcesWrapper.SendString(":GL#"); //:GL# Get Local Time in 24 hour format //Returns: HH: MM: SS# //The Local Time in 24 - hour Format @@ -1864,12 +1868,12 @@ namespace ASCOM.Meade.net CheckConnected("UTCDate Set"); - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { var utcCorrection = GetUtcCorrection(); var localDateTime = value - utcCorrection; - var timeResult = SharedResources.SendChar($":SL{localDateTime:HH:mm:ss}#"); + var timeResult = _sharedResourcesWrapper.SendChar($":SL{localDateTime:HH:mm:ss}#"); //:SLHH:MM:SS# //Set the local Time //Returns: @@ -1880,7 +1884,7 @@ namespace ASCOM.Meade.net throw new InvalidOperationException("Failed to set local time"); } - var dateResult = SharedResources.SendChar($":SC{localDateTime:MM/dd/yy}#"); + var dateResult = _sharedResourcesWrapper.SendChar($":SC{localDateTime:MM/dd/yy}#"); //:SCMM/DD/YY# //Change Handbox Date to MM/DD/YY //Returns: @@ -1893,8 +1897,8 @@ namespace ASCOM.Meade.net } //throwing away these two strings which represent - SharedResources.ReadTerminated(); //Updating Planetary Data# - SharedResources.ReadTerminated(); // # + _sharedResourcesWrapper.ReadTerminated(); //Updating Planetary Data# + _sharedResourcesWrapper.ReadTerminated(); // # }); } } @@ -2014,7 +2018,7 @@ namespace ASCOM.Meade.net /// internal void ReadProfile() { - var profileProperties = SharedResources.ReadProfile(); + var profileProperties = _sharedResourcesWrapper.ReadProfile(); tl.Enabled = profileProperties.TraceLogger; comPort = profileProperties.ComPort; } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 75a6f18..f19eddc 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -40,6 +40,7 @@ using ASCOM.DeviceInterface; using System.Globalization; using System.Collections; using System.Reflection; +using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; namespace ASCOM.Meade.net @@ -103,6 +104,8 @@ namespace ASCOM.Meade.net /// internal static TraceLogger tl; + private readonly ISharedResourcesWrapper _sharedResourcesWrapper; + /// /// Initializes a new instance of the class. /// Must be public for COM registration. @@ -117,6 +120,7 @@ namespace ASCOM.Meade.net connectedState = false; // Initialise connected to false utilities = new Util(); //Initialise util object astroUtilities = new AstroUtils(); // Initialise astro utilities object + _sharedResourcesWrapper = new SharedResourcesWrapper(); tl.LogMessage("Focuser", "Completed initialisation"); } @@ -137,7 +141,7 @@ namespace ASCOM.Meade.net public void SetupDialog() { tl.LogMessage("SetupDialog", "Opening setup dialog"); - SharedResources.SetupDialog(); + _sharedResourcesWrapper.SetupDialog(); ReadProfile(); tl.LogMessage("SetupDialog", "complete"); } @@ -162,7 +166,7 @@ namespace ASCOM.Meade.net CheckConnected("CommandBlind"); // Call CommandString and return as soon as it finishes //this.CommandString(command, raw); - SharedResources.SendBlind(command); + _sharedResourcesWrapper.SendBlind(command); // or //throw new ASCOM.MethodNotImplementedException("CommandBlind"); // DO NOT have both these sections! One or the other @@ -184,7 +188,7 @@ namespace ASCOM.Meade.net // it's a good idea to put all the low level communication with the device here, // then all communication calls this function // you need something to ensure that only one command is in progress at a time - return SharedResources.SendString(command); + return _sharedResourcesWrapper.SendString(command); throw new ASCOM.MethodNotImplementedException("CommandString"); } @@ -218,7 +222,7 @@ namespace ASCOM.Meade.net { try { - SharedResources.Connect("Serial"); + _sharedResourcesWrapper.Connect("Serial"); try { SelectSite(1); @@ -228,7 +232,7 @@ namespace ASCOM.Meade.net } catch (Exception) { - SharedResources.Disconnect("Serial"); + _sharedResourcesWrapper.Disconnect("Serial"); throw; } } @@ -240,7 +244,7 @@ namespace ASCOM.Meade.net else { LogMessage("Connected Set", "Disconnecting from port {0}", comPort); - SharedResources.Disconnect("Serial"); + _sharedResourcesWrapper.Disconnect("Serial"); connectedState = false; } } @@ -248,9 +252,9 @@ namespace ASCOM.Meade.net private void SetLongFormat(bool setLongFormat) { - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { - var result = SharedResources.SendString(":GZ#"); + var result = _sharedResourcesWrapper.SendString(":GZ#"); //:GZ# Get telescope azimuth //Returns: DDD*MM#T or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. @@ -260,7 +264,7 @@ namespace ASCOM.Meade.net if (isLongFormat != setLongFormat) { utilities.WaitForMilliseconds(500); - SharedResources.SendBlind(":U#"); + _sharedResourcesWrapper.SendBlind(":U#"); //:U# Toggle between low/hi precision positions //Low - RA displays and messages HH:MM.T sDD*MM //High - Dec / Az / El displays and messages HH:MM: SS sDD*MM:SS @@ -271,7 +275,7 @@ namespace ASCOM.Meade.net private void SelectSite(int site) { - SharedResources.SendBlind($":W{site}#"); + _sharedResourcesWrapper.SendBlind($":W{site}#"); //:W# //Set current site to, an ASCII digit in the range 1..4 //Returns: Nothing @@ -354,7 +358,7 @@ namespace ASCOM.Meade.net Stopwatch stopwatch = Stopwatch.StartNew(); while (stopwatch.ElapsedMilliseconds < 1000) { - SharedResources.SendBlind(":FQ#"); + _sharedResourcesWrapper.SendBlind(":FQ#"); //:FQ# Halt Focuser Motion //Returns: Nothing @@ -436,9 +440,9 @@ namespace ASCOM.Meade.net private void MoveFocuser(bool directionOut, int steps) { - SharedResources.Lock(() => + _sharedResourcesWrapper.Lock(() => { - //SharedResources.SendBlind(":FF#"); + //_sharedResourcesWrapper.SendBlind(":FF#"); //:FF# Set Focus speed to fastest setting //Returns: Nothing @@ -454,7 +458,7 @@ namespace ASCOM.Meade.net Stopwatch stopwatch = Stopwatch.StartNew(); while (stopwatch.ElapsedMilliseconds < steps) { - SharedResources.SendBlind(directionOut ? ":F+#" : ":F-#"); + _sharedResourcesWrapper.SendBlind(directionOut ? ":F+#" : ":F-#"); //:F+# Start Focuser moving inward (toward objective) //Returns: None @@ -630,7 +634,7 @@ namespace ASCOM.Meade.net /// internal void ReadProfile() { - var profileProperties = SharedResources.ReadProfile(); + var profileProperties = _sharedResourcesWrapper.ReadProfile(); tl.Enabled = profileProperties.TraceLogger; comPort = profileProperties.ComPort; } diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index e1d415b..b11387a 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -103,6 +103,7 @@ + Designer frmMain.cs diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 6afc65e..9e04d32 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -233,15 +233,7 @@ namespace ASCOM.Meade.net } #endregion - - #region AutostarProducts - - public const string AUTOSTAR497 = "Autostar"; - - public const string AUTOSTAR497_31EE = "31Ee"; - - #endregion - + #region Multi Driver handling public static string ProductName { get; private set; } = string.Empty; diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs new file mode 100644 index 0000000..90caa72 --- /dev/null +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ASCOM.Meade.net.Wrapper +{ + public interface ISharedResourcesWrapper + { + string AUTOSTAR497 { get; } + string AUTOSTAR497_31EE { get; } + + void Connect(string deviceId); + void Disconnect(string deviceId); + + string ProductName { get; } + + string FirmwareVersion { get; } + + void Lock(Action action); + T Lock(Func func); + + string SendString(string message); + void SendBlind(string message); + string SendChar(string message); + + string ReadTerminated(); + + ProfileProperties ReadProfile(); + + void SetupDialog(); + } + + public class SharedResourcesWrapper : ISharedResourcesWrapper + { + #region AutostarProducts + + public string AUTOSTAR497 => "Autostar"; + + public string AUTOSTAR497_31EE => "31Ee"; + + #endregion + + public void Connect(string deviceId) + { + SharedResources.Connect( deviceId); + } + + public void Disconnect(string deviceId) + { + SharedResources.Disconnect(deviceId); + } + + public string ProductName => SharedResources.ProductName; + + public string FirmwareVersion => SharedResources.FirmwareVersion; + + public void Lock(Action action) + { + SharedResources.Lock(action); + } + + public T Lock(Func func) + { + return SharedResources.Lock(func); + } + + public string SendString(string message) + { + return SharedResources.SendString(message); + } + + public void SendBlind(string message) + { + SharedResources.SendBlind(message); + } + + public string SendChar(string message) + { + return SharedResources.SendChar(message); + } + + public string ReadTerminated() + { + return SharedResources.ReadTerminated(); + } + + public ProfileProperties ReadProfile() + { + return SharedResources.ReadProfile(); + } + + public void SetupDialog() + { + SharedResources.SetupDialog(); + } + } +} From ca3dd0e4fd0399c8ba42396017907bd0c4bb73a1 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 8 Jul 2019 17:30:02 +0100 Subject: [PATCH 058/109] Refactored code to use interrfaces in declarations, rather than concrete classes. --- Meade.net.Telescope/AstroMaths.cs | 2 +- Meade.net.Telescope/IAstroMaths.cs | 17 +++ .../Meade.net.Telescope.csproj | 1 + Meade.net.Telescope/Telescope.cs | 118 +++++------------- Meade.net.focuser/Focuser.cs | 75 ++--------- 5 files changed, 64 insertions(+), 149 deletions(-) create mode 100644 Meade.net.Telescope/IAstroMaths.cs diff --git a/Meade.net.Telescope/AstroMaths.cs b/Meade.net.Telescope/AstroMaths.cs index 7123eaa..f197b5f 100644 --- a/Meade.net.Telescope/AstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths.cs @@ -24,7 +24,7 @@ namespace ASCOM.Meade.net public EquatorialCoordinates equatorialCoordinates { get; set; } } - public class AstroMaths + public class AstroMaths : IAstroMaths { //returns the decimal hour angle for given right ascension on a given datetime for a given logitude. diff --git a/Meade.net.Telescope/IAstroMaths.cs b/Meade.net.Telescope/IAstroMaths.cs new file mode 100644 index 0000000..970942c --- /dev/null +++ b/Meade.net.Telescope/IAstroMaths.cs @@ -0,0 +1,17 @@ +using System; + +namespace ASCOM.Meade.net +{ + public interface IAstroMaths + { + double RightAscensionToHourAngle(DateTime utcDateTime, double longitude, double rightAscension); + double HourAngleToRightAscension(DateTime utcDateTime, double longitude, double hourAngle ); + EquatorialCoordinates ConvertHozToEq( DateTime utcDateTime, double latitude, double longitude, HorizonCoordinates altAz); + HorizonCoordinates ConvertEqToHoz(double hourAngle, double latitude, EquatorialCoordinates raDec); + double DegreesToRadians(double degrees); + double RadiansToDegrees(double radians); + double DateTimeToDecimalHours( DateTime utcDateTime); + double UTtoGST(DateTime utcDateTime); + double GSTtoLST(double gst, double longitude); + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 35f9b0b..9d4be6b 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -89,6 +89,7 @@ + diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index b2b1e0e..32ee3b6 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1,39 +1,7 @@ -//tabs=4 -// -------------------------------------------------------------------------------- -// TODO fill in this information for your driver, then remove this line! -// -// ASCOM Telescope driver for Meade.net -// -// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam -// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam -// erat, sed diam voluptua. At vero eos et accusam et justo duo -// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata -// sanctus est Lorem ipsum dolor sit amet. -// -// Implements: ASCOM Telescope interface version: -// Author: (XXX) Your N. Here -// -// Edit Log: -// -// Date Who Vers Description -// ----------- --- ----- ------------------------------------------------------- -// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template -// -------------------------------------------------------------------------------- -// - - -// This is used to define code in the template that is specific to one class implementation -// unused code canbe deleted and this definition removed. #define Telescope using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; using System.Runtime.InteropServices; - -using ASCOM; -using ASCOM.Astrometry; using ASCOM.Astrometry.AstroUtils; using ASCOM.Utilities; using ASCOM.DeviceInterface; @@ -41,6 +9,7 @@ using System.Globalization; using System.Collections; using System.Reflection; using ASCOM.Meade.net.Wrapper; +using ASCOM.Utilities.Interfaces; namespace ASCOM.Meade.net { @@ -77,29 +46,20 @@ namespace ASCOM.Meade.net /// private static string driverDescription = "Meade Generic"; - internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence - internal static string comPortDefault = "COM1"; - internal static string traceStateProfileName = "Trace Level"; - internal static string traceStateDefault = "false"; - internal static string comPort; // Variables to hold the currrent device configuration - /// - /// Private variable to hold the connected state - /// - private bool _connectedState; - /// /// Private variable to hold an ASCOM Utilities object /// - private Util utilities; + private readonly IUtil _utilities; + private readonly IUtilExtra _utilitiesExtra; /// /// Private variable to hold an ASCOM AstroUtilities object to provide the Range method /// - private AstroUtils astroUtilities; + private readonly IAstroUtils _astroUtilities; - private readonly AstroMaths _astroMaths; + private readonly IAstroMaths _astroMaths; /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) @@ -119,9 +79,10 @@ namespace ASCOM.Meade.net tl.LogMessage("Telescope", "Starting initialisation"); - _connectedState = false; // Initialise connected to false - utilities = new Util(); //Initialise util object - astroUtilities = new AstroUtils(); // Initialise astro utilities object + IsConnected = false; // Initialise connected to false + _utilities = new Util(); //Initialise util object + _utilitiesExtra = new Util(); //Initialise util object + _astroUtilities = new AstroUtils(); // Initialise astro utilities object _sharedResourcesWrapper = new SharedResourcesWrapper(); //TODO: Implement your additional construction here @@ -297,10 +258,6 @@ namespace ASCOM.Meade.net tl.Enabled = false; tl.Dispose(); tl = null; - utilities.Dispose(); - utilities = null; - astroUtilities.Dispose(); - astroUtilities = null; } public bool Connected @@ -333,7 +290,7 @@ namespace ASCOM.Meade.net _userNewerPulseGuiding = IsNewPulseGuidingSupported(); - _connectedState = true; + IsConnected = true; } catch (Exception) { @@ -350,7 +307,7 @@ namespace ASCOM.Meade.net { LogMessage("Connected Set", "Disconnecting from port {0}", comPort); _sharedResourcesWrapper.Disconnect("Serial"); - _connectedState = false; + IsConnected = false; } } } @@ -385,7 +342,7 @@ namespace ASCOM.Meade.net if (isLongFormat != setLongFormat) { - utilities.WaitForMilliseconds(500); + _utilities.WaitForMilliseconds(500); _sharedResourcesWrapper.SendBlind(":U#"); //:U# Toggle between low/hi precision positions //Low - RA displays and messages HH:MM.T sDD*MM @@ -835,9 +792,9 @@ namespace ASCOM.Meade.net //Returns: sDD* MM# or sDD*MM’SS# //Depending upon the current precision setting for the telescope. - double declination = utilities.DMSToDegrees(result); + double declination = _utilities.DMSToDegrees(result); - tl.LogMessage("Declination", "Get - " + utilities.DegreesToDMS(declination, ":", ":")); + tl.LogMessage("Declination", "Get - " + _utilitiesExtra.DegreesToDMS(declination, ":", ":")); return declination; } } @@ -1090,7 +1047,7 @@ namespace ASCOM.Meade.net //Returns – Nothing //LX200 – Not Supported - utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed + _utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed } else { @@ -1108,7 +1065,7 @@ namespace ASCOM.Meade.net //Returns: Nothing //:Mw# Move Telescope West at current slew rate //Returns: Nothing - utilities.WaitForMilliseconds(duration); + _utilities.WaitForMilliseconds(duration); _sharedResourcesWrapper.SendBlind($":Q{d}#"); //:Qe# Halt eastward Slews //Returns: Nothing @@ -1132,9 +1089,9 @@ namespace ASCOM.Meade.net //Returns: HH: MM.T# or HH:MM:SS# //Depending which precision is set for the telescope - double rightAscension = utilities.HMSToHours(result); + double rightAscension = _utilities.HMSToHours(result); - tl.LogMessage("RightAscension", "Get - " + utilities.HoursToHMS(rightAscension)); + tl.LogMessage("RightAscension", "Get - " + _utilitiesExtra.HoursToHMS(rightAscension)); return rightAscension; } } @@ -1182,7 +1139,7 @@ namespace ASCOM.Meade.net double siderealTime = 0.0; using (var novas = new ASCOM.Astrometry.NOVAS.NOVAS31()) { - var jd = utilities.DateUTCToJulian(DateTime.UtcNow); + var jd = _utilities.DateUTCToJulian(DateTime.UtcNow); novas.SiderealTime(jd, 0, novas.DeltaT(jd), ASCOM.Astrometry.GstType.GreenwichApparentSiderealTime, ASCOM.Astrometry.Method.EquinoxBased, @@ -1193,7 +1150,7 @@ namespace ASCOM.Meade.net siderealTime += SiteLongitude / 360.0 * 24.0; // Reduce to the range 0 to 24 hours - siderealTime = astroUtilities.ConditionRA(siderealTime); + siderealTime = _astroUtilities.ConditionRA(siderealTime); tl.LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); return siderealTime; @@ -1225,13 +1182,13 @@ namespace ASCOM.Meade.net //Returns: sDD* MM# //The latitude of the current site. Positive inplies North latitude. - var siteLatitude = utilities.DMSToDegrees(latitude); - tl.LogMessage("SiteLatitude Get", $"{utilities.DegreesToDMS(siteLatitude)}"); + var siteLatitude = _utilities.DMSToDegrees(latitude); + tl.LogMessage("SiteLatitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLatitude)}"); return siteLatitude; } set { - tl.LogMessage("SiteLatitude Set", $"{utilities.DegreesToDMS(value)}"); + tl.LogMessage("SiteLatitude Set", $"{_utilitiesExtra.DegreesToDMS(value)}"); CheckConnected("SiteLatitude Set"); @@ -1266,21 +1223,21 @@ namespace ASCOM.Meade.net //:Gg# Get Current Site Longitude //Returns: sDDD* MM# //The current site Longitude. East Longitudes are expressed as negative - double siteLongitude = utilities.DMSToDegrees(longitude); + double siteLongitude = _utilities.DMSToDegrees(longitude); if (siteLongitude > 180) siteLongitude = siteLongitude - 360; siteLongitude = -siteLongitude; - tl.LogMessage("SiteLongitude Get", $"{utilities.DegreesToDMS(siteLongitude)}"); + tl.LogMessage("SiteLongitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLongitude)}"); return siteLongitude; } set { var newLongitude = value; - tl.LogMessage("SiteLongitude Set", $"{utilities.DegreesToDMS(newLongitude)}"); + tl.LogMessage("SiteLongitude Set", $"{_utilitiesExtra.DegreesToDMS(newLongitude)}"); CheckConnected("SiteLongitude Set"); @@ -1332,7 +1289,7 @@ namespace ASCOM.Meade.net while (Slewing) //wait for slew to complete { - utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); + _utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); } } @@ -1350,7 +1307,7 @@ namespace ASCOM.Meade.net //todo this serial string does not work. Calculate the EQ version instead. - var dms = utilities.DegreesToDMS(value, "*", "'", "",0); + var dms = _utilities.DegreesToDMS(value, "*", "'", "",0); var s = value < 0 ? string.Empty : "+"; var result = _sharedResourcesWrapper.SendChar($":Sa{s}{dms}#"); @@ -1379,7 +1336,7 @@ namespace ASCOM.Meade.net //todo this serial string does not work. Calculate the EQ version instead. - var dms = utilities.DegreesToDM(value, "*" ); + var dms = _utilitiesExtra.DegreesToDM(value, "*" ); var result = _sharedResourcesWrapper.SendChar($":Sz{dms}#"); //:SzDDD*MM# @@ -1501,7 +1458,7 @@ namespace ASCOM.Meade.net while (Slewing) //wait for slew to complete { - utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); + _utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); } tl.LogMessage("SlewToCoordinates", $"Slewing completed new coordinates Ra={RightAscension}, Dec={Declination}"); @@ -1530,7 +1487,7 @@ namespace ASCOM.Meade.net while (Slewing) { - utilities.WaitForMilliseconds(200); + _utilities.WaitForMilliseconds(200); } } @@ -1643,7 +1600,7 @@ namespace ASCOM.Meade.net CheckConnected("TargetDeclination Set"); - var dms = utilities.DegreesToDMS(value, "*", ":", ":", 2); + var dms = _utilities.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? string.Empty : "+"; var command = $":Sd{s}{dms}#"; @@ -1697,7 +1654,7 @@ namespace ASCOM.Meade.net CheckConnected("TargetRightAscension Set"); //todo implement the low precision version - var hms = utilities.HoursToHMS(value, ":", ":", ":", 2); + var hms = _utilities.HoursToHMS(value, ":", ":", ":", 2); var response = _sharedResourcesWrapper.SendChar($":Sr{hms}#"); //:SrHH:MM.T# //:SrHH:MM:SS# @@ -1992,14 +1949,7 @@ namespace ASCOM.Meade.net /// /// Returns true if there is a valid connection to the driver hardware /// - private bool IsConnected - { - get - { - // TODO check that the driver hardware connection exists and is connected to the hardware - return _connectedState; - } - } + private bool IsConnected { get; set; } /// /// Use this function to throw an exception if we aren't connected to the hardware diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index f19eddc..a0bd42d 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -1,29 +1,3 @@ -//tabs=4 -// -------------------------------------------------------------------------------- -// TODO fill in this information for your driver, then remove this line! -// -// ASCOM Focuser driver for Meade.net -// -// Description: Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam -// nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam -// erat, sed diam voluptua. At vero eos et accusam et justo duo -// dolores et ea rebum. Stet clita kasd gubergren, no sea takimata -// sanctus est Lorem ipsum dolor sit amet. -// -// Implements: ASCOM Focuser interface version: -// Author: (XXX) Your N. Here -// -// Edit Log: -// -// Date Who Vers Description -// ----------- --- ----- ------------------------------------------------------- -// dd-mmm-yyyy XXX 6.0.0 Initial edit, created from ASCOM driver template -// -------------------------------------------------------------------------------- -// - - -// This is used to define code in the template that is specific to one class implementation -// unused code canbe deleted and this definition removed. #define Focuser using System; @@ -77,27 +51,12 @@ namespace ASCOM.Meade.net /// private static string driverDescription = "Meade Generic"; - internal static string comPortProfileName = "COM Port"; // Constants used for Profile persistence - internal static string comPortDefault = "COM1"; - internal static string traceStateProfileName = "Trace Level"; - internal static string traceStateDefault = "false"; - internal static string comPort; // Variables to hold the currrent device configuration - /// - /// Private variable to hold the connected state - /// - private bool connectedState; - /// /// Private variable to hold an ASCOM Utilities object /// - private Util utilities; - - /// - /// Private variable to hold an ASCOM AstroUtilities object to provide the Range method - /// - private AstroUtils astroUtilities; + private readonly IUtil _utilities; /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) @@ -117,9 +76,8 @@ namespace ASCOM.Meade.net tl.LogMessage("Focuser", "Starting initialisation"); - connectedState = false; // Initialise connected to false - utilities = new Util(); //Initialise util object - astroUtilities = new AstroUtils(); // Initialise astro utilities object + IsConnected = false; // Initialise connected to false + _utilities = new Util(); //Initialise util object _sharedResourcesWrapper = new SharedResourcesWrapper(); tl.LogMessage("Focuser", "Completed initialisation"); @@ -199,10 +157,6 @@ namespace ASCOM.Meade.net tl.Enabled = false; tl.Dispose(); tl = null; - utilities.Dispose(); - utilities = null; - astroUtilities.Dispose(); - astroUtilities = null; } public bool Connected @@ -228,7 +182,7 @@ namespace ASCOM.Meade.net SelectSite(1); SetLongFormat(true); - connectedState = true; + IsConnected = true; } catch (Exception) { @@ -245,7 +199,7 @@ namespace ASCOM.Meade.net { LogMessage("Connected Set", "Disconnecting from port {0}", comPort); _sharedResourcesWrapper.Disconnect("Serial"); - connectedState = false; + IsConnected = false; } } } @@ -263,7 +217,7 @@ namespace ASCOM.Meade.net if (isLongFormat != setLongFormat) { - utilities.WaitForMilliseconds(500); + _utilities.WaitForMilliseconds(500); _sharedResourcesWrapper.SendBlind(":U#"); //:U# Toggle between low/hi precision positions //Low - RA displays and messages HH:MM.T sDD*MM @@ -362,7 +316,7 @@ namespace ASCOM.Meade.net //:FQ# Halt Focuser Motion //Returns: Nothing - utilities.WaitForMilliseconds(250); + _utilities.WaitForMilliseconds(250); } } @@ -452,7 +406,7 @@ namespace ASCOM.Meade.net //:F# Autostar, Autostar II – set focuser speed to where is an ASCII digit 1..4 //Returns: Nothing //All others – Not Supported - utilities.WaitForMilliseconds(100); + _utilities.WaitForMilliseconds(100); //A Single focus command sometimes gets lost on the #909, so sending lots of them solves the issue. Stopwatch stopwatch = Stopwatch.StartNew(); @@ -465,13 +419,13 @@ namespace ASCOM.Meade.net //:F-# Start Focuser moving outward (away from objective) //Returns: None - utilities.WaitForMilliseconds(250); + _utilities.WaitForMilliseconds(250); } Halt(); //This gives the focuser time to physically stop. - utilities.WaitForMilliseconds(1000); + _utilities.WaitForMilliseconds(1000); }); } @@ -608,14 +562,7 @@ namespace ASCOM.Meade.net /// /// Returns true if there is a valid connection to the driver hardware /// - private bool IsConnected - { - get - { - // TODO check that the driver hardware connection exists and is connected to the hardware - return connectedState; - } - } + private bool IsConnected { get; set; } /// /// Use this function to throw an exception if we aren't connected to the hardware From f8cbc3fa8d88a1208952ed377f15b120318ef82c Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 8 Jul 2019 22:07:35 +0100 Subject: [PATCH 059/109] Changed the initialisation order to avoid issue with ISharedResourcesWrapper being called before it's created. --- Meade.net.Telescope/Telescope.cs | 16 ++++++++-------- Meade.net.focuser/Focuser.cs | 19 +++++++------------ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 32ee3b6..2e698dd 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -74,20 +74,20 @@ namespace ASCOM.Meade.net /// public Telescope() { - tl = new TraceLogger("", "Meade.net.Telescope"); - ReadProfile(); // Read device configuration from the ASCOM Profile store - - tl.LogMessage("Telescope", "Starting initialisation"); - - IsConnected = false; // Initialise connected to false + //todo move this out to IOC _utilities = new Util(); //Initialise util object _utilitiesExtra = new Util(); //Initialise util object _astroUtilities = new AstroUtils(); // Initialise astro utilities object _sharedResourcesWrapper = new SharedResourcesWrapper(); - - //TODO: Implement your additional construction here _astroMaths = new AstroMaths(); + tl = new TraceLogger("", "Meade.net.Telescope"); + tl.LogMessage("Telescope", "Starting initialisation"); + + ReadProfile(); // Read device configuration from the ASCOM Profile store + + IsConnected = false; // Initialise connected to false + tl.LogMessage("Telescope", "Completed initialisation"); } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index a0bd42d..73ebca4 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -1,14 +1,8 @@ #define Focuser using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; using System.Runtime.InteropServices; - -using ASCOM; -using ASCOM.Astrometry; -using ASCOM.Astrometry.AstroUtils; using ASCOM.Utilities; using ASCOM.DeviceInterface; using System.Globalization; @@ -71,15 +65,16 @@ namespace ASCOM.Meade.net /// public Focuser() { - tl = new TraceLogger("", "Meade.net.focusser"); - ReadProfile(); // Read device configuration from the ASCOM Profile store - - tl.LogMessage("Focuser", "Starting initialisation"); - - IsConnected = false; // Initialise connected to false + //todo move this out to IOC _utilities = new Util(); //Initialise util object _sharedResourcesWrapper = new SharedResourcesWrapper(); + tl = new TraceLogger("", "Meade.net.focusser"); + + tl.LogMessage("Focuser", "Starting initialisation"); + ReadProfile(); // Read device configuration from the ASCOM Profile store + IsConnected = false; // Initialise connected to false + tl.LogMessage("Focuser", "Completed initialisation"); } From 465d4cb5d93d0268eadaf1928d9a1b59f80e942e Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 8 Jul 2019 22:17:05 +0100 Subject: [PATCH 060/109] Seperated out the non ioc init code to it's own method --- Meade.net.Telescope/Telescope.cs | 5 +++++ Meade.net.focuser/Focuser.cs | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 2e698dd..886a772 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -81,6 +81,11 @@ namespace ASCOM.Meade.net _sharedResourcesWrapper = new SharedResourcesWrapper(); _astroMaths = new AstroMaths(); + Initialise(); + } + + private void Initialise() + { tl = new TraceLogger("", "Meade.net.Telescope"); tl.LogMessage("Telescope", "Starting initialisation"); diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 73ebca4..62d4ba3 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -68,13 +68,19 @@ namespace ASCOM.Meade.net //todo move this out to IOC _utilities = new Util(); //Initialise util object _sharedResourcesWrapper = new SharedResourcesWrapper(); + + Initialise(); + } + + private void Initialise() + { tl = new TraceLogger("", "Meade.net.focusser"); - + tl.LogMessage("Focuser", "Starting initialisation"); ReadProfile(); // Read device configuration from the ASCOM Profile store IsConnected = false; // Initialise connected to false - + tl.LogMessage("Focuser", "Completed initialisation"); } From c72d2c00fcd5301193058e7c32b8b755046969f9 Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 8 Jul 2019 22:58:02 +0100 Subject: [PATCH 061/109] Finished refactoring needed to allow unit testing. --- .../AstroMath.UnitTests.csproj | 12 +- AstroMath.UnitTests/packages.config | 8 +- .../BootstrapAscomProfileStore.ps1 | 36 +++++ .../Meade.net.Telescope.UnitTests.csproj | 141 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++ .../TelescopeUnitTests.cs | 52 +++++++ Meade.net.Telescope.UnitTests/app.config | 11 ++ Meade.net.Telescope.UnitTests/packages.config | 9 ++ .../BootstrapAscomProfileStore.ps1 | 36 +++++ .../Meade.net.Telescope.csproj | 43 +++++- Meade.net.Telescope/Telescope.cs | 12 ++ Meade.net.Telescope/packages.config | 4 + .../BootstrapAscomProfileStore.ps1 | 36 +++++ Meade.net.focuser/Meade.net.focuser.csproj | 43 +++++- Meade.net.focuser/packages.config | 4 + Meade.net.sln | 15 ++ Meade.net/BootstrapAscomProfileStore.ps1 | 36 +++++ Meade.net/Meade.net.csproj | 39 ++++- Meade.net/packages.config | 4 + 19 files changed, 547 insertions(+), 30 deletions(-) create mode 100644 Meade.net.Telescope.UnitTests/BootstrapAscomProfileStore.ps1 create mode 100644 Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj create mode 100644 Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs create mode 100644 Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs create mode 100644 Meade.net.Telescope.UnitTests/app.config create mode 100644 Meade.net.Telescope.UnitTests/packages.config create mode 100644 Meade.net.Telescope/BootstrapAscomProfileStore.ps1 create mode 100644 Meade.net.Telescope/packages.config create mode 100644 Meade.net.focuser/BootstrapAscomProfileStore.ps1 create mode 100644 Meade.net.focuser/packages.config create mode 100644 Meade.net/BootstrapAscomProfileStore.ps1 create mode 100644 Meade.net/packages.config diff --git a/AstroMath.UnitTests/AstroMath.UnitTests.csproj b/AstroMath.UnitTests/AstroMath.UnitTests.csproj index d066d8f..ad41f58 100644 --- a/AstroMath.UnitTests/AstroMath.UnitTests.csproj +++ b/AstroMath.UnitTests/AstroMath.UnitTests.csproj @@ -54,10 +54,10 @@ - ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll + ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll - - ..\packages\Moq.4.10.1\lib\net45\Moq.dll + + ..\packages\Moq.4.12.0\lib\net45\Moq.dll ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll @@ -65,11 +65,11 @@ - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll diff --git a/AstroMath.UnitTests/packages.config b/AstroMath.UnitTests/packages.config index 22d8680..605fe2b 100644 --- a/AstroMath.UnitTests/packages.config +++ b/AstroMath.UnitTests/packages.config @@ -1,8 +1,8 @@  - - + + - - + + \ No newline at end of file diff --git a/Meade.net.Telescope.UnitTests/BootstrapAscomProfileStore.ps1 b/Meade.net.Telescope.UnitTests/BootstrapAscomProfileStore.ps1 new file mode 100644 index 0000000..213c64d --- /dev/null +++ b/Meade.net.Telescope.UnitTests/BootstrapAscomProfileStore.ps1 @@ -0,0 +1,36 @@ +<# +This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work +without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, +it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on +ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. + +NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. +#> + +$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node +if ($wow) + { + $root = "HKLM:\SOFTWARE\Wow6432Node" + } +else + { + $root = "HKLM:\SOFTWARE" + } +$ascomRoot = $root + "\ASCOM" + +if (Test-Path $ascomRoot) + { + <# Don't upset an already-existing ASCOM registry #> + exit + } + +<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> +New-Item -Path $root -Name ASCOM –Force +$ascomAcl = Get-Acl $ascomRoot +$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") +$ascomAcl.SetAccessRule($aclRule) +$ascomAcl | Set-Acl -Path $ascomRoot + +<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> +New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force +New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj b/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj new file mode 100644 index 0000000..89b3231 --- /dev/null +++ b/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj @@ -0,0 +1,141 @@ + + + + + + Debug + AnyCPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33} + Library + Properties + Meade.net.Telescope.UnitTests + Meade.net.Telescope.UnitTests + v4.7.2 + 512 + true + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll + + + ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll + + + ..\packages\Moq.4.12.0\lib\net45\Moq.dll + + + ..\packages\NUnit.3.12.0\lib\net40\nunit.framework.dll + + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + {64308775-bd4a-469c-bcab-3ed830b811af} + Meade.net.Telescope + + + {3689a2cb-94c5-4012-a5cf-7e7d1dd27143} + Meade.net + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b58554d --- /dev/null +++ b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Meade.net.Telescope.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Meade.net.Telescope.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b7eeeefd-5bff-443d-981c-7b8ab5dfde33")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs new file mode 100644 index 0000000..55c3af3 --- /dev/null +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -0,0 +1,52 @@ +using ASCOM.Astrometry.AstroUtils; +using ASCOM.Meade.net; +using ASCOM.Meade.net.Wrapper; +using ASCOM.Utilities.Interfaces; +using Moq; +using NUnit.Framework; + +namespace Meade.net.Telescope.UnitTests +{ + [TestFixture] + public class TelescopeUnitTests + { + private ASCOM.Meade.net.Telescope _telescope; + private Mock _utilMock; + private Mock _utilExtraMock; + private Mock _astroUtilsMock; + private Mock _sharedResourcesWrapperMock; + private Mock _astroMathsMock; + + private ProfileProperties _profileProperties; + + [SetUp] + public void Setup() + { + _profileProperties = new ProfileProperties(); + _profileProperties.TraceLogger = false; + _profileProperties.ComPort = "TestCom1"; + + _utilMock = new Mock(); + _utilExtraMock = new Mock(); + _astroUtilsMock = new Mock(); + _sharedResourcesWrapperMock = new Mock(); + _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); + + _astroMathsMock = new Mock(); + + _telescope = new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, _sharedResourcesWrapperMock.Object, _astroMathsMock.Object); + } + + [Test] + public void CheckThatClassCreatedProperly() + { + Assert.That(_telescope, Is.Not.Null); + } + + [Test] + public void NotConnectedByDefault() + { + Assert.That(_telescope.Connected, Is.False); + } + } +} diff --git a/Meade.net.Telescope.UnitTests/app.config b/Meade.net.Telescope.UnitTests/app.config new file mode 100644 index 0000000..312e994 --- /dev/null +++ b/Meade.net.Telescope.UnitTests/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Meade.net.Telescope.UnitTests/packages.config b/Meade.net.Telescope.UnitTests/packages.config new file mode 100644 index 0000000..b360f81 --- /dev/null +++ b/Meade.net.Telescope.UnitTests/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Telescope/BootstrapAscomProfileStore.ps1 b/Meade.net.Telescope/BootstrapAscomProfileStore.ps1 new file mode 100644 index 0000000..213c64d --- /dev/null +++ b/Meade.net.Telescope/BootstrapAscomProfileStore.ps1 @@ -0,0 +1,36 @@ +<# +This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work +without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, +it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on +ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. + +NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. +#> + +$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node +if ($wow) + { + $root = "HKLM:\SOFTWARE\Wow6432Node" + } +else + { + $root = "HKLM:\SOFTWARE" + } +$ascomRoot = $root + "\ASCOM" + +if (Test-Path $ascomRoot) + { + <# Don't upset an already-existing ASCOM registry #> + exit + } + +<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> +New-Item -Path $root -Name ASCOM –Force +$ascomAcl = Get-Acl $ascomRoot +$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") +$ascomAcl.SetAccessRule($aclRule) +$ascomAcl | Set-Acl -Path $ascomRoot + +<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> +New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force +New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 9d4be6b..6f0fdde 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -68,14 +68,39 @@ x86 - - - - - - - - + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll + @@ -116,6 +141,8 @@ + + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 886a772..061bf0f 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -84,8 +84,20 @@ namespace ASCOM.Meade.net Initialise(); } + public Telescope( IUtil util, IUtilExtra utilExtra, IAstroUtils astroUtilities, ISharedResourcesWrapper sharedResourcesWrapper, IAstroMaths astroMaths) + { + _utilities = util; //Initialise util object + _utilitiesExtra = utilExtra; //Initialise util object + _astroUtilities = astroUtilities; // Initialise astro utilities object + _sharedResourcesWrapper = sharedResourcesWrapper; + _astroMaths = astroMaths; + + Initialise(); + } + private void Initialise() { + //todo move the TraceLogger out to a factory class. tl = new TraceLogger("", "Meade.net.Telescope"); tl.LogMessage("Telescope", "Starting initialisation"); diff --git a/Meade.net.Telescope/packages.config b/Meade.net.Telescope/packages.config new file mode 100644 index 0000000..a842451 --- /dev/null +++ b/Meade.net.Telescope/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Meade.net.focuser/BootstrapAscomProfileStore.ps1 b/Meade.net.focuser/BootstrapAscomProfileStore.ps1 new file mode 100644 index 0000000..213c64d --- /dev/null +++ b/Meade.net.focuser/BootstrapAscomProfileStore.ps1 @@ -0,0 +1,36 @@ +<# +This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work +without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, +it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on +ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. + +NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. +#> + +$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node +if ($wow) + { + $root = "HKLM:\SOFTWARE\Wow6432Node" + } +else + { + $root = "HKLM:\SOFTWARE" + } +$ascomRoot = $root + "\ASCOM" + +if (Test-Path $ascomRoot) + { + <# Don't upset an already-existing ASCOM registry #> + exit + } + +<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> +New-Item -Path $root -Name ASCOM –Force +$ascomAcl = Get-Acl $ascomRoot +$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") +$ascomAcl.SetAccessRule($aclRule) +$ascomAcl | Set-Acl -Path $ascomRoot + +<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> +New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force +New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/Meade.net.focuser/Meade.net.focuser.csproj b/Meade.net.focuser/Meade.net.focuser.csproj index bafde48..d161efc 100644 --- a/Meade.net.focuser/Meade.net.focuser.csproj +++ b/Meade.net.focuser/Meade.net.focuser.csproj @@ -80,14 +80,39 @@ MinimumRecommendedRules.ruleset - - - - - - - - + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll + @@ -124,6 +149,8 @@ + + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/Meade.net.focuser/packages.config b/Meade.net.focuser/packages.config new file mode 100644 index 0000000..a842451 --- /dev/null +++ b/Meade.net.focuser/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Meade.net.sln b/Meade.net.sln index 96aacec..a77a62d 100644 --- a/Meade.net.sln +++ b/Meade.net.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AstroMath.UnitTests", "Astr EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Meade.net.Setup", "Meade.net.Setup\Meade.net.Setup.wixproj", "{8EEB5C25-8394-4257-8E57-CDED47CB6F1B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meade.net.Telescope.UnitTests", "Meade.net.Telescope.UnitTests\Meade.net.Telescope.UnitTests.csproj", "{B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,6 +108,18 @@ Global {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x64.ActiveCfg = Release|x86 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x86.ActiveCfg = Release|x86 {8EEB5C25-8394-4257-8E57-CDED47CB6F1B}.Release|x86.Build.0 = Release|x86 + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|x64.ActiveCfg = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|x64.Build.0 = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|x86.ActiveCfg = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Debug|x86.Build.0 = Debug|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|Any CPU.Build.0 = Release|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|x64.ActiveCfg = Release|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|x64.Build.0 = Release|Any CPU + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|x86.ActiveCfg = Release|x86 + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -114,6 +128,7 @@ Global {D5207217-61C7-4E94-8097-91DBACE57D2A} = {BF650D97-AF98-4638-9C55-21311C6D88DA} {AABC96B8-C462-4B3A-9B5F-2929E3CB7A49} = {BF650D97-AF98-4638-9C55-21311C6D88DA} {AD4959DD-33D7-4C3F-8DB0-7361D8E74A95} = {0958D817-269C-44BE-BEFB-F3E6A409DE91} + {B7EEEEFD-5BFF-443D-981C-7B8AB5DFDE33} = {0958D817-269C-44BE-BEFB-F3E6A409DE91} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3C0509DC-C7F5-48DC-920D-DCFD9C879BD2} diff --git a/Meade.net/BootstrapAscomProfileStore.ps1 b/Meade.net/BootstrapAscomProfileStore.ps1 new file mode 100644 index 0000000..213c64d --- /dev/null +++ b/Meade.net/BootstrapAscomProfileStore.ps1 @@ -0,0 +1,36 @@ +<# +This script initializes a bare minimum set of registry entries required for ASCOM.Utilities.Profile to work +without throwing any exceptions. When building on a build server, or on a computer without the ASCOM Platform installed, +it may be useful to execute this script as a build step prior to running any unit tests, or calling any code that relies on +ASCOM.Utilities.Profile. The alternative is to install the ASCOM Platform on the build agent. + +NOTE: This script equires elevated permissions because it creates registry keys in the LocalMachine hive. +#> + +$wow = Test-Path HKLM:\SOFTWARE\Wow6432Node +if ($wow) + { + $root = "HKLM:\SOFTWARE\Wow6432Node" + } +else + { + $root = "HKLM:\SOFTWARE" + } +$ascomRoot = $root + "\ASCOM" + +if (Test-Path $ascomRoot) + { + <# Don't upset an already-existing ASCOM registry #> + exit + } + +<# Create the ASCOM root key and set it's ACL to allow all users read/write access #> +New-Item -Path $root -Name ASCOM –Force +$ascomAcl = Get-Acl $ascomRoot +$aclRule = New-Object System.Security.AccessControl.RegistryAccessRule ("Users","FullControl","Allow") +$ascomAcl.SetAccessRule($aclRule) +$ascomAcl | Set-Acl -Path $ascomRoot + +<# Now create the bare minimum keys required so that ASCOM.Utilities.Profile doesn't crash and burn #> +New-ItemProperty -Path $ascomRoot -Name PlatformVersion -Value "6.1" -PropertyType String –Force +New-ItemProperty -Path $ascomRoot -Name SerTraceFile -Value "C:\SerialTraceAuto.txt" -PropertyType String –Force diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index b11387a..05e64fd 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -83,10 +83,39 @@ MinimumRecommendedRules.ruleset - - - - + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Astrometry.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Attributes.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Cache.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Controls.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DeviceInterfaces.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.DriverAccess.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Exceptions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Internal.Extensions.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.SettingsProvider.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.dll + + + ..\packages\ASCOM.Platform.6.4.2\lib\net40\ASCOM.Utilities.Video.dll + @@ -134,6 +163,8 @@ + + diff --git a/Meade.net/packages.config b/Meade.net/packages.config new file mode 100644 index 0000000..a842451 --- /dev/null +++ b/Meade.net/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 44e02dda1d8b5f271ff990a6264f431a05dcde31 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 9 Jul 2019 18:05:12 +0100 Subject: [PATCH 062/109] Added unit test for setup dialog. --- .../Meade.net.Telescope.UnitTests.csproj | 1 + Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs | 11 +++++++++++ Meade.net.Telescope/Telescope.cs | 5 +++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj b/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj index 89b3231..23613aa 100644 --- a/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj +++ b/Meade.net.Telescope.UnitTests/Meade.net.Telescope.UnitTests.csproj @@ -26,6 +26,7 @@ prompt 4 false + x86 pdbonly diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 55c3af3..a427f0c 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -48,5 +48,16 @@ namespace Meade.net.Telescope.UnitTests { Assert.That(_telescope.Connected, Is.False); } + + [Test] + public void SetupDialog() + { + _sharedResourcesWrapperMock.Verify(x => x.ReadProfile(), Times.Once); + + _telescope.SetupDialog(); + + _sharedResourcesWrapperMock.Verify( x => x.SetupDialog(), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.ReadProfile(), Times.Exactly(2)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 061bf0f..b0987af 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -75,8 +75,9 @@ namespace ASCOM.Meade.net public Telescope() { //todo move this out to IOC - _utilities = new Util(); //Initialise util object - _utilitiesExtra = new Util(); //Initialise util object + var util = new Util(); //Initialise util object + _utilities = util; + _utilitiesExtra = util; //Initialise util object _astroUtilities = new AstroUtils(); // Initialise astro utilities object _sharedResourcesWrapper = new SharedResourcesWrapper(); _astroMaths = new AstroMaths(); From 9049412acc8b6b37842eb25323281c87fea8d5de Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 9 Jul 2019 18:06:44 +0100 Subject: [PATCH 063/109] Checked in NCrunch files needed to run unit tests properly. Note: Run Visual Studio in Administrator mode --- .../Meade.net.Telescope.v3.ncrunchproject | 5 +++++ .../Meade.net.focuser.v3.ncrunchproject | 5 +++++ Meade.net.v3.ncrunchsolution | 7 +++++++ Meade.net.v3.ncrunchsolution.user | 15 +++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 Meade.net.Telescope/Meade.net.Telescope.v3.ncrunchproject create mode 100644 Meade.net.focuser/Meade.net.focuser.v3.ncrunchproject create mode 100644 Meade.net.v3.ncrunchsolution create mode 100644 Meade.net.v3.ncrunchsolution.user diff --git a/Meade.net.Telescope/Meade.net.Telescope.v3.ncrunchproject b/Meade.net.Telescope/Meade.net.Telescope.v3.ncrunchproject new file mode 100644 index 0000000..54c2f06 --- /dev/null +++ b/Meade.net.Telescope/Meade.net.Telescope.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + x86 + + \ No newline at end of file diff --git a/Meade.net.focuser/Meade.net.focuser.v3.ncrunchproject b/Meade.net.focuser/Meade.net.focuser.v3.ncrunchproject new file mode 100644 index 0000000..54c2f06 --- /dev/null +++ b/Meade.net.focuser/Meade.net.focuser.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + x86 + + \ No newline at end of file diff --git a/Meade.net.v3.ncrunchsolution b/Meade.net.v3.ncrunchsolution new file mode 100644 index 0000000..e4047c2 --- /dev/null +++ b/Meade.net.v3.ncrunchsolution @@ -0,0 +1,7 @@ + + + True + True + True + + \ No newline at end of file diff --git a/Meade.net.v3.ncrunchsolution.user b/Meade.net.v3.ncrunchsolution.user new file mode 100644 index 0000000..b162f35 --- /dev/null +++ b/Meade.net.v3.ncrunchsolution.user @@ -0,0 +1,15 @@ + + + True + Run all tests automatically [Global] + 25 + + false + false + true + true + false + + 451 + + \ No newline at end of file From feb69c970f6a5485a64201382e8c71e422d98602 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 9 Jul 2019 21:36:44 +0100 Subject: [PATCH 064/109] Added more unit tests and refactored AstroMaths to be in a sub folder --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 1 + .../TelescopeUnitTests.cs | 77 ++++++++++++++++++- .../AstroMaths/AltitudeData.cs | 12 +++ .../{ => AstroMaths}/AstroMaths.cs | 23 +----- .../AstroMaths/EquatorialCoordinates.cs | 8 ++ .../AstroMaths/HorizonCoordinates.cs | 8 ++ .../{ => AstroMaths}/IAstroMaths.cs | 2 +- .../Meade.net.Telescope.csproj | 7 +- Meade.net.Telescope/Telescope.cs | 9 ++- Meade.net.v3.ncrunchsolution.user | 1 + 10 files changed, 116 insertions(+), 32 deletions(-) create mode 100644 Meade.net.Telescope/AstroMaths/AltitudeData.cs rename Meade.net.Telescope/{ => AstroMaths}/AstroMaths.cs (90%) create mode 100644 Meade.net.Telescope/AstroMaths/EquatorialCoordinates.cs create mode 100644 Meade.net.Telescope/AstroMaths/HorizonCoordinates.cs rename Meade.net.Telescope/{ => AstroMaths}/IAstroMaths.cs (95%) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index cdbe4ad..a890647 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -1,5 +1,6 @@ using System; using ASCOM.Meade.net; +using ASCOM.Meade.net.AstroMaths; using NUnit.Framework; namespace AstroMath.UnitTests diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index a427f0c..d174cec 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,5 +1,8 @@ -using ASCOM.Astrometry.AstroUtils; +using System.Xml.Serialization; +using ASCOM; +using ASCOM.Astrometry.AstroUtils; using ASCOM.Meade.net; +using ASCOM.Meade.net.AstroMaths; using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; using Moq; @@ -34,7 +37,8 @@ namespace Meade.net.Telescope.UnitTests _astroMathsMock = new Mock(); - _telescope = new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, _sharedResourcesWrapperMock.Object, _astroMathsMock.Object); + _telescope = new ASCOM.Meade.net.Telescope(_utilMock.Object, _utilExtraMock.Object, _astroUtilsMock.Object, + _sharedResourcesWrapperMock.Object, _astroMathsMock.Object); } [Test] @@ -56,8 +60,75 @@ namespace Meade.net.Telescope.UnitTests _telescope.SetupDialog(); - _sharedResourcesWrapperMock.Verify( x => x.SetupDialog(), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SetupDialog(), Times.Once); _sharedResourcesWrapperMock.Verify(x => x.ReadProfile(), Times.Exactly(2)); } + + [Test] + public void SupportedActions() + { + var supportedActions = _telescope.SupportedActions; + + Assert.That(supportedActions, Is.Not.Null); + Assert.That(supportedActions.Count, Is.EqualTo(1)); + Assert.That(supportedActions.Contains("handbox"), Is.True); + } + + [Test] + public void Action_Handbox_ReadDisplay() + { + string expectedResult = "test result string"; + _sharedResourcesWrapperMock.Setup(x => x.SendString(It.IsAny())).Returns(expectedResult); + + var actualResult = _telescope.Action("handbox", "readdisplay"); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(":ED#"), Times.Once); + Assert.That(actualResult, Is.EqualTo(expectedResult)); + } + + [TestCase("enter", ":EK13#")] + [TestCase("mode", ":EK9#")] + [TestCase("longMode", ":EK11#")] + [TestCase("goto", ":EK24#")] + [TestCase("0", ":EK48#")] + [TestCase("1", ":EK49#")] + [TestCase("2", ":EK50#")] + [TestCase("3", ":EK51#")] + [TestCase("4", ":EK52#")] + [TestCase("5", ":EK53#")] + [TestCase("6", ":EK54#")] + [TestCase("7", ":EK55#")] + [TestCase("8", ":EK56#")] + [TestCase("9", ":EK57#")] + [TestCase("up", ":EK94#")] + [TestCase("down", ":EK118#")] + [TestCase("back", ":EK87#")] + [TestCase("forward", ":EK69#")] + [TestCase("?", ":EK63#")] + public void Action_Handbox_blindCommands(string action, string expectedString) + { + _telescope.Action("handbox", action); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(expectedString), Times.Once); + } + + [Test] + public void Action_Handbox_nonExistantAction() + { + string actionName = "handbox"; + string actionParameters = "doesnotexist"; + var exception = Assert.Throws(() => { _telescope.Action(actionName, actionParameters); }); + + Assert.That(exception.Message, Is.EqualTo($"Action {actionName}({actionParameters}) is not implemented in this driver is not implemented in this driver.")); + } + + [Test] + public void Action_nonExistantAction() + { + string actionName = "doesnotexist"; + var exception = Assert.Throws(() => { _telescope.Action(actionName, string.Empty); }); + + Assert.That(exception.Message, Is.EqualTo($"Action {actionName} is not implemented in this driver is not implemented in this driver.")); + } } } diff --git a/Meade.net.Telescope/AstroMaths/AltitudeData.cs b/Meade.net.Telescope/AstroMaths/AltitudeData.cs new file mode 100644 index 0000000..a00f7db --- /dev/null +++ b/Meade.net.Telescope/AstroMaths/AltitudeData.cs @@ -0,0 +1,12 @@ +using System; + +namespace ASCOM.Meade.net.AstroMaths +{ + public class AltitudeData + { + public DateTime UtcDateTime { get; set; } + public double SiteLatitude { get; set; } + public double SiteLongitude { get; set; } + public EquatorialCoordinates equatorialCoordinates { get; set; } + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/AstroMaths.cs b/Meade.net.Telescope/AstroMaths/AstroMaths.cs similarity index 90% rename from Meade.net.Telescope/AstroMaths.cs rename to Meade.net.Telescope/AstroMaths/AstroMaths.cs index f197b5f..45fea5f 100644 --- a/Meade.net.Telescope/AstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths/AstroMaths.cs @@ -1,29 +1,8 @@ using System; using ASCOM.Utilities; -namespace ASCOM.Meade.net +namespace ASCOM.Meade.net.AstroMaths { - public class EquatorialCoordinates - { - public double RightAscension { get; set; } - public double Declination { get; set; } - } - - public class HorizonCoordinates - { - public double Altitude { get; set; } - public double Azimuth { get; set; } - } - - - public class AltitudeData - { - public DateTime UtcDateTime { get; set; } - public double SiteLatitude { get; set; } - public double SiteLongitude { get; set; } - public EquatorialCoordinates equatorialCoordinates { get; set; } - } - public class AstroMaths : IAstroMaths { diff --git a/Meade.net.Telescope/AstroMaths/EquatorialCoordinates.cs b/Meade.net.Telescope/AstroMaths/EquatorialCoordinates.cs new file mode 100644 index 0000000..e181e79 --- /dev/null +++ b/Meade.net.Telescope/AstroMaths/EquatorialCoordinates.cs @@ -0,0 +1,8 @@ +namespace ASCOM.Meade.net.AstroMaths +{ + public class EquatorialCoordinates + { + public double RightAscension { get; set; } + public double Declination { get; set; } + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/AstroMaths/HorizonCoordinates.cs b/Meade.net.Telescope/AstroMaths/HorizonCoordinates.cs new file mode 100644 index 0000000..de7eeae --- /dev/null +++ b/Meade.net.Telescope/AstroMaths/HorizonCoordinates.cs @@ -0,0 +1,8 @@ +namespace ASCOM.Meade.net.AstroMaths +{ + public class HorizonCoordinates + { + public double Altitude { get; set; } + public double Azimuth { get; set; } + } +} \ No newline at end of file diff --git a/Meade.net.Telescope/IAstroMaths.cs b/Meade.net.Telescope/AstroMaths/IAstroMaths.cs similarity index 95% rename from Meade.net.Telescope/IAstroMaths.cs rename to Meade.net.Telescope/AstroMaths/IAstroMaths.cs index 970942c..ff4ef4e 100644 --- a/Meade.net.Telescope/IAstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths/IAstroMaths.cs @@ -1,6 +1,6 @@ using System; -namespace ASCOM.Meade.net +namespace ASCOM.Meade.net.AstroMaths { public interface IAstroMaths { diff --git a/Meade.net.Telescope/Meade.net.Telescope.csproj b/Meade.net.Telescope/Meade.net.Telescope.csproj index 6f0fdde..cf50efa 100644 --- a/Meade.net.Telescope/Meade.net.Telescope.csproj +++ b/Meade.net.Telescope/Meade.net.Telescope.csproj @@ -113,8 +113,11 @@ - - + + + + + diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index b0987af..d80f52f 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -8,6 +8,7 @@ using ASCOM.DeviceInterface; using System.Globalization; using System.Collections; using System.Reflection; +using ASCOM.Meade.net.AstroMaths; using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; @@ -80,7 +81,7 @@ namespace ASCOM.Meade.net _utilitiesExtra = util; //Initialise util object _astroUtilities = new AstroUtils(); // Initialise astro utilities object _sharedResourcesWrapper = new SharedResourcesWrapper(); - _astroMaths = new AstroMaths(); + _astroMaths = new AstroMaths.AstroMaths(); Initialise(); } @@ -173,7 +174,7 @@ namespace ASCOM.Meade.net case "mode": _sharedResourcesWrapper.SendBlind(":EK9#"); break; - case "longMode": + case "longmode": _sharedResourcesWrapper.SendBlind(":EK11#"); break; case "goto": @@ -228,12 +229,12 @@ namespace ASCOM.Meade.net break; default: LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException($"Action {actionName}({actionParameters}) is not implemented by this driver"); + throw new ASCOM.ActionNotImplementedException($"{actionName}({actionParameters})"); } break; default: LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException($"Action {actionName} is not implemented by this driver"); + throw new ASCOM.ActionNotImplementedException($"{actionName}"); } return string.Empty; diff --git a/Meade.net.v3.ncrunchsolution.user b/Meade.net.v3.ncrunchsolution.user index b162f35..24ce899 100644 --- a/Meade.net.v3.ncrunchsolution.user +++ b/Meade.net.v3.ncrunchsolution.user @@ -2,6 +2,7 @@ True Run all tests automatically [Global] + False 25 false From d03b0f2cd14834ca687f3bed6c9f9f551c0531db Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 9 Jul 2019 22:06:20 +0100 Subject: [PATCH 065/109] Code refactoring --- Meade.net.Common/Meade.net.Common.csproj | 46 +++++++++++++++++++++ Meade.net.Common/Properties/AssemblyInfo.cs | 36 ++++++++++++++++ Meade.net.Setup/Config.wxi | 4 +- Meade.net/Meade.net.csproj | 2 +- Meade.net/ProfileProperties.cs | 9 ++++ Meade.net/SharedResources.cs | 7 ---- 6 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 Meade.net.Common/Meade.net.Common.csproj create mode 100644 Meade.net.Common/Properties/AssemblyInfo.cs create mode 100644 Meade.net/ProfileProperties.cs diff --git a/Meade.net.Common/Meade.net.Common.csproj b/Meade.net.Common/Meade.net.Common.csproj new file mode 100644 index 0000000..070032c --- /dev/null +++ b/Meade.net.Common/Meade.net.Common.csproj @@ -0,0 +1,46 @@ + + + + + Debug + AnyCPU + {7A63F045-FC76-47B9-9DC6-59FA4B758FBB} + Library + Properties + Meade.net.Common + Meade.net.Common + v4.0 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meade.net.Common/Properties/AssemblyInfo.cs b/Meade.net.Common/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9f4880f --- /dev/null +++ b/Meade.net.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Meade.net.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Meade.net.Common")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7a63f045-fc76-47b9-9dc6-59fa4b758fbb")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Meade.net.Setup/Config.wxi b/Meade.net.Setup/Config.wxi index 8e64544..a43ee7a 100644 --- a/Meade.net.Setup/Config.wxi +++ b/Meade.net.Setup/Config.wxi @@ -43,6 +43,6 @@ - - + --> + \ No newline at end of file diff --git a/Meade.net/Meade.net.csproj b/Meade.net/Meade.net.csproj index 05e64fd..5eda70d 100644 --- a/Meade.net/Meade.net.csproj +++ b/Meade.net/Meade.net.csproj @@ -131,6 +131,7 @@ + @@ -188,7 +189,6 @@ true - - --> + \ No newline at end of file From 4ea22d94552e986b77234575a1cfe8815215d892 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 9 Jul 2019 22:20:09 +0100 Subject: [PATCH 067/109] Added a build.build file --- build.build | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 build.build diff --git a/build.build b/build.build new file mode 100644 index 0000000..6f09681 --- /dev/null +++ b/build.build @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 02f69b54a4c7423f9713c2b99fc8dd098efa1765 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 01:15:05 +0100 Subject: [PATCH 068/109] Added more unit testing to the telescope driver. --- .../TelescopeUnitTests.cs | 106 +++++++++++++++++- Meade.net.Telescope/Telescope.cs | 4 +- 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index d174cec..e29273f 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,5 +1,5 @@ -using System.Xml.Serialization; -using ASCOM; +using ASCOM; +using ASCOM.Astrometry; using ASCOM.Astrometry.AstroUtils; using ASCOM.Meade.net; using ASCOM.Meade.net.AstroMaths; @@ -32,7 +32,11 @@ namespace Meade.net.Telescope.UnitTests _utilMock = new Mock(); _utilExtraMock = new Mock(); _astroUtilsMock = new Mock(); + _sharedResourcesWrapperMock = new Mock(); + _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR497"); + _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31EE"); + _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); _astroMathsMock = new Mock(); @@ -74,9 +78,23 @@ namespace Meade.net.Telescope.UnitTests Assert.That(supportedActions.Contains("handbox"), Is.True); } + [Test] + public void Action_WhenNotConnected_ThrowsNotConnectedException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var actualResult = _telescope.Action(string.Empty, string.Empty); }); + Assert.That(exception.Message,Is.EqualTo("Not connected to telescope when trying to execute: Action")); + } + [Test] public void Action_Handbox_ReadDisplay() { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + string expectedResult = "test result string"; _sharedResourcesWrapperMock.Setup(x => x.SendString(It.IsAny())).Returns(expectedResult); @@ -107,6 +125,9 @@ namespace Meade.net.Telescope.UnitTests [TestCase("?", ":EK63#")] public void Action_Handbox_blindCommands(string action, string expectedString) { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; _telescope.Action("handbox", action); _sharedResourcesWrapperMock.Verify(x => x.SendBlind(expectedString), Times.Once); @@ -115,6 +136,10 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_Handbox_nonExistantAction() { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + string actionName = "handbox"; string actionParameters = "doesnotexist"; var exception = Assert.Throws(() => { _telescope.Action(actionName, actionParameters); }); @@ -125,10 +150,87 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_nonExistantAction() { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + string actionName = "doesnotexist"; var exception = Assert.Throws(() => { _telescope.Action(actionName, string.Empty); }); Assert.That(exception.Message, Is.EqualTo($"Action {actionName} is not implemented in this driver is not implemented in this driver.")); } + + [Test] + public void CommandBlind_WhenNotConnected_ThenThrowsNotConnectedException() + { + string expectedMessage = "test blind Message"; + var exception = Assert.Throws(() => { _telescope.CommandBlind(expectedMessage, true); }); + + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: CommandBlind")); + } + + [Test] + public void CommandBlind_WhenConnected_ThenSendsExpectedMessage() + { + string expectedMessage = "test blind Message"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns( () => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.CommandBlind(expectedMessage, true); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(expectedMessage), Times.Once); + } + + [Test] + public void CommandBool_WhenNotConnected_ThenThrowsNotConnectedException() + { + string expectedMessage = "test blind Message"; + var exception = Assert.Throws(() => { _telescope.CommandBool(expectedMessage, true); }); + + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: CommandBool")); + } + + [Test] + public void CommandBool_WhenConnected_ThenSendsExpectedMessage() + { + string expectedMessage = "test blind Message"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.CommandBool(expectedMessage, true); }); + + Assert.That(exception.Message, Is.EqualTo("Method CommandBool is not implemented in this driver.")); + } + + [Test] + public void CommandString_WhenNotConnected_ThenThrowsNotConnectedException() + { + string expectedMessage = "test blind Message"; + var exception = Assert.Throws(() => { _telescope.CommandString(expectedMessage, true); }); + + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: CommandString")); + } + + [Test] + public void CommandString_WhenConnected_ThenSendsExpectedMessage() + { + string expectedMessage = "expected result message"; + string sendMessage = "test blind Message"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(sendMessage)).Returns(() => expectedMessage); + + var actualMessage = _telescope.CommandString(sendMessage, true); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(sendMessage), Times.Once); + Assert.That(actualMessage, Is.EqualTo(expectedMessage)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index d80f52f..70927d5 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -157,6 +157,8 @@ namespace ASCOM.Meade.net public string Action(string actionName, string actionParameters) { + CheckConnected("Action"); + switch (actionName.ToLower()) { case "handbox": @@ -1978,7 +1980,7 @@ namespace ASCOM.Meade.net { if (!IsConnected) { - throw new ASCOM.NotConnectedException(message); + throw new ASCOM.NotConnectedException($"Not connected to telescope when trying to execute: {message}"); } } From 31628273969d957221dfb97e022ccb44d264f52d Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 15:59:50 +0100 Subject: [PATCH 069/109] Site no longer set to site 1 on connect. --- Meade.net.Telescope/Telescope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 70927d5..433d6d4 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -305,7 +305,7 @@ namespace ASCOM.Meade.net LogMessage("Connected Set", $"Commented to port {comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); - SelectSite(1); + //SelectSite(1); SetLongFormat(true); From 8089e8d53698650cceaf04ebf00e72a4d6c4b5bf Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 16:00:08 +0100 Subject: [PATCH 070/109] More unit testing and associated refactoring --- .../TelescopeUnitTests.cs | 73 ++++++++++++++++++- Meade.net.Telescope/Telescope.cs | 12 ++- 2 files changed, 79 insertions(+), 6 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index e29273f..2749b4d 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,5 +1,5 @@ -using ASCOM; -using ASCOM.Astrometry; +using System; +using ASCOM; using ASCOM.Astrometry.AstroUtils; using ASCOM.Meade.net; using ASCOM.Meade.net.AstroMaths; @@ -34,9 +34,12 @@ namespace Meade.net.Telescope.UnitTests _astroUtilsMock = new Mock(); _sharedResourcesWrapperMock = new Mock(); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS#"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR497"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31EE"); + _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); + _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); _astroMathsMock = new Mock(); @@ -93,10 +96,12 @@ namespace Meade.net.Telescope.UnitTests { _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; string expectedResult = "test result string"; - _sharedResourcesWrapperMock.Setup(x => x.SendString(It.IsAny())).Returns(expectedResult); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":ED#")).Returns(expectedResult); + _telescope.Connected = true; + + var actualResult = _telescope.Action("handbox", "readdisplay"); @@ -127,6 +132,7 @@ namespace Meade.net.Telescope.UnitTests { _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; _telescope.Action("handbox", action); @@ -232,5 +238,64 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendString(sendMessage), Times.Once); Assert.That(actualMessage, Is.EqualTo(expectedMessage)); } + + [TestCase(true)] + [TestCase(false)] + public void Connected_Get_ReturnsExpectedValue(bool expectedConnected) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = expectedConnected; + + Assert.That(_telescope.Connected, Is.EqualTo(expectedConnected)); + } + + + [Test] + public void Connected_Set_SettingTrueWhenTrue_ThenDoesNothing() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + _sharedResourcesWrapperMock.Verify( x => x.Connect(It.IsAny()),Times.Once); + + //act + _telescope.Connected = true; + + //assert + _sharedResourcesWrapperMock.Verify(x => x.Connect(It.IsAny()), Times.Once); + } + + [Test] + public void Connected_Set_SettingFalseWhenTrue_ThenDisconnects() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + _sharedResourcesWrapperMock.Verify(x => x.Connect(It.IsAny()), Times.Once); + + //act + _telescope.Connected = false; + + //assert + _sharedResourcesWrapperMock.Verify(x => x.Disconnect(It.IsAny()), Times.Once()); + } + + [Test] + public void Connected_Set_WhenFailsToConnect_ThenDisconnects() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + _sharedResourcesWrapperMock.Setup(x => x.SendString(It.IsAny())).Throws(new Exception("TestFailed")); + + //act + _telescope.Connected = true; + + //assert + _sharedResourcesWrapperMock.Verify(x => x.Disconnect(It.IsAny()), Times.Once()); + } + + } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 433d6d4..e4ea0d3 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -65,7 +65,7 @@ namespace ASCOM.Meade.net /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) /// - internal static TraceLogger tl; + private TraceLogger tl; private readonly ISharedResourcesWrapper _sharedResourcesWrapper; @@ -275,6 +275,9 @@ namespace ASCOM.Meade.net public void Dispose() { + if (Connected) + Connected = false; + // Clean up the tracelogger and util objects tl.Enabled = false; tl.Dispose(); @@ -375,6 +378,11 @@ namespace ASCOM.Meade.net private void SelectSite(int site) { + if (site < 1) + throw new ArgumentOutOfRangeException("site cannot be lower than 1"); + else if (site > 4) + throw new ArgumentOutOfRangeException("site cannot be higher than 4"); + _sharedResourcesWrapper.SendBlind($":W{site}#"); //:W# //Set current site to, an ASCII digit in the range 1..4 @@ -2000,7 +2008,7 @@ namespace ASCOM.Meade.net /// /// /// - internal static void LogMessage(string identifier, string message, params object[] args) + internal void LogMessage(string identifier, string message, params object[] args) { var msg = string.Format(message, args); tl.LogMessage(identifier, msg); From bd49a868663e4c5621bad42f610e210ba229fffd Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 16:15:58 +0100 Subject: [PATCH 071/109] Refactor all LogMessage commands via LogMessage Method instead of directory to dependent class --- Meade.net.Telescope/Telescope.cs | 211 +++++++++++++++---------------- 1 file changed, 104 insertions(+), 107 deletions(-) diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index e4ea0d3..42dfabb 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -101,13 +101,13 @@ namespace ASCOM.Meade.net { //todo move the TraceLogger out to a factory class. tl = new TraceLogger("", "Meade.net.Telescope"); - tl.LogMessage("Telescope", "Starting initialisation"); + LogMessage("Telescope", "Starting initialisation"); ReadProfile(); // Read device configuration from the ASCOM Profile store IsConnected = false; // Initialise connected to false - tl.LogMessage("Telescope", "Completed initialisation"); + LogMessage("Telescope", "Completed initialisation"); } @@ -125,10 +125,10 @@ namespace ASCOM.Meade.net /// public void SetupDialog() { - tl.LogMessage("SetupDialog", "Opening setup dialog"); + LogMessage("SetupDialog", "Opening setup dialog"); _sharedResourcesWrapper.SetupDialog(); ReadProfile(); - tl.LogMessage("SetupDialog", "complete"); + LogMessage("SetupDialog", "complete"); //// consider only showing the setup dialog if not connected //// or call a different dialog if connected //if (IsConnected) @@ -148,7 +148,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); + LogMessage("SupportedActions Get", "Returning empty arraylist"); var supportedActions = new ArrayList(); supportedActions.Add("handbox"); return supportedActions; @@ -293,7 +293,7 @@ namespace ASCOM.Meade.net } set { - tl.LogMessage("Connected", "Set {0}", value); + LogMessage("Connected", "Set {0}", value); if (value == IsConnected) return; @@ -305,14 +305,11 @@ namespace ASCOM.Meade.net _sharedResourcesWrapper.Connect("Serial"); try { - LogMessage("Connected Set", $"Commented to port {comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); + LogMessage("Connected Set", $"Connected to port {comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); - - //SelectSite(1); SetLongFormat(true); - - _userNewerPulseGuiding = IsNewPulseGuidingSupported(); + LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); IsConnected = true; } @@ -336,7 +333,7 @@ namespace ASCOM.Meade.net } } - private bool IsNewPulseGuidingSupported() + public bool IsNewPulseGuidingSupported() { if (_sharedResourcesWrapper.ProductName == _sharedResourcesWrapper.AUTOSTAR497) { @@ -394,7 +391,7 @@ namespace ASCOM.Meade.net // TODO customise this device description get { - tl.LogMessage("Description Get", driverDescription); + LogMessage("Description Get", driverDescription); return driverDescription; } } @@ -407,7 +404,7 @@ namespace ASCOM.Meade.net // TODO customise this driver description string driverInfo = "Meade Generic .net driver. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverInfo Get", driverInfo); + LogMessage("DriverInfo Get", driverInfo); return driverInfo; } } @@ -419,7 +416,7 @@ namespace ASCOM.Meade.net Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; string driverVersion = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverVersion Get", driverVersion); + LogMessage("DriverVersion Get", driverVersion); return driverVersion; } } @@ -450,7 +447,7 @@ namespace ASCOM.Meade.net //string name = $"{telescopeProduceName} - {firmwareVersion}"; string name = driverDescription; - tl.LogMessage("Name Get", name); + LogMessage("Name Get", name); return name; } } @@ -463,7 +460,7 @@ namespace ASCOM.Meade.net { CheckConnected("AbortSlew"); - tl.LogMessage("AbortSlew", "Aborting slew"); + LogMessage("AbortSlew", "Aborting slew"); _sharedResourcesWrapper.SendBlind(":Q#"); //:Q# Halt all current slewing //Returns:Nothing @@ -473,7 +470,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("AlignmentMode Get", "Getting alignmode"); + LogMessage("AlignmentMode Get", "Getting alignmode"); CheckConnected("AlignmentMode Get"); @@ -513,7 +510,7 @@ namespace ASCOM.Meade.net $"unknown alignment returned from telescope: {alignmentString}"); } - tl.LogMessage("AlignmentMode Get", $"alignmode = {alignmentMode}"); + LogMessage("AlignmentMode Get", $"alignmode = {alignmentMode}"); return alignmentMode; } set @@ -549,7 +546,7 @@ namespace ASCOM.Meade.net CheckConnected("Altitude get"); var altAz = CalcAltAzFromTelescopeEqData(); - tl.LogMessage("Altitude", $"{altAz.Altitude}"); + LogMessage("Altitude", $"{altAz.Altitude}"); return altAz.Altitude; ////todo firmware bug in 44Eg, :GA# is returning the dec, not the altitude! @@ -559,10 +556,10 @@ namespace ASCOM.Meade.net ////The current scope altitude. The returned format depending on the current precision setting. //var alt = utilities.DMSToDegrees(result); - //tl.LogMessage("Altitude", $"{alt}"); + //LogMessage("Altitude", $"{alt}"); //return alt; - //tl.LogMessage("Altitude Get", "Not implemented"); + //LogMessage("Altitude Get", "Not implemented"); //throw new ASCOM.PropertyNotImplementedException("Altitude", false); } } @@ -591,7 +588,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("ApertureArea Get", "Not implemented"); + LogMessage("ApertureArea Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("ApertureArea", false); } } @@ -600,7 +597,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("ApertureDiameter Get", "Not implemented"); + LogMessage("ApertureDiameter Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("ApertureDiameter", false); } } @@ -609,7 +606,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("AtHome", "Get - " + false.ToString()); + LogMessage("AtHome", "Get - " + false.ToString()); return false; } } @@ -620,7 +617,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("AtPark", "Get - " + _atPark); + LogMessage("AtPark", "Get - " + _atPark); return _atPark; } private set { _atPark = value; } @@ -628,7 +625,7 @@ namespace ASCOM.Meade.net public IAxisRates AxisRates(TelescopeAxes Axis) { - tl.LogMessage("AxisRates", "Get - " + Axis.ToString()); + LogMessage("AxisRates", "Get - " + Axis.ToString()); return new AxisRates(Axis); } @@ -645,11 +642,11 @@ namespace ASCOM.Meade.net //double az = utilities.DMSToDegrees(result); - //tl.LogMessage("Azimuth Get", $"{az}"); + //LogMessage("Azimuth Get", $"{az}"); //return az; var altAz = CalcAltAzFromTelescopeEqData(); - tl.LogMessage("Azimuth Get", $"{altAz.Azimuth}"); + LogMessage("Azimuth Get", $"{altAz.Azimuth}"); return altAz.Azimuth; } } @@ -658,14 +655,14 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanFindHome", "Get - " + false.ToString()); + LogMessage("CanFindHome", "Get - " + false.ToString()); return false; } } public bool CanMoveAxis(TelescopeAxes Axis) { - tl.LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); + LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); switch (Axis) { case TelescopeAxes.axisPrimary: return true; //RA or AZ @@ -679,7 +676,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanPark", "Get - " + true.ToString()); + LogMessage("CanPark", "Get - " + true.ToString()); return true; } } @@ -688,7 +685,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanPulseGuide", "Get - " + true.ToString()); + LogMessage("CanPulseGuide", "Get - " + true.ToString()); return true; } } @@ -697,7 +694,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetDeclinationRate", "Get - " + false.ToString()); + LogMessage("CanSetDeclinationRate", "Get - " + false.ToString()); return false; } } @@ -706,7 +703,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetGuideRates", "Get - " + false.ToString()); + LogMessage("CanSetGuideRates", "Get - " + false.ToString()); return false; } } @@ -715,7 +712,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetPark", "Get - " + false.ToString()); + LogMessage("CanSetPark", "Get - " + false.ToString()); return false; } } @@ -724,7 +721,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetPierSide", "Get - " + false.ToString()); + LogMessage("CanSetPierSide", "Get - " + false.ToString()); return false; } } @@ -733,7 +730,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetRightAscensionRate", "Get - " + false.ToString()); + LogMessage("CanSetRightAscensionRate", "Get - " + false.ToString()); return false; } } @@ -742,7 +739,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSetTracking", "Get - " + true.ToString()); + LogMessage("CanSetTracking", "Get - " + true.ToString()); return true; } } @@ -751,7 +748,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSlew", "Get - " + true.ToString()); + LogMessage("CanSlew", "Get - " + true.ToString()); return true; } } @@ -760,7 +757,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSlewAltAz", "Get - " + true.ToString()); + LogMessage("CanSlewAltAz", "Get - " + true.ToString()); return true; } } @@ -769,7 +766,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSlewAltAzAsync", "Get - " + true.ToString()); + LogMessage("CanSlewAltAzAsync", "Get - " + true.ToString()); return true; } } @@ -778,7 +775,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSlewAsync", "Get - " + true.ToString()); + LogMessage("CanSlewAsync", "Get - " + true.ToString()); return true; } } @@ -787,7 +784,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSync", "Get - " + true.ToString()); + LogMessage("CanSync", "Get - " + true.ToString()); return true; } } @@ -796,7 +793,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanSyncAltAz", "Get - " + false.ToString()); + LogMessage("CanSyncAltAz", "Get - " + false.ToString()); return false; } } @@ -805,7 +802,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("CanUnpark", "Get - " + false.ToString()); + LogMessage("CanUnpark", "Get - " + false.ToString()); return false; } } @@ -823,7 +820,7 @@ namespace ASCOM.Meade.net double declination = _utilities.DMSToDegrees(result); - tl.LogMessage("Declination", "Get - " + _utilitiesExtra.DegreesToDMS(declination, ":", ":")); + LogMessage("Declination", "Get - " + _utilitiesExtra.DegreesToDMS(declination, ":", ":")); return declination; } } @@ -833,19 +830,19 @@ namespace ASCOM.Meade.net get { double declination = 0.0; - tl.LogMessage("DeclinationRate", "Get - " + declination.ToString()); + LogMessage("DeclinationRate", "Get - " + declination.ToString()); return declination; } set { - tl.LogMessage("DeclinationRate Set", "Not implemented"); + LogMessage("DeclinationRate Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("DeclinationRate", true); } } public PierSide DestinationSideOfPier(double rightAscension, double declination) { - tl.LogMessage("DestinationSideOfPier Get", "Not implemented"); + LogMessage("DestinationSideOfPier Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("DestinationSideOfPier", false); } @@ -853,12 +850,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("DoesRefraction Get", "Not implemented"); + LogMessage("DoesRefraction Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("DoesRefraction", false); } set { - tl.LogMessage("DoesRefraction Set", "Not implemented"); + LogMessage("DoesRefraction Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("DoesRefraction", true); } } @@ -868,14 +865,14 @@ namespace ASCOM.Meade.net get { EquatorialCoordinateType equatorialSystem = EquatorialCoordinateType.equTopocentric; - tl.LogMessage("DeclinationRate", "Get - " + equatorialSystem.ToString()); + LogMessage("DeclinationRate", "Get - " + equatorialSystem.ToString()); return equatorialSystem; } } public void FindHome() { - tl.LogMessage("FindHome", "Not implemented"); + LogMessage("FindHome", "Not implemented"); throw new ASCOM.MethodNotImplementedException("FindHome"); } @@ -883,7 +880,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("FocalLength Get", "Not implemented"); + LogMessage("FocalLength Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("FocalLength", false); } } @@ -892,12 +889,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("GuideRateDeclination Get", "Not implemented"); + LogMessage("GuideRateDeclination Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", false); } set { - tl.LogMessage("GuideRateDeclination Set", "Not implemented"); + LogMessage("GuideRateDeclination Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", true); } } @@ -906,12 +903,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("GuideRateRightAscension Get", "Not implemented"); + LogMessage("GuideRateRightAscension Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", false); } set { - tl.LogMessage("GuideRateRightAscension Set", "Not implemented"); + LogMessage("GuideRateRightAscension Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", true); } } @@ -920,7 +917,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); + LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); //throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); return false; } @@ -931,7 +928,7 @@ namespace ASCOM.Meade.net public void MoveAxis(TelescopeAxes axis, double rate) { - tl.LogMessage("MoveAxis", $"Axis={axis} rate={rate}"); + LogMessage("MoveAxis", $"Axis={axis} rate={rate}"); CheckConnected("MoveAxis"); var absRate = Math.Abs(rate); @@ -1028,7 +1025,7 @@ namespace ASCOM.Meade.net public void Park() { - tl.LogMessage("Park", "Parking telescope"); + LogMessage("Park", "Parking telescope"); CheckConnected("Park"); if (AtPark) @@ -1044,7 +1041,7 @@ namespace ASCOM.Meade.net public void PulseGuide(GuideDirections direction, int duration) { - tl.LogMessage("PulseGuide", $"pulse guide direction {direction} duration {duration}"); + LogMessage("PulseGuide", $"pulse guide direction {direction} duration {duration}"); CheckConnected("PulseGuide"); string d = string.Empty; @@ -1120,7 +1117,7 @@ namespace ASCOM.Meade.net double rightAscension = _utilities.HMSToHours(result); - tl.LogMessage("RightAscension", "Get - " + _utilitiesExtra.HoursToHMS(rightAscension)); + LogMessage("RightAscension", "Get - " + _utilitiesExtra.HoursToHMS(rightAscension)); return rightAscension; } } @@ -1130,19 +1127,19 @@ namespace ASCOM.Meade.net get { double rightAscensionRate = 0.0; - tl.LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString()); + LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString()); return rightAscensionRate; } set { - tl.LogMessage("RightAscensionRate Set", "Not implemented"); + LogMessage("RightAscensionRate Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("RightAscensionRate", true); } } public void SetPark() { - tl.LogMessage("SetPark", "Not implemented"); + LogMessage("SetPark", "Not implemented"); throw new ASCOM.MethodNotImplementedException("SetPark"); } @@ -1150,12 +1147,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("SideOfPier Get", "Not implemented"); + LogMessage("SideOfPier Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SideOfPier", false); } set { - tl.LogMessage("SideOfPier Set", "Not implemented"); + LogMessage("SideOfPier Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SideOfPier", true); } } @@ -1181,7 +1178,7 @@ namespace ASCOM.Meade.net // Reduce to the range 0 to 24 hours siderealTime = _astroUtilities.ConditionRA(siderealTime); - tl.LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); + LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); return siderealTime; } } @@ -1190,12 +1187,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("SiteElevation Get", "Not implemented"); + LogMessage("SiteElevation Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SiteElevation", false); } set { - tl.LogMessage("SiteElevation Set", "Not implemented"); + LogMessage("SiteElevation Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SiteElevation", true); } } @@ -1212,12 +1209,12 @@ namespace ASCOM.Meade.net //The latitude of the current site. Positive inplies North latitude. var siteLatitude = _utilities.DMSToDegrees(latitude); - tl.LogMessage("SiteLatitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLatitude)}"); + LogMessage("SiteLatitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLatitude)}"); return siteLatitude; } set { - tl.LogMessage("SiteLatitude Set", $"{_utilitiesExtra.DegreesToDMS(value)}"); + LogMessage("SiteLatitude Set", $"{_utilitiesExtra.DegreesToDMS(value)}"); CheckConnected("SiteLatitude Set"); @@ -1259,14 +1256,14 @@ namespace ASCOM.Meade.net siteLongitude = -siteLongitude; - tl.LogMessage("SiteLongitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLongitude)}"); + LogMessage("SiteLongitude Get", $"{_utilitiesExtra.DegreesToDMS(siteLongitude)}"); return siteLongitude; } set { var newLongitude = value; - tl.LogMessage("SiteLongitude Set", $"{_utilitiesExtra.DegreesToDMS(newLongitude)}"); + LogMessage("SiteLongitude Set", $"{_utilitiesExtra.DegreesToDMS(newLongitude)}"); CheckConnected("SiteLongitude Set"); @@ -1299,19 +1296,19 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("SlewSettleTime Get", "Not implemented"); + LogMessage("SlewSettleTime Get", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", false); } set { - tl.LogMessage("SlewSettleTime Set", "Not implemented"); + LogMessage("SlewSettleTime Set", "Not implemented"); throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", true); } } public void SlewToAltAz(double azimuth, double altitude) { - tl.LogMessage("SlewToAltAz", $"Az=~{azimuth} Alt={altitude}"); + LogMessage("SlewToAltAz", $"Az=~{azimuth} Alt={altitude}"); CheckConnected("SlewToAltAz"); SlewToAltAzAsync(azimuth, altitude); @@ -1394,7 +1391,7 @@ namespace ASCOM.Meade.net if (azimuth < 0) throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); - tl.LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); + LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); CheckConnected("SlewToAltAzAsync"); HorizonCoordinates altAz = new HorizonCoordinates(); @@ -1441,20 +1438,20 @@ namespace ASCOM.Meade.net { case "0": //We're slewing everything should be working just fine. - tl.LogMessage("DoSlewAsync", "Slewing to target"); + LogMessage("DoSlewAsync", "Slewing to target"); break; case "1": //Below Horizon string belowHorizonMessage = _sharedResourcesWrapper.ReadTerminated(); - tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowHorizonMessage}\""); + LogMessage("DoSlewAsync", $"Slew failed \"{belowHorizonMessage}\""); throw new ASCOM.InvalidOperationException(belowHorizonMessage); case "2": //Below Horizon string belowMinimumElevationMessage = _sharedResourcesWrapper.ReadTerminated(); - tl.LogMessage("DoSlewAsync", $"Slew failed \"{belowMinimumElevationMessage}\""); + LogMessage("DoSlewAsync", $"Slew failed \"{belowMinimumElevationMessage}\""); throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); default: - tl.LogMessage("DoSlewAsync", $"Slew failed - unknown response \"{response}\""); + LogMessage("DoSlewAsync", $"Slew failed - unknown response \"{response}\""); throw new ASCOM.DriverException("This error should not happen"); } @@ -1480,7 +1477,7 @@ namespace ASCOM.Meade.net public void SlewToCoordinates(double rightAscension, double declination) { - tl.LogMessage("SlewToCoordinates", $"Ra={rightAscension}, Dec={declination}"); + LogMessage("SlewToCoordinates", $"Ra={rightAscension}, Dec={declination}"); CheckConnected("SlewToCoordinates"); SlewToCoordinatesAsync(rightAscension, declination); @@ -1490,12 +1487,12 @@ namespace ASCOM.Meade.net _utilities.WaitForMilliseconds(200); //be responsive to AbortSlew(); } - tl.LogMessage("SlewToCoordinates", $"Slewing completed new coordinates Ra={RightAscension}, Dec={Declination}"); + LogMessage("SlewToCoordinates", $"Slewing completed new coordinates Ra={RightAscension}, Dec={Declination}"); } public void SlewToCoordinatesAsync(double rightAscension, double declination) { - tl.LogMessage("SlewToCoordinatesAsync", $"Ra={rightAscension}, Dec={declination}"); + LogMessage("SlewToCoordinatesAsync", $"Ra={rightAscension}, Dec={declination}"); CheckConnected("SlewToCoordinatesAsync"); _sharedResourcesWrapper.Lock(() => @@ -1510,7 +1507,7 @@ namespace ASCOM.Meade.net public void SlewToTarget() { - tl.LogMessage("SlewToTarget", "Executing"); + LogMessage("SlewToTarget", "Executing"); CheckConnected("SlewToTarget"); SlewToTargetAsync(); @@ -1556,20 +1553,20 @@ namespace ASCOM.Meade.net //Autostars and Autostar II – a string containing one bar until a slew is complete, then a null string is returned. bool isSlewing = result != string.Empty; - tl.LogMessage("Slewing Get", $"Result = {isSlewing}"); + LogMessage("Slewing Get", $"Result = {isSlewing}"); return isSlewing; } } public void SyncToAltAz(double azimuth, double altitude) { - tl.LogMessage("SyncToAltAz", "Not implemented"); + LogMessage("SyncToAltAz", "Not implemented"); throw new ASCOM.MethodNotImplementedException("SyncToAltAz"); } public void SyncToCoordinates(double rightAscension, double declination) { - tl.LogMessage("SyncToCoordinates", $"RA={rightAscension} Dec={declination}"); + LogMessage("SyncToCoordinates", $"RA={rightAscension} Dec={declination}"); CheckConnected("SyncToCoordinates"); _sharedResourcesWrapper.Lock(() => @@ -1583,7 +1580,7 @@ namespace ASCOM.Meade.net public void SyncToTarget() { - tl.LogMessage("SyncToTarget", "Executing"); + LogMessage("SyncToTarget", "Executing"); CheckConnected("SyncToTarget"); var result = _sharedResourcesWrapper.SendString(":CM#"); @@ -1613,12 +1610,12 @@ namespace ASCOM.Meade.net //return targetDec; - tl.LogMessage("TargetDeclination Get", $"{_targetDeclination}"); + LogMessage("TargetDeclination Get", $"{_targetDeclination}"); return _targetDeclination; } set { - tl.LogMessage("TargetDeclination Set", $"{value}"); + LogMessage("TargetDeclination Set", $"{value}"); //todo implement low precision version of this. if (value > 90) @@ -1634,7 +1631,7 @@ namespace ASCOM.Meade.net var command = $":Sd{s}{dms}#"; - tl.LogMessage("TargetDeclination Set", $"{command}"); + LogMessage("TargetDeclination Set", $"{command}"); var result = _sharedResourcesWrapper.SendChar(command); //:SdsDD*MM# //Set target object declination to sDD*MM or sDD*MM:SS depending on the current precision setting @@ -1667,12 +1664,12 @@ namespace ASCOM.Meade.net //double targetRa = HmsToDouble(result); //return targetRa; - tl.LogMessage("TargetRightAscension Get", $"{_targetRightAscension}"); + LogMessage("TargetRightAscension Get", $"{_targetRightAscension}"); return _targetRightAscension; } set { - tl.LogMessage("TargetRightAscension Set", $"{value}"); + LogMessage("TargetRightAscension Set", $"{value}"); if (value < 0) throw new InvalidValueException("Right ascension value cannot be below 0"); @@ -1704,12 +1701,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("Tracking", $"Get - {_tracking}"); + LogMessage("Tracking", $"Get - {_tracking}"); return _tracking; } set { - tl.LogMessage($"Tracking Set", $"{value}"); + LogMessage($"Tracking Set", $"{value}"); _tracking = value; } } @@ -1732,12 +1729,12 @@ namespace ASCOM.Meade.net // return DriveRates.driveSidereal; //return DriveRates.driveKing; - tl.LogMessage("TrackingRate Get", $"{_trackingRate}"); + LogMessage("TrackingRate Get", $"{_trackingRate}"); return _trackingRate; } set { - tl.LogMessage("TrackingRate Set", $"{value}"); + LogMessage("TrackingRate Set", $"{value}"); CheckConnected("TrackingRate Set"); switch (value) @@ -1774,10 +1771,10 @@ namespace ASCOM.Meade.net get { ITrackingRates trackingRates = new TrackingRates(); - tl.LogMessage("TrackingRates", "Get - "); + LogMessage("TrackingRates", "Get - "); foreach (DriveRates driveRate in trackingRates) { - tl.LogMessage("TrackingRates", "Get - " + driveRate.ToString()); + LogMessage("TrackingRates", "Get - " + driveRate.ToString()); } return trackingRates; } @@ -1810,7 +1807,7 @@ namespace ASCOM.Meade.net { CheckConnected("UTCDate Get"); - tl.LogMessage("UTCDate", "Get started"); + LogMessage("UTCDate", "Get started"); TelescopeDateDetails telescopeDateDetails = _sharedResourcesWrapper.Lock(() => { @@ -1844,13 +1841,13 @@ namespace ASCOM.Meade.net var utcDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + telescopeDateDetails.utcCorrection; - tl.LogMessage("UTCDate", "Get - " + utcDate.ToString("MM/dd/yy HH:mm:ss")); + LogMessage("UTCDate", "Get - " + utcDate.ToString("MM/dd/yy HH:mm:ss")); return utcDate; } set { - tl.LogMessage("UTCDate", "Set - " + value.ToString("MM/dd/yy HH:mm:ss")); + LogMessage("UTCDate", "Set - " + value.ToString("MM/dd/yy HH:mm:ss")); CheckConnected("UTCDate Set"); @@ -1891,7 +1888,7 @@ namespace ASCOM.Meade.net public void Unpark() { - tl.LogMessage("Unpark", "Not implemented"); + LogMessage("Unpark", "Not implemented"); throw new ASCOM.MethodNotImplementedException("Unpark"); } From 64b949551e38c8819f036017a85366e054e9f25b Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 16:27:47 +0100 Subject: [PATCH 072/109] More unit testing, this time for pulse guiding support --- .../TelescopeUnitTests.cs | 16 ++++++++++++++-- Meade.net.Telescope/Telescope.cs | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 2749b4d..e0af2bf 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -35,8 +35,8 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock = new Mock(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS#"); - _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR497"); - _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31EE"); + _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR"); + _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31Ee"); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); @@ -296,6 +296,18 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.Disconnect(It.IsAny()), Times.Once()); } + [TestCase("AUTOSTAR", "30Ab", false)] + [TestCase("AUTOSTAR","31Ee", true)] + [TestCase("AUTOSTAR", "41Aa", true)] + [TestCase("AUTOSTAR II", "", false)] + public void IsNewPulseGuidingSupported_ThenIsSupported_ThenReturnsTrue(string productName, string firmware, bool isSupported) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(productName); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(firmware); + var result = _telescope.IsNewPulseGuidingSupported(); + + Assert.That(result, Is.EqualTo(isSupported)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 42dfabb..d04c107 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -350,7 +350,7 @@ namespace ASCOM.Meade.net return (comparison >= 0); } - private void SetLongFormat(bool setLongFormat) + public void SetLongFormat(bool setLongFormat) { _sharedResourcesWrapper.Lock(() => { From bfde58c6af18cd0e40d9ae36f5e7ce6af196f372 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 19:27:51 +0100 Subject: [PATCH 073/109] Lots more unit tests, and some refactoring to make the code follow SOLID better. --- .../TelescopeUnitTests.cs | 122 +++++++++++++++++- Meade.net.Telescope/Telescope.cs | 16 +-- 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index e0af2bf..a3868db 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,6 +1,8 @@ using System; +using System.Globalization; using ASCOM; using ASCOM.Astrometry.AstroUtils; +using ASCOM.DeviceInterface; using ASCOM.Meade.net; using ASCOM.Meade.net.AstroMaths; using ASCOM.Meade.net.Wrapper; @@ -34,7 +36,7 @@ namespace Meade.net.Telescope.UnitTests _astroUtilsMock = new Mock(); _sharedResourcesWrapperMock = new Mock(); - _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS#"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31Ee"); @@ -309,5 +311,123 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(isSupported)); } + + [Test] + public void SetLongFormatFalse_WhenTelescopeReturnsShortFormat_ThenDoesNothing() + { + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM"); + _telescope.SetLongFormat(false); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":U#"),Times.Never); + } + + [Test] + public void SetLongFormatFalse_WhenTelescopeReturnsLongFormat_ThenTogglesPrecision() + { + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS"); + _telescope.SetLongFormat(false); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":U#"), Times.Once); + } + + [Test] + public void SetLongFormatTrue_WhenTelescopeReturnsLongFormat_ThenDoesNothing() + { + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS"); + _telescope.SetLongFormat(true); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":U#"), Times.Never); + } + + [Test] + public void SetLongFormatTrue_WhenTelescopeReturnsShortFormat_ThenTogglesPrecision() + { + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM"); + _telescope.SetLongFormat(true); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":U#"), Times.Once); + } + + [Test] + public void SelectSite_WhenNewSiteToLow_ThenThrowsException() + { + var site = 0; + var result = Assert.Throws(() => { _telescope.SelectSite(site); }); + + Assert.That(result.Message, Is.EqualTo($"Site cannot be lower than 1\r\nParameter name: site\r\nActual value was {site}.")); + } + + [Test] + public void SelectSite_WhenNewSiteToHigh_ThenThrowsException() + { + var site = 5; + var result = Assert.Throws(() => { _telescope.SelectSite(site); }); + + Assert.That(result.Message, Is.EqualTo($"Site cannot be higher than 4\r\nParameter name: site\r\nActual value was {site}.")); + } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + public void SelectSite_WhenNewSiteToHigh_ThenThrowsException(int site) + { + _telescope.SelectSite(site); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind($":W{site}#"), Times.Once); + } + + [Test] + public void Description_Get() + { + var expectedDescription = "Meade Generic"; + + var description = _telescope.Description; + + Assert.That(description, Is.EqualTo(expectedDescription)); + } + + [Test] + public void DriverVersion_Get() + { + Version version = System.Reflection.Assembly.GetAssembly(typeof(ASCOM.Meade.net.Telescope)).GetName().Version; + + string exptectedDriverInfo = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; + + var driverVersion = _telescope.DriverVersion; + + Assert.That(driverVersion, Is.EqualTo(exptectedDriverInfo)); + } + + [Test] + public void DriverInfo_Get() + { + Version version = System.Reflection.Assembly.GetAssembly(typeof(ASCOM.Meade.net.Telescope)).GetName().Version; + + string exptectedDriverInfo = $"{_telescope.Description} .net driver. Version: {_telescope.DriverVersion}"; + + var driverInfo = _telescope.DriverInfo; + + Assert.That(driverInfo, Is.EqualTo(exptectedDriverInfo)); + } + + [Test] + public void InterfaceVersion_Get() + { + var interfaceVersion = _telescope.InterfaceVersion; + Assert.That(interfaceVersion, Is.EqualTo(3)); + + Assert.That(_telescope, Is.AssignableTo()); + } + + [Test] + public void Name_Get() + { + string expectedName = "Meade Generic"; + + var name = _telescope.Name; + + Assert.That(name, Is.EqualTo(expectedName)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index d04c107..3dab40a 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -356,7 +356,7 @@ namespace ASCOM.Meade.net { var result = _sharedResourcesWrapper.SendString(":GZ#"); //:GZ# Get telescope azimuth - //Returns: DDD*MM#T or DDD*MM’SS# + //Returns: DDD*MM# or DDD*MM’SS# //The current telescope Azimuth depending on the selected precision. bool isLongFormat = result.Length > 6; @@ -373,12 +373,13 @@ namespace ASCOM.Meade.net }); } - private void SelectSite(int site) + //todo hook this up to a custom action + public void SelectSite(int site) { if (site < 1) - throw new ArgumentOutOfRangeException("site cannot be lower than 1"); + throw new ArgumentOutOfRangeException("site",site,"Site cannot be lower than 1"); else if (site > 4) - throw new ArgumentOutOfRangeException("site cannot be higher than 4"); + throw new ArgumentOutOfRangeException("site", site, "Site cannot be higher than 4"); _sharedResourcesWrapper.SendBlind($":W{site}#"); //:W# @@ -400,10 +401,8 @@ namespace ASCOM.Meade.net { get { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; // TODO customise this driver description - string driverInfo = "Meade Generic .net driver. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, - version.Minor); + string driverInfo = $"{Description} .net driver. Version: {DriverVersion}"; LogMessage("DriverInfo Get", driverInfo); return driverInfo; } @@ -414,8 +413,7 @@ namespace ASCOM.Meade.net get { Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - string driverVersion = - String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); + string driverVersion = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; LogMessage("DriverVersion Get", driverVersion); return driverVersion; } From 8980c3c6b52ea6c3a3cabb69d179e3641ced811f Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 20:02:06 +0100 Subject: [PATCH 074/109] More unit testing. Added check for to be able to support setting the alignment mode --- .../TelescopeUnitTests.cs | 79 ++++++++++++++++++- Meade.net.Telescope/Telescope.cs | 27 ++++--- Meade.net/Wrapper/SharedResourcesWrapper.cs | 3 + 3 files changed, 99 insertions(+), 10 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index a3868db..4b4ab51 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -9,6 +9,7 @@ using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; using Moq; using NUnit.Framework; +using NotImplementedException = ASCOM.NotImplementedException; namespace Meade.net.Telescope.UnitTests { @@ -39,6 +40,7 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR"); _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31Ee"); + _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_43EG) .Returns(() => "43Eg"); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); @@ -300,7 +302,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase("AUTOSTAR", "30Ab", false)] [TestCase("AUTOSTAR","31Ee", true)] - [TestCase("AUTOSTAR", "41Aa", true)] + [TestCase("AUTOSTAR", "43Eg", true)] [TestCase("AUTOSTAR II", "", false)] public void IsNewPulseGuidingSupported_ThenIsSupported_ThenReturnsTrue(string productName, string firmware, bool isSupported) { @@ -429,5 +431,80 @@ namespace Meade.net.Telescope.UnitTests Assert.That(name, Is.EqualTo(expectedName)); } + + [Test] + public void AlignmentMode_Get_WhenNotConnected_ThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var actualResult = _telescope.AlignmentMode; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AlignmentMode Get")); + } + + + [TestCase("A", AlignmentModes.algAltAz)] + [TestCase("P", AlignmentModes.algPolar)] + [TestCase("G", AlignmentModes.algGermanPolar)] + public void AlignmentMode_Get_WhenScopeInAltAz_ReturnsAltAz(string telescopeMode, AlignmentModes alignmentMode) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + const char ack = (char)6; + _sharedResourcesWrapperMock.Setup(x => x.SendChar(ack.ToString())).Returns(telescopeMode); + + var actualResult = _telescope.AlignmentMode; + + Assert.That(actualResult, Is.EqualTo(alignmentMode)); + } + + [Test] + public void AlignmentMode_Get_WhenUnknownAlignmentMode_ThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + Assert.Throws(() => { var actualResult = _telescope.AlignmentMode; }); + } + + [Test] + public void AlignmentMode_Set_WhenNotConnected_ThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.AlignmentMode = AlignmentModes.algAltAz; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AlignmentMode Set")); + } + + [TestCase("AUTOSTAR", "43Eg", AlignmentModes.algAltAz, ":AA#")] + [TestCase("AUTOSTAR", "43Eg", AlignmentModes.algPolar, ":AP#")] + [TestCase("AUTOSTAR", "43Eg", AlignmentModes.algGermanPolar, ":AP#")] + public void AlignmentMode_Set_WhenConnected_ThenSendsExpectedCommand(string productName, string firmware, AlignmentModes alignmentMode, string expectedCommand) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(productName); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(firmware); + _telescope.Connected = true; + + _telescope.AlignmentMode = alignmentMode; + + _sharedResourcesWrapperMock.Verify( x => x.SendBlind(expectedCommand), Times.Once); + } + + [TestCase("AUTOSTAR", "43Ef")] + public void AlignmentMode_Set_WhenAutostarFirmwareToLow_ThenThrowsException(string productName, string firmware ) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(productName); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(firmware); + _telescope.Connected = true; + + var excpetion = Assert.Throws(() => { _telescope.AlignmentMode = AlignmentModes.algAltAz; }); + + Assert.That(excpetion.Property, Is.EqualTo("AlignmentMode")); + Assert.That(excpetion.AccessorSet, Is.True); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 3dab40a..b95c53a 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -482,14 +482,17 @@ namespace ASCOM.Meade.net //L If scope in Land Mode //P If scope in Polar Mode - //todo implement GW Command - //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); - //:GW# Get Scope Alignment Status - //Returns: # - // where: - //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial - //tracking: T - tracking, N - not tracking - //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + //todo implement GW Command - Supported in Autostar 43Eg and above + //if FirmwareIsGreaterThan(_sharedResourcesWrapper.AUTOSTAR497_43EG) + //{ + //var alignmentString = SerialPort.CommandTerminated(":GW#", "#"); + //:GW# Get Scope Alignment Status + //Returns: # + // where: + //mount: A - AzEl mounted, P - Equatorially mounted, G - german mounted equatorial + //tracking: T - tracking, N - not tracking + //alignment: 0 - needs alignment, 1 - one star aligned, 2 - two star aligned, 3 - three star aligned. + //} AlignmentModes alignmentMode; switch (alignmentString) @@ -515,7 +518,13 @@ namespace ASCOM.Meade.net { CheckConnected("AlignmentMode Set"); - switch (value) + //todo tidy this up into a better solution that means can :GW#, :AL#, :AA#, & :AP# and checked for Autostar properly + if (!FirmwareIsGreaterThan(_sharedResourcesWrapper.AUTOSTAR497_43EG)) + throw new PropertyNotImplementedException("AlignmentMode",true ); + + //todo make this only try with Autostar 43Eg and above. + + switch (value) { case AlignmentModes.algAltAz: _sharedResourcesWrapper.SendBlind(":AA#"); diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index 90caa72..a7f662c 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -10,6 +10,8 @@ namespace ASCOM.Meade.net.Wrapper string AUTOSTAR497 { get; } string AUTOSTAR497_31EE { get; } + string AUTOSTAR497_43EG { get;} + void Connect(string deviceId); void Disconnect(string deviceId); @@ -38,6 +40,7 @@ namespace ASCOM.Meade.net.Wrapper public string AUTOSTAR497 => "Autostar"; public string AUTOSTAR497_31EE => "31Ee"; + public string AUTOSTAR497_43EG => "43Eg"; #endregion From 69434454ca4fd52329ca6048b1a0c9e1a8589246 Mon Sep 17 00:00:00 2001 From: Colin Date: Sat, 13 Jul 2019 23:26:19 +0100 Subject: [PATCH 075/109] More unit test coverage --- .../TelescopeUnitTests.cs | 196 +++++++++++++++++- 1 file changed, 195 insertions(+), 1 deletion(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 4b4ab51..3f82e7a 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using ASCOM; using ASCOM.Astrometry.AstroUtils; using ASCOM.DeviceInterface; @@ -506,5 +505,200 @@ namespace Meade.net.Telescope.UnitTests Assert.That(excpetion.Property, Is.EqualTo("AlignmentMode")); Assert.That(excpetion.AccessorSet, Is.True); } + + [Test] + public void ApertureArea_Get_ThrowsNotImplementedException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.ApertureArea; }); + + Assert.That(excpetion.Property, Is.EqualTo("ApertureArea")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void ApertureDiameter_Get_ThrowsNotImplementedException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.ApertureDiameter; }); + + Assert.That(excpetion.Property, Is.EqualTo("ApertureDiameter")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void AtHome_Get_ReturnsFalse() + { + var result = _telescope.AtHome; + + Assert.That(result, Is.False); + } + + [Test] + public void AtPark_Get_WhenNotParked_ThenReturnsFalse() + { + var result = _telescope.AtPark; + + Assert.That(result, Is.False); + } + + [Test] + public void AtPark_Get_WhenParked_ThenReturnsTrue() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_43EG); + _telescope.Connected = true; + _telescope.Park(); + + var result = _telescope.AtPark; + + Assert.That(result, Is.True); + } + + [TestCase(TelescopeAxes.axisPrimary, 4)] + [TestCase(TelescopeAxes.axisSecondary, 4)] + [TestCase(TelescopeAxes.axisTertiary, 0)] + public void AxisRates_ReturnsExpectedResult(TelescopeAxes axis, int expectedCount) + { + var result = _telescope.AxisRates(axis); + + Assert.That(result.Count, Is.EqualTo(expectedCount)); + } + + [Test] + public void CanFindHome_Get_ReturnsFalse() + { + var result = _telescope.CanFindHome; + + Assert.That(result, Is.False); + } + + [TestCase(TelescopeAxes.axisPrimary, true)] + [TestCase(TelescopeAxes.axisSecondary, true)] + [TestCase(TelescopeAxes.axisTertiary, false)] + public void CanMoveAxis_ReturnsExpectedResult(TelescopeAxes axis, bool expected) + { + var result = _telescope.CanMoveAxis(axis); + + Assert.That(result, Is.EqualTo(expected)); + } + + [Test] + public void CanPark_Get_ReturnsTrue() + { + var result = _telescope.CanPark; + + Assert.That(result, Is.True); + } + + [Test] + public void CanPulseGuide_Get_ReturnsTrue() + { + var result = _telescope.CanPulseGuide; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSetDeclinationRate_Get_ReturnsFalse() + { + var result = _telescope.CanSetDeclinationRate; + + Assert.That(result, Is.False); + } + + [Test] + public void CanSetGuideRates_Get_ReturnsFalse() + { + var result = _telescope.CanSetGuideRates; + + Assert.That(result, Is.False); + } + + [Test] + public void CanSetPark_Get_ReturnsFalse() + { + var result = _telescope.CanSetPark; + + Assert.That(result, Is.False); + } + + [Test] + public void CanSetPierSide_Get_ReturnsFalse() + { + var result = _telescope.CanSetPierSide; + + Assert.That(result, Is.False); + } + + [Test] + public void CanSetRightAscensionRate_Get_ReturnsFalse() + { + var result = _telescope.CanSetRightAscensionRate; + + Assert.That(result, Is.False); + } + + [Test] + public void CanSetTracking_Get_ReturnsTrue() + { + var result = _telescope.CanSetTracking; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSlew_Get_ReturnsTrue() + { + var result = _telescope.CanSlew; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSlewAltAz_Get_ReturnsTrue() + { + var result = _telescope.CanSlewAltAz; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSlewAltAzAsync_Get_ReturnsTrue() + { + var result = _telescope.CanSlewAltAzAsync; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSlewAsync_Get_ReturnsTrue() + { + var result = _telescope.CanSlewAsync; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSync_Get_ReturnsTrue() + { + var result = _telescope.CanSync; + + Assert.That(result, Is.True); + } + + [Test] + public void CanSyncAltAz_Get_ReturnsFalse() + { + var result = _telescope.CanSyncAltAz; + + Assert.That(result, Is.False); + } + + [Test] + public void CanUnpark_Get_ReturnsFalse() + { + var result = _telescope.CanUnpark; + + Assert.That(result, Is.False); + } } } From 5f5d819f3b37ebdcfcae0a9d4821152e7634e87b Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 17:12:56 +0100 Subject: [PATCH 076/109] More unit tests added --- .../TelescopeUnitTests.cs | 298 ++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 10 +- 2 files changed, 304 insertions(+), 4 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 3f82e7a..e53cad0 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.Eventing.Reader; using ASCOM; using ASCOM.Astrometry.AstroUtils; using ASCOM.DeviceInterface; @@ -700,5 +701,302 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.False); } + + [Test] + public void Declination_Get_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var actualResult = _telescope.Declination; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Declination Get")); + } + + [TestCase("s12*34")] + [TestCase("s12*34’56")] + public void Declination_Get_WhenConnected_ThenReadsValueFromScope(string declincationString) + { + var expectedResult = 12.34; + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GD#")).Returns(declincationString); + _utilMock.Setup(x => x.DMSToDegrees(declincationString)).Returns(expectedResult); + + var actualResult = _telescope.Declination; + Assert.That(actualResult, Is.EqualTo(expectedResult)); + } + + [Test] + public void DeclinationRate_Get_ThenReturns0() + { + var actualResult = _telescope.DeclinationRate; + + Assert.That(actualResult, Is.EqualTo(0)); + } + + [Test] + public void DeclinationRate_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.DeclinationRate = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("DeclinationRate")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void DestinationSideOfPier_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.DestinationSideOfPier(0,0); }); + + Assert.That(excpetion.Method, Is.EqualTo("DestinationSideOfPier")); + } + + [Test] + public void DoesRefraction_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.DoesRefraction; }); + + Assert.That(excpetion.Property, Is.EqualTo("DoesRefraction")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void DoesRefraction_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.DoesRefraction = true; }); + + Assert.That(excpetion.Property, Is.EqualTo("DoesRefraction")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void EquatorialSystem_Get_ReturnsExpectedValue() + { + var actualResult = _telescope.EquatorialSystem; + + Assert.That(actualResult, Is.EqualTo(EquatorialCoordinateType.equTopocentric)); + } + + [Test] + public void FindHome_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.FindHome();}); + + Assert.That(excpetion.Method, Is.EqualTo("FindHome")); + } + + [Test] + public void FocalLength_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.FocalLength; }); + + Assert.That(excpetion.Property, Is.EqualTo("FocalLength")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void GuideRateDeclination_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.GuideRateDeclination; }); + + Assert.That(excpetion.Property, Is.EqualTo("GuideRateDeclination")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void GuideRateDeclination_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.GuideRateDeclination = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("GuideRateDeclination")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void GuideRateRightAscension_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.GuideRateRightAscension; }); + + Assert.That(excpetion.Property, Is.EqualTo("GuideRateRightAscension")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void GuideRateRightAscension_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.GuideRateRightAscension = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("GuideRateRightAscension")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void IsPulseGuiding_Get_ReturnsFalse() + { + var result = _telescope.IsPulseGuiding; + + Assert.That(result, Is.False); + } + + + [Test] + public void MoveAxis_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.MoveAxis(TelescopeAxes.axisPrimary, 0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: MoveAxis")); + } + + [TestCase( 0, "", TelescopeAxes.axisPrimary)] + [TestCase( 1, ":RG#", TelescopeAxes.axisPrimary)] + [TestCase(-1, ":RG#", TelescopeAxes.axisPrimary)] + [TestCase( 2, ":RC#", TelescopeAxes.axisPrimary)] + [TestCase(-2, ":RC#", TelescopeAxes.axisPrimary)] + [TestCase( 3, ":RM#", TelescopeAxes.axisPrimary)] + [TestCase(-3, ":RM#", TelescopeAxes.axisPrimary)] + [TestCase( 4, ":RS#", TelescopeAxes.axisPrimary)] + [TestCase(-4, ":RS#", TelescopeAxes.axisPrimary)] + [TestCase(0, "", TelescopeAxes.axisSecondary)] + [TestCase(1, ":RG#", TelescopeAxes.axisSecondary)] + [TestCase(-1, ":RG#", TelescopeAxes.axisSecondary)] + [TestCase(2, ":RC#", TelescopeAxes.axisSecondary)] + [TestCase(-2, ":RC#", TelescopeAxes.axisSecondary)] + [TestCase(3, ":RM#", TelescopeAxes.axisSecondary)] + [TestCase(-3, ":RM#", TelescopeAxes.axisSecondary)] + [TestCase(4, ":RS#", TelescopeAxes.axisSecondary)] + [TestCase(-4, ":RS#", TelescopeAxes.axisSecondary)] + public void MoveAxis_WhenConnected_ThenExecutesCorrectCommandSequence(double rate, string slewRateCommand, TelescopeAxes axis) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.MoveAxis(axis, rate); + + if (slewRateCommand != string.Empty) + _sharedResourcesWrapperMock.Verify( x => x.SendBlind(slewRateCommand), Times.Once); + else + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":RG#"), Times.Never); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":RC#"), Times.Never); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":RM#"), Times.Never); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":RS#"), Times.Never); + } + + switch (axis) + { + case TelescopeAxes.axisPrimary: + if (rate == 0) + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Qe#"), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Qw#"), Times.Once); + } + else if (rate > 0) + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Me#"), Times.Once); + } + else + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Mw#"), Times.Once); + } + break; + case TelescopeAxes.axisSecondary: + if (rate == 0) + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Qn#"), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Qs#"), Times.Once); + } + else if (rate > 0) + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Mn#"), Times.Once); + } + else + { + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":Ms#"), Times.Once); + } + break; + default: + Assert.Fail("This should never happen"); + break; + } + } + + [Test] + public void MoveAxis_WhenRateTooHigh_ThenThrowsException() + { + var testRate = 5; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws( () => { _telescope.MoveAxis(TelescopeAxes.axisTertiary, testRate); }); + + Assert.That(exception.Message, Is.EqualTo($"Rate {testRate} not supported")); + } + + [Test] + public void MoveAxis_WhenTertiaryAxis_ThenThrowsException() + { + var testRate = 0; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.MoveAxis(TelescopeAxes.axisTertiary, testRate); }); + + Assert.That(exception.Message, Is.EqualTo($"Can not move this axis.")); + } + + [Test] + public void Park_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.Park(); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Park")); + } + + [Test] + public void Park_WhenNotParked_ThenSendsParkCommand() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + Assert.That(_telescope.AtPark, Is.False); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Never); + + _telescope.Park(); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Once); + Assert.That(_telescope.AtPark, Is.True); + } + + [Test] + public void Park_WhenParked_ThenDoesNothing() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.Park(); + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Once); + Assert.That(_telescope.AtPark, Is.True); + + + //act + _telescope.Park(); + + //no change from previous state. + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Once); + Assert.That(_telescope.AtPark, Is.True); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index b95c53a..b5a4371 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -822,7 +822,7 @@ namespace ASCOM.Meade.net var result = _sharedResourcesWrapper.SendString(":GD#"); //:GD# Get Telescope Declination. - //Returns: sDD* MM# or sDD*MM’SS# + //Returns: sDD*MM# or sDD*MM’SS# //Depending upon the current precision setting for the telescope. double declination = _utilities.DMSToDegrees(result); @@ -850,7 +850,7 @@ namespace ASCOM.Meade.net public PierSide DestinationSideOfPier(double rightAscension, double declination) { LogMessage("DestinationSideOfPier Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DestinationSideOfPier", false); + throw new ASCOM.MethodNotImplementedException("DestinationSideOfPier"); } public bool DoesRefraction @@ -924,6 +924,7 @@ namespace ASCOM.Meade.net { get { + //Todo implement this if I can make the new pulse guiding async LogMessage("IsPulseGuiding Get", "pulse guiding is synchronous for this driver"); //throw new ASCOM.PropertyNotImplementedException("IsPulseGuiding", false); return false; @@ -1026,7 +1027,7 @@ namespace ASCOM.Meade.net break; default: - throw new ASCOM.MethodNotImplementedException("Can not move this axis."); + throw new ASCOM.InvalidValueException("Can not move this axis."); } } @@ -1080,7 +1081,8 @@ namespace ASCOM.Meade.net //Returns – Nothing //LX200 – Not Supported - _utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed + //todo implement IsPulseGuiding if WaitForMilliseconds is not needed + _utilities.WaitForMilliseconds(duration); //todo figure out if this is really needed } else { From e3f82ff2327248efd4006fb111d8b12538c2df7c Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 17:51:34 +0100 Subject: [PATCH 077/109] More unit tests --- .../TelescopeUnitTests.cs | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index e53cad0..d55d216 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -998,5 +998,204 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Once); Assert.That(_telescope.AtPark, Is.True); } + + [Test] + public void PulseGuide_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.PulseGuide(GuideDirections.guideEast,0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: PulseGuide")); + } + + [TestCase(GuideDirections.guideEast)] + [TestCase(GuideDirections.guideWest)] + [TestCase(GuideDirections.guideNorth)] + [TestCase(GuideDirections.guideSouth)] + public void PulseGuide_WhenConnectedAndNewerPulseGuidingAvailable_ThenSendsNewCommandsAndWaits(GuideDirections direction) + { + var duration = 0; + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.PulseGuide(direction, 0); + + string d = string.Empty; + switch (direction) + { + case GuideDirections.guideEast: + d = "e"; + break; + case GuideDirections.guideWest: + d = "w"; + break; + case GuideDirections.guideNorth: + d = "n"; + break; + case GuideDirections.guideSouth: + d = "s"; + break; + } + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind($":Mg{d}{duration:0000}#")); + _utilMock.Verify( x => x.WaitForMilliseconds(duration), Times.Once); + } + + [TestCase(GuideDirections.guideEast)] + [TestCase(GuideDirections.guideWest)] + [TestCase(GuideDirections.guideNorth)] + [TestCase(GuideDirections.guideSouth)] + public void PulseGuide_WhenConnectedAndNewerPulseGuidingNotAvailable_ThenSendsOldCommandsAndWaits(GuideDirections direction) + { + var duration = 0; + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => "31Ed"); + _telescope.Connected = true; + + _telescope.PulseGuide(direction, 0); + + string d = string.Empty; + switch (direction) + { + case GuideDirections.guideEast: + d = "e"; + break; + case GuideDirections.guideWest: + d = "w"; + break; + case GuideDirections.guideNorth: + d = "n"; + break; + case GuideDirections.guideSouth: + d = "s"; + break; + } + + _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":RG#")); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind($":M{d}#")); + _utilMock.Verify(x => x.WaitForMilliseconds(duration), Times.Once); + _sharedResourcesWrapperMock.Verify(x => x.SendBlind($":Q{d}#")); + } + + [Test] + public void RightAscension_Get_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.RightAscension; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: RightAscension Get")); + } + + [Test] + public void RightAscension_Get_WhenConnected_ThenReturnsExpectedResult() + { + var telescopeRaResult = "HH:MM:SS"; + var hmsResult = 1.2; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GR#")).Returns(telescopeRaResult); + + _utilMock.Setup(x => x.HMSToHours(telescopeRaResult)).Returns(hmsResult); + + var result = _telescope.RightAscension; + + _sharedResourcesWrapperMock.Verify( x => x.SendString(":GR#"), Times.Once); + _utilMock.Verify( x => x.HMSToHours(telescopeRaResult), Times.Once); + + Assert.That(result,Is.EqualTo(hmsResult)); + } + + [Test] + public void RightAscensionRate_Get_ThenReturns0() + { + var result = _telescope.RightAscensionRate; + + Assert.That(result, Is.EqualTo(0)); + } + + [Test] + public void RightAscensionRate_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.RightAscensionRate = 1; }); + + Assert.That(excpetion.Property, Is.EqualTo("RightAscensionRate")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void SetPark_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.SetPark(); }); + + Assert.That(excpetion.Method, Is.EqualTo("SetPark")); + } + + [Test] + public void SideOfPier_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.SideOfPier; }); + + Assert.That(excpetion.Property, Is.EqualTo("SideOfPier")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void SideOfPier_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.SideOfPier = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("SideOfPier")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void SiteElevation_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.SiteElevation; }); + + Assert.That(excpetion.Property, Is.EqualTo("SiteElevation")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void SiteElevation_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.SiteElevation = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("SiteElevation")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void SlewSettleTime_Get_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { var result = _telescope.SlewSettleTime; }); + + Assert.That(excpetion.Property, Is.EqualTo("SlewSettleTime")); + Assert.That(excpetion.AccessorSet, Is.False); + } + + [Test] + public void SlewSettleTime_Set_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.SlewSettleTime = 0; }); + + Assert.That(excpetion.Property, Is.EqualTo("SlewSettleTime")); + Assert.That(excpetion.AccessorSet, Is.True); + } + + [Test] + public void Unpark_ThenThrowsException() + { + var excpetion = Assert.Throws(() => { _telescope.Unpark(); }); + + Assert.That(excpetion.Method, Is.EqualTo("Unpark")); + } } } From 34a145765b414ff4b37b49b13b72f2df4fba8efb Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 21:47:02 +0100 Subject: [PATCH 078/109] More unit testing Fixed issue when setting site latitude to negative value. --- .../TelescopeUnitTests.cs | 94 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 9 +- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index d55d216..222876c 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1197,5 +1197,99 @@ namespace Meade.net.Telescope.UnitTests Assert.That(excpetion.Method, Is.EqualTo("Unpark")); } + + [Test] + public void SiteLatitude_Get_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.SiteLatitude; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLatitude Get")); + } + + [Test] + public void SiteLatitude_Get_WhenConnected_ThenRetrievesAndReturnsExpectedValue() + { + var siteLatitudeString = "testLatString"; + var siteLatitudeValue = 123.45; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gt#")).Returns(siteLatitudeString); + _utilMock.Setup(x => x.DMSToDegrees(siteLatitudeString)).Returns(siteLatitudeValue); + + var result = _telescope.SiteLatitude; + + _sharedResourcesWrapperMock.Verify( x => x.SendString(":Gt#"), Times.Once); + + Assert.That(result,Is.EqualTo(siteLatitudeValue)); + } + + [Test] + public void SiteLatitude_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SiteLatitude = 123.45; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLatitude Set")); + } + + [Test] + public void SiteLatitude_Set_WhenConnectedAndLatitudeIsGreaterThan90_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SiteLatitude = 90.01; }); + Assert.That(exception.Message, Is.EqualTo("Latitude cannot be greater than 90 degrees.")); + } + + [Test] + public void SiteLatitude_Set_WhenConnectedAndLatitudeIsLessThanNegative90_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SiteLatitude = -90.01; }); + Assert.That(exception.Message, Is.EqualTo("Latitude cannot be less than -90 degrees.")); + } + + [TestCase(-10.5)] + [TestCase(20.75)] + public void SiteLatitude_Set_WhenValueSetAndTelescopRejects_ThenExceptionThrown(double siteLatitude) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.SiteLatitude = siteLatitude; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to set site latitude.")); + } + + [TestCase(-10.5, ":St-10*30#")] + [TestCase(20.75, ":St+20*45#")] + public void SiteLatitude_Set_WhenValidValues_ThenValueSentToTelescope(double siteLatitude, string expectedCommand) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(expectedCommand)).Returns("1"); + + _telescope.SiteLatitude = siteLatitude; + + _sharedResourcesWrapperMock.Verify(x => x.SendChar(expectedCommand), Times.Once); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index b5a4371..33f3234 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1234,10 +1234,13 @@ namespace ASCOM.Meade.net throw new InvalidValueException("Latitude cannot be less than -90 degrees."); string sign = value > 0 ? "+" : "-"; - int d = Convert.ToInt32(Math.Floor(value)); - int m = Convert.ToInt32(60 * (value - d)); - var result = _sharedResourcesWrapper.SendChar($":St{sign}{d:00}*{m:00}#"); + var absValue = Math.Abs(value); + int d = Convert.ToInt32(Math.Floor(absValue)); + int m = Convert.ToInt32(60 * (absValue - d)); + var commandString = $":St{sign}{d:00}*{m:00}#"; + + var result = _sharedResourcesWrapper.SendChar(commandString); //:StsDD*MM# //Sets the current site latitude to sDD* MM# //Returns: From 73e8e8ffe81c5eaf96e83cabfd6826500a44872d Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:05:25 +0100 Subject: [PATCH 079/109] More unit testing --- .../TelescopeUnitTests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 222876c..4cc8ac7 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1291,5 +1291,37 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar(expectedCommand), Times.Once); } + + [Test] + public void SiteLongitude_Get_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.SiteLongitude; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLongitude Get")); + } + + + //todo figure out if this is right. don't feel right to me + [TestCase("5", 5, -5)] + [TestCase("-5", -5, 5)] + [TestCase("185", 185, 175)] + [TestCase("350", 350, 10)] + public void SiteLongitude_Get_WhenConnected_ThenRetrivesAndReturnsExpectedValue(string telescopelongitudeString, double telescopeLongitudeValue, double expectedResult) + { + var telescopeLongitude = "testLongitude"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gg#")).Returns(telescopeLongitude); + _utilMock.Setup(x => x.DMSToDegrees(telescopeLongitude)).Returns(telescopeLongitudeValue); + + var result = _telescope.SiteLongitude; + + Assert.That(result, Is.EqualTo(expectedResult)); + } } } From 112fdf0bb987cc5b5aa104ad2eef0d4cbd4f3fd4 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:14:43 +0100 Subject: [PATCH 080/109] Experiment on build.build to see if I can rename the msi file --- build.build | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.build b/build.build index 6f09681..80c6c03 100644 --- a/build.build +++ b/build.build @@ -4,6 +4,7 @@ + @@ -32,5 +33,13 @@ + + + + + + + + \ No newline at end of file From 07569b146e6f8df9cd3bb28cf2ef100f67a2cd24 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:19:05 +0100 Subject: [PATCH 081/109] Trying the nant variable inside the string. --- build.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.build b/build.build index 80c6c03..6d55f45 100644 --- a/build.build +++ b/build.build @@ -38,7 +38,7 @@ - + From 12c11b49874483ba74970b5299b0964b394544c8 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:19:55 +0100 Subject: [PATCH 082/109] Removed unneeded comments --- build.build | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.build b/build.build index 6d55f45..12275ea 100644 --- a/build.build +++ b/build.build @@ -35,9 +35,7 @@ - - From a7904d7485e4ccac8ffa57a3553debfde184511b Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:28:32 +0100 Subject: [PATCH 083/109] Another attempt at the version number rename. --- build.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.build b/build.build index 12275ea..ec7f5f2 100644 --- a/build.build +++ b/build.build @@ -4,7 +4,7 @@ - + @@ -36,7 +36,7 @@ - + From 2846e9f7190c998d942ad9e4e7d8a081cd4e33cf Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:32:38 +0100 Subject: [PATCH 084/109] Anotther try. --- build.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.build b/build.build index ec7f5f2..4576cda 100644 --- a/build.build +++ b/build.build @@ -4,7 +4,7 @@ - + @@ -36,7 +36,7 @@ - + From e89f01ed516f25c7e1169a1254d4649dca701965 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:40:45 +0100 Subject: [PATCH 085/109] Another try --- build.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.build b/build.build index 4576cda..1b017d7 100644 --- a/build.build +++ b/build.build @@ -4,7 +4,7 @@ - + @@ -36,7 +36,7 @@ - + From 0475217d6253e929fd5a60ab7c11940158c21f40 Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 22:56:32 +0100 Subject: [PATCH 086/109] Trying to read the BUILD_NUMBER from the environment. --- build.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.build b/build.build index 1b017d7..3a1403f 100644 --- a/build.build +++ b/build.build @@ -4,7 +4,6 @@ - @@ -36,7 +35,7 @@ - + From a6308f1a64c2bfe422b96b691ae8c258f1aa87af Mon Sep 17 00:00:00 2001 From: Colin Date: Sun, 14 Jul 2019 23:00:15 +0100 Subject: [PATCH 087/109] Added a missing . to the name file name. Working :) --- build.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.build b/build.build index 3a1403f..e66f39f 100644 --- a/build.build +++ b/build.build @@ -35,7 +35,7 @@ - + From ee60613a95d6c0ae9db22a01a5bd85cc8c165e5d Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 15 Jul 2019 00:16:08 +0100 Subject: [PATCH 088/109] More unit testing --- .../TelescopeUnitTests.cs | 60 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 4 +- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 4cc8ac7..ac9b72e 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -9,6 +9,7 @@ using ASCOM.Meade.net.Wrapper; using ASCOM.Utilities.Interfaces; using Moq; using NUnit.Framework; +using InvalidOperationException = ASCOM.InvalidOperationException; using NotImplementedException = ASCOM.NotImplementedException; namespace Meade.net.Telescope.UnitTests @@ -1323,5 +1324,64 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(expectedResult)); } + + [Test] + public void SiteLongitude_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SiteLongitude = 123.45; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLongitude Set")); + } + + [Test] + public void SiteLongitude_Set_WhenConnectedAndGreaterThan180_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SiteLongitude = 180.1; }); + Assert.That(exception.Message, Is.EqualTo("Longitude cannot be greater than 180 degrees.")); + } + + [Test] + public void SiteLongitude_Set_WhenConnectedAndLessThanNegative180_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SiteLongitude = -180.1; }); + Assert.That(exception.Message, Is.EqualTo("Longitude cannot be lower than -180 degrees.")); + } + + [Test] + public void SiteLongitude_Set_WhenConnectedAndTelescopeFails_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.SiteLongitude = 10; }); + Assert.That(exception.Message, Is.EqualTo("Failed to set site longitude.")); + } + + [TestCase(10, ":Sg350*00#")] + public void SiteLongitude_Set_WhenConnectedAndTelescopeFails_ThenThrowsException(double longitude, string expectedCommand) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(expectedCommand)).Returns("1"); + + _telescope.SiteLongitude = longitude; + + _sharedResourcesWrapperMock.Verify(x => x.SendChar(expectedCommand), Times.Once); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 33f3234..25c98b8 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1293,7 +1293,9 @@ namespace ASCOM.Meade.net int d = Convert.ToInt32(Math.Floor(newLongitude)); int m = Convert.ToInt32(60 * (newLongitude - d)); - var result = _sharedResourcesWrapper.SendChar($":Sg{d:000}*{m:00}#"); + var commandstring = $":Sg{d:000}*{m:00}#"; + + var result = _sharedResourcesWrapper.SendChar(commandstring); //:SgDDD*MM# //Set current site’s longitude to DDD*MM an ASCII position string //Returns: From 0ac7b8b7bddf7ba93942020a9369260f01eab811 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 16 Jul 2019 22:03:56 +0100 Subject: [PATCH 089/109] Unit tests for TargetDeclination --- .../TelescopeUnitTests.cs | 144 ++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 14 +- 2 files changed, 152 insertions(+), 6 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index ac9b72e..ca26daf 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1383,5 +1383,149 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar(expectedCommand), Times.Once); } + + [Test] + public void SyncToAltAz_WhenConnected_ThenSendsExpectedMessage() + { + string expectedMessage = "test blind Message"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SyncToAltAz(0,0); }); + + Assert.That(exception.Message, Is.EqualTo("Method SyncToAltAz is not implemented in this driver.")); + } + + [Test] + public void SyncToTarget_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SyncToTarget(); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SyncToTarget")); + } + + [Test] + public void SyncToTarget_WhenSyncToTargetFails_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":CM#")).Returns(string.Empty); + + var exception = Assert.Throws(() => { _telescope.SyncToTarget(); } ); + + Assert.That(exception.Message, Is.EqualTo("Unable to perform sync")); + _sharedResourcesWrapperMock.Verify(x => x.SendString(":CM#"), Times.Once); + } + + [Test] + public void SyncToTarget_WhenSyncToTargetWorks_ThennoExceptionThrown() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":CM#")).Returns(" M31 EX GAL MAG 3.5 SZ178.0'#"); + + Assert.DoesNotThrow(() => { _telescope.SyncToTarget(); }); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(":CM#"), Times.Once); + } + + [Test] + public void TargetDeclination_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.TargetDeclination = 0; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TargetDeclination Set")); + } + + [Test] + public void TargetDeclination_Set_WhenValueTooHigh_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.TargetDeclination = 90.1; }); + Assert.That(exception.Message, Is.EqualTo("Declination cannot be greater than 90.")); + } + + [Test] + public void TargetDeclination_Set_WhenValueTooLow_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.TargetDeclination = -90.1; }); + Assert.That(exception.Message, Is.EqualTo("Declination cannot be less than -90.")); + } + + [Test] + public void TargetDeclination_Set_WhenTelescopeReportsInvalidDec_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.TargetDeclination = 50; }); + Assert.That(exception.Message, Is.EqualTo("Target declination invalid")); + } + + [TestCase(-30.5, "-30*30:00", ":Sd-30*30:00#")] + [TestCase(30.5, "30*30:00", ":Sd+30*30:00#")] + [TestCase(-75.25, "-75*15:00", ":Sd-75*15:00#")] + [TestCase(50, "50*00:00", ":Sd+50*00:00#")] + public void TargetDeclination_Set_WhenValueOK_ThenSetsNewTargetDeclination( double declination,string decstring, string commandString) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _utilMock.Setup(x => x.DegreesToDMS(declination, "*", ":", ":", 2)).Returns(decstring); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); + + _telescope.TargetDeclination = declination; + + _sharedResourcesWrapperMock.Verify(x => x.SendChar(commandString),Times.Once); + } + + [Test] + public void TargetDeclination_Get_WhenTargetNotSet_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { var result = _telescope.TargetDeclination; }); + Assert.That(exception.Message, Is.EqualTo("Target not set")); + } + + [TestCase(50, "50*00:00", ":Sd+50*00:00#")] + public void TargetDeclination_Get_WhenValueOK_ThenSetsNewTargetDeclination(double declination, string decstring, string commandString) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _utilMock.Setup(x => x.DegreesToDMS(declination, "*", ":", ":", 2)).Returns(decstring); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); + + _telescope.TargetDeclination = declination; + + var result = _telescope.TargetDeclination; + + Assert.That(result, Is.EqualTo(declination)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 25c98b8..6b7e8ce 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -309,8 +309,10 @@ namespace ASCOM.Meade.net SetLongFormat(true); _userNewerPulseGuiding = IsNewPulseGuidingSupported(); - LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); + _targetDeclination = INVALID_PARAMETER; + _targetRightAscension = INVALID_PARAMETER; + LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); IsConnected = true; } catch (Exception) @@ -1601,7 +1603,7 @@ namespace ASCOM.Meade.net //:CM# Synchronizes the telescope's position with the currently selected database object's coordinates. //Returns: //LX200's - a "#" terminated string with the name of the object that was synced. - // Autostars & Autostar II - At static string: " M31 EX GAL MAG 3.5 SZ178.0'#" + // Autostars & Autostar II - A static string: " M31 EX GAL MAG 3.5 SZ178.0'#" if (result == string.Empty) throw new ASCOM.InvalidOperationException("Unable to perform sync"); @@ -1630,16 +1632,16 @@ namespace ASCOM.Meade.net set { LogMessage("TargetDeclination Set", $"{value}"); - + + CheckConnected("TargetDeclination Set"); + //todo implement low precision version of this. if (value > 90) throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); if (value < -90) throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); - - CheckConnected("TargetDeclination Set"); - + var dms = _utilities.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? string.Empty : "+"; From bfb8f257a10c5262dc06b83d0ac9328384d7ef6e Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 16 Jul 2019 23:22:41 +0100 Subject: [PATCH 090/109] Unit tests for TargetRightAscension --- .../TelescopeUnitTests.cs | 89 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 3 +- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index ca26daf..ab017f5 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1527,5 +1527,94 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(declination)); } + + [Test] + public void TargetRightAscension_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.TargetRightAscension = 0; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TargetRightAscension Set")); + } + + [Test] + public void TargetRightAscension_Set_WhenValueTooHigh_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.TargetRightAscension = 24; }); + Assert.That(exception.Message, Is.EqualTo("Right ascension value cannot be greater than 23:59:59")); + } + + [Test] + public void TargetRightAscension_Set_WhenValueTooLow_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.TargetRightAscension = -0.1; }); + Assert.That(exception.Message, Is.EqualTo("Right ascension value cannot be below 0")); + } + + [Test] + public void TargetRightAscension_Set_WhenTelescopeReportsInvalidRA_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.TargetRightAscension = 1; }); + Assert.That(exception.Message, Is.EqualTo("Failed to set TargetRightAscension.")); + } + + [TestCase(5.5, "05:30:00", ":Sr05:30:00#")] + [TestCase(10, "10:00:00", ":Sr10:00:00#")] + public void TargetRightAscension_Set_WhenValueOK_ThenSetsNewTargetDeclination(double rightAscension, string hms, string commandString) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); + + _telescope.TargetRightAscension = rightAscension; + + _sharedResourcesWrapperMock.Verify(x => x.SendChar(commandString), Times.Once); + } + + [Test] + public void TargetRightAscension_Get_WhenTargetNotSet_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { var result = _telescope.TargetRightAscension; }); + Assert.That(exception.Message, Is.EqualTo("Target not set")); + } + + [TestCase(15, "15:00:00", ":Sr15:00:00#")] + public void TargetRightAscension_Get_WhenValueOK_ThenSetsNewTargetDeclination(double rightAscension, string hms, string commandString) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); + + _telescope.TargetRightAscension = rightAscension; + + var result = _telescope.TargetRightAscension; + + Assert.That(result, Is.EqualTo(rightAscension)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 6b7e8ce..5169308 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1686,14 +1686,13 @@ namespace ASCOM.Meade.net set { LogMessage("TargetRightAscension Set", $"{value}"); + CheckConnected("TargetRightAscension Set"); if (value < 0) throw new InvalidValueException("Right ascension value cannot be below 0"); if (value >= 24) throw new InvalidValueException("Right ascension value cannot be greater than 23:59:59"); - - CheckConnected("TargetRightAscension Set"); //todo implement the low precision version var hms = _utilities.HoursToHMS(value, ":", ":", ":", 2); From b3b1d95cda63fb97ad2ae0631edb1cfbd9840ed8 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 16 Jul 2019 23:33:53 +0100 Subject: [PATCH 091/109] Unit tests for Tracking property --- .../TelescopeUnitTests.cs | 17 +++++++++++++++++ Meade.net.Telescope/Telescope.cs | 1 + 2 files changed, 18 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index ab017f5..a7282be 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1616,5 +1616,22 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(rightAscension)); } + + [Test] + public void Tracking_Get_WhenDefault_ThenIsTrue() + { + Assert.That(_telescope.Tracking, Is.True); + } + + [TestCase(true)] + [TestCase(false)] + public void Tracking_SetAndGet_WhenValueSet_ThenCanGetNewValue(bool tracking) + { + _telescope.Tracking = tracking; + + Assert.That(_telescope.Tracking, Is.EqualTo( tracking)); + } + + } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 5169308..a79b7c4 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -311,6 +311,7 @@ namespace ASCOM.Meade.net _userNewerPulseGuiding = IsNewPulseGuidingSupported(); _targetDeclination = INVALID_PARAMETER; _targetRightAscension = INVALID_PARAMETER; + _tracking = true; LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); IsConnected = true; From 83865a3911dc6282f527bbf62624957a118f8873 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 17 Jul 2019 11:30:49 +0100 Subject: [PATCH 092/109] Unit testing for TrackingRate --- .../TelescopeUnitTests.cs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index a7282be..065a420 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1632,6 +1632,66 @@ namespace Meade.net.Telescope.UnitTests Assert.That(_telescope.Tracking, Is.EqualTo( tracking)); } + [Test] + public void TrackingRate_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + var exception = Assert.Throws(() => { _telescope.TrackingRate = DriveRates.driveSidereal; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TrackingRate Set")); + } + + [TestCase(DriveRates.driveSidereal, ":TQ#")] + [TestCase(DriveRates.driveLunar, ":TL#")] + public void TrackingRate_Set_WhenConnected_ThenSendsCommandToTelescope(DriveRates rate, string commandString) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TrackingRate = rate; + + _sharedResourcesWrapperMock.Verify( x => x.SendBlind(commandString), Times.Once); + } + + [Test] + public void TrackingRate_Set_WhenUnSupportedRateSet_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws( () => { _telescope.TrackingRate = DriveRates.driveKing; }); + + Assert.That(exception.Message, Is.EqualTo("Exception of type 'System.ArgumentOutOfRangeException' was thrown.\r\nParameter name: value\r\nActual value was driveKing.")); + } + + [Test] + public void TrackingRage_Get_WhenReadongDefaultValue_ThenAssumesSidereal() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var result = _telescope.TrackingRate; + + Assert.That(result, Is.EqualTo(DriveRates.driveSidereal)); + } + + [TestCase(DriveRates.driveSidereal)] + [TestCase(DriveRates.driveLunar)] + public void TrackingRate_Get_WhenConnected_ThenSendsCommandToTelescope(DriveRates rate) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TrackingRate = rate; + + var result = _telescope.TrackingRate; + + Assert.That(result, Is.EqualTo(rate)); + } } } From 325e9908a7cffb4c3f597d0768a641c5a555267d Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 17 Jul 2019 14:42:28 +0100 Subject: [PATCH 093/109] Unit testing for UTCDate --- .../TelescopeUnitTests.cs | 129 +++++++++++++++++- Meade.net.Telescope/Telescope.cs | 14 +- 2 files changed, 135 insertions(+), 8 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 065a420..1486a32 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -44,7 +44,8 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_43EG) .Returns(() => "43Eg"); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); - + _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny>())).Returns>( (func) => func()); + _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); _astroMathsMock = new Mock(); @@ -1693,5 +1694,131 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.EqualTo(rate)); } + + [Test] + public void TrackingRates_Get_ReturnsExpectedType() + { + var result = _telescope.TrackingRates; + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.AssignableTo()); + } + + [Test] + public void UTCDate_Get_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.UTCDate; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: UTCDate Get")); + } + + [TestCase("10/15/20", "20:15:10", "-1.0", 2020, 10, 15, 19, 15, 10)] + [TestCase("12/03/15", "21:30:45", "+0.0", 2015, 12, 3, 21, 30, 45)] + public void UTCDate_Get_WhenConnected_ThenReturnsUTCDateTime(string telescopeDate, string telescopeTime, + string telescopeUtcCorrection, int year, int month, int day, int hour, int min, int second) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns(telescopeDate); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns(telescopeTime); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); + + var result = _telescope.UTCDate; + + Assert.That(result, Is.Not.Null); + Assert.That(result, Is.AssignableTo()); + Assert.That(result.Kind, Is.EqualTo(DateTimeKind.Utc)); + Assert.That(result.Year, Is.EqualTo(year)); + Assert.That(result.Month, Is.EqualTo(month)); + Assert.That(result.Day, Is.EqualTo(day)); + Assert.That(result.Hour, Is.EqualTo(hour)); + Assert.That(result.Minute, Is.EqualTo(min)); + Assert.That(result.Second, Is.EqualTo(second)); + } + + [Test] + public void UTCDate_Set_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.UTCDate = new DateTime(2010,10,15,16,42,32, DateTimeKind.Utc); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: UTCDate Set")); + } + + [TestCase("10/15/20", "20:15:10", "-1.0", 2020, 10, 15, 19, 15, 10)] + [TestCase("12/03/15", "21:30:45", "+0.0", 2015, 12, 3, 21, 30, 45)] + public void UTCDate_Set_WhenFailsToSetTelescopeTime_ThenThrowsException(string telescopeDate, string telescopeTime, string telescopeUtcCorrection, int year, int month, int day, int hour, int min, int second) + { + double utcOffsetHours = double.Parse(telescopeUtcCorrection); + TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); + + var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.UTCDate = newDate; } ); + + Assert.That(exception.Message, Is.EqualTo("Failed to set local time")); + } + + [TestCase("10/15/20", "20:15:10", "-1.0", 2020, 10, 15, 20, 15, 10)] + [TestCase("12/03/15", "21:30:45", "+0.0", 2015, 12, 3, 21, 30, 45)] + public void UTCDate_Set_WhenFailsToSetTelescopeDate_ThenThrowsException(string telescopeDate, string telescopeTime, string telescopeUtcCorrection, int year, int month, int day, int hour, int min, int second) + { + double utcOffsetHours = double.Parse(telescopeUtcCorrection); + TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); + + var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; + + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("1"); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SC{newDate:MM/dd/yy}#")).Returns("0"); + + var exception = Assert.Throws(() => { _telescope.UTCDate = newDate; }); + + Assert.That(exception.Message, Is.EqualTo("Failed to set local date")); + } + + [TestCase("10/15/20", "20:15:10", "-1.0", 2020, 10, 15, 20, 15, 10)] + [TestCase("12/03/15", "21:30:45", "+0.0", 2015, 12, 3, 21, 30, 45)] + public void UTCDate_Set_WhenSucceeds_ThenReadsTwoStringsFromTelescope(string telescopeDate, + string telescopeTime, string telescopeUtcCorrection, int year, int month, int day, int hour, int min, + int second) + { + double utcOffsetHours = double.Parse(telescopeUtcCorrection); + TimeSpan utcCorrection = TimeSpan.FromHours(utcOffsetHours); + + var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; + + + _sharedResourcesWrapperMock.Setup(x => x.ProductName) + .Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion) + .Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("1"); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SC{telescopeDate}#")).Returns("1"); + + _telescope.UTCDate = newDate; + + _sharedResourcesWrapperMock.Verify(x => x.ReadTerminated(), Times.Exactly(2)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index a79b7c4..f10c804 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1798,8 +1798,6 @@ namespace ASCOM.Meade.net private TimeSpan GetUtcCorrection() { - CheckConnected("GetUtcCorrection"); - string utcOffSet = _sharedResourcesWrapper.SendString(":GG#"); //:GG# Get UTC offset time //Returns: sHH# or sHH.H# @@ -1810,7 +1808,7 @@ namespace ASCOM.Meade.net return utcCorrection; } - private class TelescopeDateDetails + public class TelescopeDateDetails { public string telescopeDate { get; set; } public string telescopeTime { get; set; } @@ -1830,11 +1828,11 @@ namespace ASCOM.Meade.net TelescopeDateDetails tdd = new TelescopeDateDetails(); tdd.telescopeDate = _sharedResourcesWrapper.SendString(":GC#"); //:GC# Get current date. - //Returns: MM / DD / YY# + //Returns: MM/DD/YY# //The current local calendar date for the telescope. tdd.telescopeTime = _sharedResourcesWrapper.SendString(":GL#"); //:GL# Get Local Time in 24 hour format - //Returns: HH: MM: SS# + //Returns: HH:MM:SS# //The Local Time in 24 - hour Format tdd.utcCorrection = GetUtcCorrection(); @@ -1872,7 +1870,8 @@ namespace ASCOM.Meade.net var utcCorrection = GetUtcCorrection(); var localDateTime = value - utcCorrection; - var timeResult = _sharedResourcesWrapper.SendChar($":SL{localDateTime:HH:mm:ss}#"); + string localStingCommand = $":SL{localDateTime:HH:mm:ss}#"; + var timeResult = _sharedResourcesWrapper.SendChar(localStingCommand); //:SLHH:MM:SS# //Set the local Time //Returns: @@ -1883,7 +1882,8 @@ namespace ASCOM.Meade.net throw new InvalidOperationException("Failed to set local time"); } - var dateResult = _sharedResourcesWrapper.SendChar($":SC{localDateTime:MM/dd/yy}#"); + string localDateCommand = $":SC{localDateTime:MM/dd/yy}#"; + var dateResult = _sharedResourcesWrapper.SendChar(localDateCommand); //:SCMM/DD/YY# //Change Handbox Date to MM/DD/YY //Returns: From a53f99810dafaa69f24f4684b083bd34a3264dd5 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 17 Jul 2019 15:35:32 +0100 Subject: [PATCH 094/109] More unit testing --- .../TelescopeUnitTests.cs | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 1486a32..347528f 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1806,10 +1806,8 @@ namespace Meade.net.Telescope.UnitTests var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; - _sharedResourcesWrapperMock.Setup(x => x.ProductName) - .Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion) - .Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); _telescope.Connected = true; _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); @@ -1820,5 +1818,31 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.ReadTerminated(), Times.Exactly(2)); } + + [Test] + public void SyncToCoordinates_WhenNotConnected_ThenThrowsException() + { + double rightAscension = 5.5; + string hms = "05:30:00"; + + double declination = -30.5; + string dec = "-30*30:00"; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":Sr{hms}#")).Returns("1"); + + _utilMock.Setup(x => x.DegreesToDMS(declination, "*", ":", ":", 2)).Returns(dec); + _sharedResourcesWrapperMock.Setup(x => x.SendChar($":Sd{dec}#")).Returns("1"); + + _telescope.SyncToCoordinates(rightAscension, declination); + + _sharedResourcesWrapperMock.Verify( x => x.SendString(":CM#"), Times.Once); + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); + } } } From fdeee5b822db68214e07a45976bcc74d9ecf071a Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 17 Jul 2019 22:58:53 +0100 Subject: [PATCH 095/109] Unit tests for slewing --- .../TelescopeUnitTests.cs | 61 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 6 ++ 2 files changed, 67 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 347528f..b5119b8 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1844,5 +1844,66 @@ namespace Meade.net.Telescope.UnitTests Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); } + + [Test] + public void Slewing_WhenNotConnected_ThenReturnsFalse() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var result = _telescope.Slewing; + + Assert.That(result, Is.False); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(":D#"), Times.Never); + } + + [Test] + public void Slewing_WhenConnectedAndTelescopeFails_ThenReturnsFalse() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var result = _telescope.Slewing; + + Assert.That(result, Is.False); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(":D#"), Times.Once); + } + + [Test] + public void Slewing_WhenTelescopeIsSlewing_ThenReturnsTrue() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns("|"); + + var result = _telescope.Slewing; + + Assert.That(result, Is.True); + + _sharedResourcesWrapperMock.Verify(x => x.SendString(":D#"),Times.Once); + } + + [TestCase(1, TelescopeAxes.axisPrimary)] + [TestCase(-1, TelescopeAxes.axisPrimary)] + [TestCase(1, TelescopeAxes.axisSecondary)] + [TestCase(-1, TelescopeAxes.axisSecondary)] + public void Slewing_WhenTelescopeIsMoving_ThenDoesNotSendCommandAndReturnsTrue(int rate, TelescopeAxes axis) + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.MoveAxis(axis, rate); + + var result = _telescope.Slewing; + + Assert.That(result, Is.True); + _sharedResourcesWrapperMock.Verify(x => x.SendString(":D#"), Times.Never); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index f10c804..c97b264 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1568,6 +1568,12 @@ namespace ASCOM.Meade.net //Returns: //LX200's – a string of bar characters indicating the distance. //Autostars and Autostar II – a string containing one bar until a slew is complete, then a null string is returned. + + if (result == null) + { + return false; + } + bool isSlewing = result != string.Empty; LogMessage("Slewing Get", $"Result = {isSlewing}"); From 1d5dcb529ee96cdcffac5e739915a04172e22810 Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 17 Jul 2019 23:20:26 +0100 Subject: [PATCH 096/109] Unit tests for slew to target async --- .../TelescopeUnitTests.cs | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index b5119b8..c1a08c7 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1905,5 +1905,109 @@ namespace Meade.net.Telescope.UnitTests Assert.That(result, Is.True); _sharedResourcesWrapperMock.Verify(x => x.SendString(":D#"), Times.Never); } + + + [Test] + public void SlewToTargetAsync_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToTargetAsync")); + } + + [Test] + public void SlewToTargetAsync_WhenTargetDeclinationNotSet_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 1; + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("Target not set")); + } + + [Test] + public void SlewToTargetAsync_WhenTargetRightAscensionNotSet_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetDeclination = 1; + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("Target not set")); + } + + [Test] + public void SlewToTargetAsync_WhenTargetSet_ThenAttemptsSlew() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 2; + _telescope.TargetDeclination = 1; + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("This error should not happen")); + } + + [Test] + public void SlewToTargetAsync_WhenTargetSetAndSlewIsPossible_ThenAttemptsSlew() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 2; + _telescope.TargetDeclination = 1; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + _telescope.SlewToTargetAsync(); + + _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); + } + + [Test] + public void SlewToTargetAsync_WhenTargetBelowHorizon_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 2; + _telescope.TargetDeclination = 1; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("1"); + + _sharedResourcesWrapperMock.Setup(x => x.ReadTerminated()).Returns("Below horizon"); + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("Below horizon")); + } + + [Test] + public void SlewToTargetAsync_WhenTargetBelowElevation_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 2; + _telescope.TargetDeclination = 1; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("2"); + + _sharedResourcesWrapperMock.Setup(x => x.ReadTerminated()).Returns("Above below elevation"); + + var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); + Assert.That(exception.Message, Is.EqualTo("Above below elevation")); + } } } From aeaaf9df954c7c136252283228df17f8665aff1a Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 18 Jul 2019 12:31:09 +0100 Subject: [PATCH 097/109] More unit testing --- .../TelescopeUnitTests.cs | 38 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 1 - 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index c1a08c7..db8c115 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2009,5 +2009,43 @@ namespace Meade.net.Telescope.UnitTests var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); Assert.That(exception.Message, Is.EqualTo("Above below elevation")); } + + [Test] + public void SlewToTarget_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToTarget(); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToTarget")); + } + + [Test] + public void SlewToTarget_WhenSlewing_ThenWaitsForTheSlewToComplete() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.TargetRightAscension = 2; + _telescope.TargetDeclination = 1; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + var slewCounter = 0; + var iterations = 10; + _sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns(() => + { + slewCounter++; + if (slewCounter <= iterations) + return "|"; + else + return ""; + }); + + _telescope.SlewToTarget(); + + _utilMock.Verify( x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); + } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index c97b264..9d82148 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -5,7 +5,6 @@ using System.Runtime.InteropServices; using ASCOM.Astrometry.AstroUtils; using ASCOM.Utilities; using ASCOM.DeviceInterface; -using System.Globalization; using System.Collections; using System.Reflection; using ASCOM.Meade.net.AstroMaths; From 04845cea7a41204d2400e6c61f9245e0becc6e5f Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 18 Jul 2019 12:54:18 +0100 Subject: [PATCH 098/109] Unit tests for SlewToCoordinates --- .../TelescopeUnitTests.cs | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index db8c115..9f37054 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2047,5 +2047,88 @@ namespace Meade.net.Telescope.UnitTests _utilMock.Verify( x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); } + + [Test] + public void SlewToCoordinatesAsync_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToCoordinatesAsync(0,0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToCoordinatesAsync")); + } + + [Test] + public void SlewToCoordinatesAsync_WhenCalled_ThenSetsTargetAndSlews() + { + var rightAscension = 1; + var declination = 2; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + //var slewCounter = 0; + //var iterations = 10; + //_sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns(() => + //{ + // slewCounter++; + // if (slewCounter <= iterations) + // return "|"; + // else + // return ""; + //}); + + _telescope.SlewToCoordinatesAsync(rightAscension, declination); + + //_utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); + _sharedResourcesWrapperMock.Verify( x => x.SendChar(":MS#"), Times.Once); + } + + [Test] + public void SlewToCoordinates_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToCoordinates(0, 0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToCoordinates")); + } + + [Test] + public void SlewToCoordinates_WhenCalled_ThenSetsTargetAndSlews() + { + var rightAscension = 1; + var declination = 2; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + var slewCounter = 0; + var iterations = 10; + _sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns(() => + { + slewCounter++; + if (slewCounter <= iterations) + return "|"; + else + return ""; + }); + + _telescope.SlewToCoordinates(rightAscension, declination); + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); + _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); + + _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); + + } } } From 8b31c8d7a986a314d929c8ef732c5d53ee43cd1b Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 18 Jul 2019 13:12:26 +0100 Subject: [PATCH 099/109] SlewToAltAzAsync unit tests --- .../TelescopeUnitTests.cs | 83 +++++++++++++++++++ Meade.net.Telescope/Telescope.cs | 5 +- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 9f37054..573c59d 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2128,7 +2128,90 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); + } + + [Test] + public void SlewToAltAzAsync_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, 0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToAltAzAsync")); + } + + [Test] + public void SlewToAltAzAsync_WhenAltitudeGreaterThan90_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, 90.1); }); + Assert.That(exception.Message, Is.EqualTo("Altitude cannot be greater than 90.")); + } + + [Test] + public void SlewToAltAzAsync_WhenAltitudeLowerThan0_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, -0.1); }); + Assert.That(exception.Message, Is.EqualTo("Altitide cannot be less than 0.")); + } + + [Test] + public void SlewToAltAzAsync_WhenAzimuth360OrHigher_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(360, 0); }); + Assert.That(exception.Message, Is.EqualTo("Azimuth cannot be 360 or higher.")); + } + + [Test] + public void SlewToAltAzAsync_WhenAzimuthLowerThan0_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(-0.1, 0); }); + Assert.That(exception.Message, Is.EqualTo("Azimuth cannot be less than 0.")); + } + + [Test] + public void SlewToAltAzAsync_WhenAltAndAzValid_ThenConvertsToRADec() + { + + var altitude = 30; + var azimuth = 45; + var rightAscension = 20; + var declination = 10; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns("-1.0"); + + _astroMathsMock + .Setup(x => x.ConvertHozToEq(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())).Returns(new EquatorialCoordinates(){ Declination = declination, RightAscension = rightAscension }); + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + _telescope.SlewToAltAzAsync(azimuth, altitude); + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); + _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); } } } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 9d82148..a95943e 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -1395,6 +1395,8 @@ namespace ASCOM.Meade.net public void SlewToAltAzAsync(double azimuth, double altitude) { + CheckConnected("SlewToAltAzAsync"); + if (altitude > 90) throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); @@ -1408,8 +1410,7 @@ namespace ASCOM.Meade.net throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); - CheckConnected("SlewToAltAzAsync"); - + HorizonCoordinates altAz = new HorizonCoordinates(); altAz.Azimuth = azimuth; altAz.Altitude = altitude; From 3579189465070bdb5309e30d3a850665967c3450 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 18 Jul 2019 13:45:26 +0100 Subject: [PATCH 100/109] SlewToAltAz unit tests --- .../TelescopeUnitTests.cs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 573c59d..e975e26 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -2187,7 +2187,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenAltAndAzValid_ThenConvertsToRADec() { - var altitude = 30; var azimuth = 45; var rightAscension = 20; @@ -2213,5 +2212,56 @@ namespace Meade.net.Telescope.UnitTests Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); } + + [Test] + public void SlewToAltAz_WhenAzimuthLowerThan0_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.SlewToAltAz(0, 0); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToAltAz")); + } + + [Test] + public void SlewToAltAz_WhenCalled_ThenSetsTargetAndSlews() + { + var rightAscension = 10; + var declination = 20; + var azimuth = 30; + var altitude = 40; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns("-1.0"); + + _astroMathsMock + .Setup(x => x.ConvertHozToEq(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())).Returns(new EquatorialCoordinates() { Declination = declination, RightAscension = rightAscension }); + + _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); + + var slewCounter = 0; + var iterations = 10; + _sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns(() => + { + slewCounter++; + if (slewCounter <= iterations) + return "|"; + else + return ""; + }); + + _telescope.SlewToAltAz( azimuth, altitude); + + Assert.That(_telescope.TargetRightAscension, Is.EqualTo(rightAscension)); + Assert.That(_telescope.TargetDeclination, Is.EqualTo(declination)); + _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); + _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); + } } } From 4b65c946d2c4cbb27868cfd92c0d799460656e76 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 12:49:56 +0100 Subject: [PATCH 101/109] Unit testing --- .../TelescopeUnitTests.cs | 123 +++++++++++++++++- Meade.net.Telescope/Telescope.cs | 9 +- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index e975e26..f1c0fb6 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -45,6 +45,8 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny>())).Returns>( (func) => func()); + _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny>())).Returns>((func) => func()); + _sharedResourcesWrapperMock.Setup(x => x.ReadProfile()).Returns(_profileProperties); @@ -1102,7 +1104,6 @@ namespace Meade.net.Telescope.UnitTests _telescope.Connected = true; _sharedResourcesWrapperMock.Setup(x => x.SendString(":GR#")).Returns(telescopeRaResult); - _utilMock.Setup(x => x.HMSToHours(telescopeRaResult)).Returns(hmsResult); var result = _telescope.RightAscension; @@ -2263,5 +2264,125 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Verify(x => x.SendChar(":MS#"), Times.Once); _utilMock.Verify(x => x.WaitForMilliseconds(It.IsAny()), Times.Exactly(iterations)); } + + [Test] + public void Azimuth_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.Azimuth; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Azimuth Get")); + } + + [Test] + public void Azimuth_WhenConnected_ThenReturnsTelescopeAzumith() + { + var expectedAzimuth = 200; + + var telescopeLongitude = "350"; + var telescopeLongitudeValue = 350; + + var telescopeLatitude = "HH:MM:SS"; + var telescopeLatitudeValue = 1.2; + + var mockHourAngle = 3; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns("-1.0"); + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gg#")).Returns(telescopeLongitude); + _utilMock.Setup(x => x.DMSToDegrees(telescopeLongitude)).Returns(telescopeLongitudeValue); + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GR#")).Returns(telescopeLatitude); + _utilMock.Setup(x => x.HMSToHours(telescopeLatitude)).Returns(telescopeLatitudeValue); + + _astroMathsMock.Setup(x => x.RightAscensionToHourAngle(It.IsAny(), It.IsAny(), It.IsAny())).Returns(mockHourAngle); + + _astroMathsMock.Setup(x => x.ConvertEqToHoz(mockHourAngle, It.IsAny(), It.IsAny())).Returns( new HorizonCoordinates{ Altitude = 45, Azimuth = expectedAzimuth }); + + var result = _telescope.Azimuth; + + Assert.That(result,Is.EqualTo(expectedAzimuth)); + } + + [Test] + public void Altitude_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { var result = _telescope.Altitude; }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Altitude Get")); + } + + [Test] + public void Altitude_WhenConnected_ThenReturnsTelescopeAltitude() + { + var expectedAltitude = 45; + + var telescopeLongitude = "350"; + var telescopeLongitudeValue = 350; + + var telescopeLatitude = "HH:MM:SS"; + var telescopeLatitudeValue = 1.2; + + var mockHourAngle = 3; + + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns("-1.0"); + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gg#")).Returns(telescopeLongitude); + _utilMock.Setup(x => x.DMSToDegrees(telescopeLongitude)).Returns(telescopeLongitudeValue); + + _sharedResourcesWrapperMock.Setup(x => x.SendString(":GR#")).Returns(telescopeLatitude); + _utilMock.Setup(x => x.HMSToHours(telescopeLatitude)).Returns(telescopeLatitudeValue); + + _astroMathsMock.Setup(x => x.RightAscensionToHourAngle(It.IsAny(), It.IsAny(), It.IsAny())).Returns(mockHourAngle); + + _astroMathsMock.Setup(x => x.ConvertEqToHoz(mockHourAngle, It.IsAny(), It.IsAny())).Returns(new HorizonCoordinates { Altitude = expectedAltitude, Azimuth = 200 }); + + var result = _telescope.Altitude; + + Assert.That(result, Is.EqualTo(expectedAltitude)); + } + + [Test] + public void AbortSlew_WhenNotConnected_ThenThrowsException() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + + var exception = Assert.Throws(() => { _telescope.AbortSlew(); }); + Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AbortSlew")); + } + + [Test] + public void AbortSlew_WhenConnected_ThenSendsStopSlewingToTelescope() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + + _telescope.AbortSlew(); + + _sharedResourcesWrapperMock.Verify( x => x.SendBlind(":Q#"),Times.Once); + + var isSloSlewing = _telescope.Slewing; + + Assert.That(isSloSlewing, Is.False); + _sharedResourcesWrapperMock.Verify( x => x.SendString(":D#"), Times.Once); + } } } +; \ No newline at end of file diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index a95943e..d9d187c 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -464,6 +464,9 @@ namespace ASCOM.Meade.net _sharedResourcesWrapper.SendBlind(":Q#"); //:Q# Halt all current slewing //Returns:Nothing + + _movingPrimary = false; + _movingSecondary = false; } public AlignmentModes AlignmentMode @@ -552,7 +555,7 @@ namespace ASCOM.Meade.net { get { - CheckConnected("Altitude get"); + CheckConnected("Altitude Get"); var altAz = CalcAltAzFromTelescopeEqData(); LogMessage("Altitude", $"{altAz.Altitude}"); @@ -642,7 +645,7 @@ namespace ASCOM.Meade.net { get { - CheckConnected("Azimuth get"); + CheckConnected("Azimuth Get"); //var result = _sharedResourcesWrapper.SendString(":GZ#"); //:GZ# Get telescope azimuth @@ -1261,7 +1264,7 @@ namespace ASCOM.Meade.net var longitude = _sharedResourcesWrapper.SendString(":Gg#"); //:Gg# Get Current Site Longitude - //Returns: sDDD* MM# + //Returns: sDDD*MM# //The current site Longitude. East Longitudes are expressed as negative double siteLongitude = _utilities.DMSToDegrees(longitude); From dfef48ff0cf348662521c686bc6f64fdcb6ba451 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 13:06:56 +0100 Subject: [PATCH 102/109] code tidy up --- .../TelescopeUnitTests.cs | 399 ++++-------------- 1 file changed, 83 insertions(+), 316 deletions(-) diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index f1c0fb6..9f0a845 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -56,6 +56,13 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Object, _astroMathsMock.Object); } + private void ConnectTelescope() + { + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _telescope.Connected = true; + } + [Test] public void CheckThatClassCreatedProperly() { @@ -92,9 +99,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_WhenNotConnected_ThrowsNotConnectedException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var actualResult = _telescope.Action(string.Empty, string.Empty); }); Assert.That(exception.Message,Is.EqualTo("Not connected to telescope when trying to execute: Action")); } @@ -102,9 +106,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_Handbox_ReadDisplay() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - string expectedResult = "test result string"; _sharedResourcesWrapperMock.Setup(x => x.SendString(":ED#")).Returns(expectedResult); _telescope.Connected = true; @@ -138,10 +139,8 @@ namespace Meade.net.Telescope.UnitTests [TestCase("?", ":EK63#")] public void Action_Handbox_blindCommands(string action, string expectedString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + ConnectTelescope(); - _telescope.Connected = true; _telescope.Action("handbox", action); _sharedResourcesWrapperMock.Verify(x => x.SendBlind(expectedString), Times.Once); @@ -150,9 +149,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_Handbox_nonExistantAction() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); string actionName = "handbox"; string actionParameters = "doesnotexist"; @@ -164,9 +161,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Action_nonExistantAction() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); string actionName = "doesnotexist"; var exception = Assert.Throws(() => { _telescope.Action(actionName, string.Empty); }); @@ -188,9 +183,7 @@ namespace Meade.net.Telescope.UnitTests { string expectedMessage = "test blind Message"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns( () => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.CommandBlind(expectedMessage, true); @@ -211,9 +204,7 @@ namespace Meade.net.Telescope.UnitTests { string expectedMessage = "test blind Message"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.CommandBool(expectedMessage, true); }); @@ -235,9 +226,7 @@ namespace Meade.net.Telescope.UnitTests string expectedMessage = "expected result message"; string sendMessage = "test blind Message"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(sendMessage)).Returns(() => expectedMessage); @@ -262,9 +251,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Connected_Set_SettingTrueWhenTrue_ThenDoesNothing() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Verify( x => x.Connect(It.IsAny()),Times.Once); //act @@ -277,9 +264,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Connected_Set_SettingFalseWhenTrue_ThenDisconnects() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Verify(x => x.Connect(It.IsAny()), Times.Once); //act @@ -439,9 +424,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AlignmentMode_Get_WhenNotConnected_ThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var actualResult = _telescope.AlignmentMode; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AlignmentMode Get")); } @@ -452,9 +434,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase("G", AlignmentModes.algGermanPolar)] public void AlignmentMode_Get_WhenScopeInAltAz_ReturnsAltAz(string telescopeMode, AlignmentModes alignmentMode) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); const char ack = (char)6; _sharedResourcesWrapperMock.Setup(x => x.SendChar(ack.ToString())).Returns(telescopeMode); @@ -467,9 +447,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AlignmentMode_Get_WhenUnknownAlignmentMode_ThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); Assert.Throws(() => { var actualResult = _telescope.AlignmentMode; }); } @@ -477,9 +455,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AlignmentMode_Set_WhenNotConnected_ThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.AlignmentMode = AlignmentModes.algAltAz; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AlignmentMode Set")); } @@ -548,9 +523,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AtPark_Get_WhenParked_ThenReturnsTrue() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_43EG); - _telescope.Connected = true; + ConnectTelescope(); _telescope.Park(); var result = _telescope.AtPark; @@ -709,9 +682,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Declination_Get_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var actualResult = _telescope.Declination; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Declination Get")); } @@ -721,9 +691,7 @@ namespace Meade.net.Telescope.UnitTests public void Declination_Get_WhenConnected_ThenReadsValueFromScope(string declincationString) { var expectedResult = 12.34; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GD#")).Returns(declincationString); _utilMock.Setup(x => x.DMSToDegrees(declincationString)).Returns(expectedResult); @@ -848,9 +816,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void MoveAxis_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.MoveAxis(TelescopeAxes.axisPrimary, 0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: MoveAxis")); } @@ -875,9 +840,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(-4, ":RS#", TelescopeAxes.axisSecondary)] public void MoveAxis_WhenConnected_ThenExecutesCorrectCommandSequence(double rate, string slewRateCommand, TelescopeAxes axis) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.MoveAxis(axis, rate); @@ -934,9 +897,7 @@ namespace Meade.net.Telescope.UnitTests { var testRate = 5; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws( () => { _telescope.MoveAxis(TelescopeAxes.axisTertiary, testRate); }); @@ -948,9 +909,7 @@ namespace Meade.net.Telescope.UnitTests { var testRate = 0; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.MoveAxis(TelescopeAxes.axisTertiary, testRate); }); @@ -960,9 +919,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Park_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.Park(); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Park")); } @@ -970,9 +926,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Park_WhenNotParked_ThenSendsParkCommand() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); Assert.That(_telescope.AtPark, Is.False); _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Never); @@ -985,10 +939,8 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Park_WhenParked_ThenDoesNothing() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; - + ConnectTelescope(); + _telescope.Park(); _sharedResourcesWrapperMock.Verify(x => x.SendBlind(":hP#"), Times.Once); @@ -1006,9 +958,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void PulseGuide_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.PulseGuide(GuideDirections.guideEast,0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: PulseGuide")); } @@ -1020,9 +969,7 @@ namespace Meade.net.Telescope.UnitTests public void PulseGuide_WhenConnectedAndNewerPulseGuidingAvailable_ThenSendsNewCommandsAndWaits(GuideDirections direction) { var duration = 0; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.PulseGuide(direction, 0); @@ -1086,9 +1033,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void RightAscension_Get_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.RightAscension; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: RightAscension Get")); } @@ -1099,9 +1043,7 @@ namespace Meade.net.Telescope.UnitTests var telescopeRaResult = "HH:MM:SS"; var hmsResult = 1.2; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GR#")).Returns(telescopeRaResult); _utilMock.Setup(x => x.HMSToHours(telescopeRaResult)).Returns(hmsResult); @@ -1204,9 +1146,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLatitude_Get_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.SiteLatitude; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLatitude Get")); } @@ -1217,10 +1156,7 @@ namespace Meade.net.Telescope.UnitTests var siteLatitudeString = "testLatString"; var siteLatitudeValue = 123.45; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; - + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gt#")).Returns(siteLatitudeString); _utilMock.Setup(x => x.DMSToDegrees(siteLatitudeString)).Returns(siteLatitudeValue); @@ -1234,9 +1170,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLatitude_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SiteLatitude = 123.45; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLatitude Set")); } @@ -1244,9 +1177,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLatitude_Set_WhenConnectedAndLatitudeIsGreaterThan90_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SiteLatitude = 90.01; }); Assert.That(exception.Message, Is.EqualTo("Latitude cannot be greater than 90 degrees.")); @@ -1255,9 +1186,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLatitude_Set_WhenConnectedAndLatitudeIsLessThanNegative90_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SiteLatitude = -90.01; }); Assert.That(exception.Message, Is.EqualTo("Latitude cannot be less than -90 degrees.")); @@ -1267,9 +1196,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(20.75)] public void SiteLatitude_Set_WhenValueSetAndTelescopRejects_ThenExceptionThrown(double siteLatitude) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); @@ -1282,12 +1209,8 @@ namespace Meade.net.Telescope.UnitTests [TestCase(20.75, ":St+20*45#")] public void SiteLatitude_Set_WhenValidValues_ThenValueSentToTelescope(double siteLatitude, string expectedCommand) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; - - - + ConnectTelescope(); + _sharedResourcesWrapperMock.Setup(x => x.SendChar(expectedCommand)).Returns("1"); _telescope.SiteLatitude = siteLatitude; @@ -1298,9 +1221,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLongitude_Get_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.SiteLongitude; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLongitude Get")); } @@ -1315,9 +1235,7 @@ namespace Meade.net.Telescope.UnitTests { var telescopeLongitude = "testLongitude"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":Gg#")).Returns(telescopeLongitude); _utilMock.Setup(x => x.DMSToDegrees(telescopeLongitude)).Returns(telescopeLongitudeValue); @@ -1330,9 +1248,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLongitude_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SiteLongitude = 123.45; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SiteLongitude Set")); } @@ -1340,9 +1255,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLongitude_Set_WhenConnectedAndGreaterThan180_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SiteLongitude = 180.1; }); Assert.That(exception.Message, Is.EqualTo("Longitude cannot be greater than 180 degrees.")); @@ -1351,9 +1264,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLongitude_Set_WhenConnectedAndLessThanNegative180_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SiteLongitude = -180.1; }); Assert.That(exception.Message, Is.EqualTo("Longitude cannot be lower than -180 degrees.")); @@ -1362,9 +1273,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SiteLongitude_Set_WhenConnectedAndTelescopeFails_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); @@ -1375,9 +1284,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(10, ":Sg350*00#")] public void SiteLongitude_Set_WhenConnectedAndTelescopeFails_ThenThrowsException(double longitude, string expectedCommand) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(expectedCommand)).Returns("1"); @@ -1391,9 +1298,7 @@ namespace Meade.net.Telescope.UnitTests { string expectedMessage = "test blind Message"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SyncToAltAz(0,0); }); @@ -1403,9 +1308,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SyncToTarget_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SyncToTarget(); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SyncToTarget")); } @@ -1413,9 +1315,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SyncToTarget_WhenSyncToTargetFails_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":CM#")).Returns(string.Empty); @@ -1428,9 +1328,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SyncToTarget_WhenSyncToTargetWorks_ThennoExceptionThrown() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":CM#")).Returns(" M31 EX GAL MAG 3.5 SZ178.0'#"); @@ -1442,9 +1340,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetDeclination_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.TargetDeclination = 0; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TargetDeclination Set")); } @@ -1452,9 +1347,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetDeclination_Set_WhenValueTooHigh_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.TargetDeclination = 90.1; }); Assert.That(exception.Message, Is.EqualTo("Declination cannot be greater than 90.")); @@ -1463,9 +1356,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetDeclination_Set_WhenValueTooLow_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.TargetDeclination = -90.1; }); Assert.That(exception.Message, Is.EqualTo("Declination cannot be less than -90.")); @@ -1474,9 +1365,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetDeclination_Set_WhenTelescopeReportsInvalidDec_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); @@ -1490,9 +1379,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(50, "50*00:00", ":Sd+50*00:00#")] public void TargetDeclination_Set_WhenValueOK_ThenSetsNewTargetDeclination( double declination,string decstring, string commandString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _utilMock.Setup(x => x.DegreesToDMS(declination, "*", ":", ":", 2)).Returns(decstring); _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); @@ -1505,9 +1392,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetDeclination_Get_WhenTargetNotSet_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { var result = _telescope.TargetDeclination; }); Assert.That(exception.Message, Is.EqualTo("Target not set")); @@ -1516,9 +1401,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(50, "50*00:00", ":Sd+50*00:00#")] public void TargetDeclination_Get_WhenValueOK_ThenSetsNewTargetDeclination(double declination, string decstring, string commandString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _utilMock.Setup(x => x.DegreesToDMS(declination, "*", ":", ":", 2)).Returns(decstring); _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); @@ -1533,9 +1416,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetRightAscension_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.TargetRightAscension = 0; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TargetRightAscension Set")); } @@ -1543,9 +1423,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetRightAscension_Set_WhenValueTooHigh_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.TargetRightAscension = 24; }); Assert.That(exception.Message, Is.EqualTo("Right ascension value cannot be greater than 23:59:59")); @@ -1554,9 +1432,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetRightAscension_Set_WhenValueTooLow_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.TargetRightAscension = -0.1; }); Assert.That(exception.Message, Is.EqualTo("Right ascension value cannot be below 0")); @@ -1565,9 +1441,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetRightAscension_Set_WhenTelescopeReportsInvalidRA_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); @@ -1579,9 +1453,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(10, "10:00:00", ":Sr10:00:00#")] public void TargetRightAscension_Set_WhenValueOK_ThenSetsNewTargetDeclination(double rightAscension, string hms, string commandString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); @@ -1594,9 +1466,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TargetRightAscension_Get_WhenTargetNotSet_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { var result = _telescope.TargetRightAscension; }); Assert.That(exception.Message, Is.EqualTo("Target not set")); @@ -1605,9 +1475,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(15, "15:00:00", ":Sr15:00:00#")] public void TargetRightAscension_Get_WhenValueOK_ThenSetsNewTargetDeclination(double rightAscension, string hms, string commandString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); _sharedResourcesWrapperMock.Setup(x => x.SendChar(commandString)).Returns("1"); @@ -1637,9 +1505,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TrackingRate_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.TrackingRate = DriveRates.driveSidereal; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: TrackingRate Set")); } @@ -1648,9 +1513,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(DriveRates.driveLunar, ":TL#")] public void TrackingRate_Set_WhenConnected_ThenSendsCommandToTelescope(DriveRates rate, string commandString) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TrackingRate = rate; @@ -1660,9 +1523,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TrackingRate_Set_WhenUnSupportedRateSet_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws( () => { _telescope.TrackingRate = DriveRates.driveKing; }); @@ -1672,9 +1533,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void TrackingRage_Get_WhenReadongDefaultValue_ThenAssumesSidereal() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var result = _telescope.TrackingRate; @@ -1685,9 +1544,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(DriveRates.driveLunar)] public void TrackingRate_Get_WhenConnected_ThenSendsCommandToTelescope(DriveRates rate) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TrackingRate = rate; @@ -1708,9 +1565,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void UTCDate_Get_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.UTCDate; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: UTCDate Get")); } @@ -1720,9 +1574,7 @@ namespace Meade.net.Telescope.UnitTests public void UTCDate_Get_WhenConnected_ThenReturnsUTCDateTime(string telescopeDate, string telescopeTime, string telescopeUtcCorrection, int year, int month, int day, int hour, int min, int second) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns(telescopeDate); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns(telescopeTime); @@ -1744,9 +1596,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void UTCDate_Set_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.UTCDate = new DateTime(2010,10,15,16,42,32, DateTimeKind.Utc); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: UTCDate Set")); } @@ -1760,9 +1609,7 @@ namespace Meade.net.Telescope.UnitTests var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("0"); @@ -1781,10 +1628,7 @@ namespace Meade.net.Telescope.UnitTests var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; - - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("1"); @@ -1806,10 +1650,7 @@ namespace Meade.net.Telescope.UnitTests var newDate = new DateTime(year, month, day, hour, min, second, DateTimeKind.Local) + utcCorrection; - - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GG#")).Returns(telescopeUtcCorrection); _sharedResourcesWrapperMock.Setup(x => x.SendChar($":SL{telescopeTime}#")).Returns("1"); @@ -1829,9 +1670,7 @@ namespace Meade.net.Telescope.UnitTests double declination = -30.5; string dec = "-30*30:00"; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _utilMock.Setup(x => x.HoursToHMS(rightAscension, ":", ":", ":", 2)).Returns(hms); _sharedResourcesWrapperMock.Setup(x => x.SendChar($":Sr{hms}#")).Returns("1"); @@ -1849,9 +1688,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Slewing_WhenNotConnected_ThenReturnsFalse() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var result = _telescope.Slewing; Assert.That(result, Is.False); @@ -1862,9 +1698,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Slewing_WhenConnectedAndTelescopeFails_ThenReturnsFalse() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var result = _telescope.Slewing; @@ -1876,9 +1710,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Slewing_WhenTelescopeIsSlewing_ThenReturnsTrue() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":D#")).Returns("|"); @@ -1895,9 +1727,7 @@ namespace Meade.net.Telescope.UnitTests [TestCase(-1, TelescopeAxes.axisSecondary)] public void Slewing_WhenTelescopeIsMoving_ThenDoesNotSendCommandAndReturnsTrue(int rate, TelescopeAxes axis) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.MoveAxis(axis, rate); @@ -1911,9 +1741,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToTargetAsync(); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToTargetAsync")); } @@ -1921,9 +1748,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetDeclinationNotSet_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 1; @@ -1934,9 +1759,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetRightAscensionNotSet_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetDeclination = 1; @@ -1947,9 +1770,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetSet_ThenAttemptsSlew() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 2; _telescope.TargetDeclination = 1; @@ -1961,9 +1782,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetSetAndSlewIsPossible_ThenAttemptsSlew() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 2; _telescope.TargetDeclination = 1; @@ -1978,9 +1797,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetBelowHorizon_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 2; _telescope.TargetDeclination = 1; @@ -1996,9 +1813,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTargetAsync_WhenTargetBelowElevation_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 2; _telescope.TargetDeclination = 1; @@ -2014,9 +1829,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTarget_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToTarget(); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToTarget")); } @@ -2024,9 +1836,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToTarget_WhenSlewing_ThenWaitsForTheSlewToComplete() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.TargetRightAscension = 2; _telescope.TargetDeclination = 1; @@ -2052,9 +1862,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToCoordinatesAsync_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToCoordinatesAsync(0,0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToCoordinatesAsync")); } @@ -2065,9 +1872,7 @@ namespace Meade.net.Telescope.UnitTests var rightAscension = 1; var declination = 2; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); @@ -2093,9 +1898,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToCoordinates_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToCoordinates(0, 0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToCoordinates")); } @@ -2106,9 +1908,7 @@ namespace Meade.net.Telescope.UnitTests var rightAscension = 1; var declination = 2; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendChar(":MS#")).Returns("0"); @@ -2134,9 +1934,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, 0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToAltAzAsync")); } @@ -2144,9 +1941,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenAltitudeGreaterThan90_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, 90.1); }); Assert.That(exception.Message, Is.EqualTo("Altitude cannot be greater than 90.")); @@ -2155,9 +1950,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenAltitudeLowerThan0_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(0, -0.1); }); Assert.That(exception.Message, Is.EqualTo("Altitide cannot be less than 0.")); @@ -2166,9 +1959,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenAzimuth360OrHigher_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(360, 0); }); Assert.That(exception.Message, Is.EqualTo("Azimuth cannot be 360 or higher.")); @@ -2177,9 +1968,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAzAsync_WhenAzimuthLowerThan0_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); var exception = Assert.Throws(() => { _telescope.SlewToAltAzAsync(-0.1, 0); }); Assert.That(exception.Message, Is.EqualTo("Azimuth cannot be less than 0.")); @@ -2193,9 +1982,7 @@ namespace Meade.net.Telescope.UnitTests var rightAscension = 20; var declination = 10; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); @@ -2217,9 +2004,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void SlewToAltAz_WhenAzimuthLowerThan0_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.SlewToAltAz(0, 0); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: SlewToAltAz")); } @@ -2232,9 +2016,7 @@ namespace Meade.net.Telescope.UnitTests var azimuth = 30; var altitude = 40; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); @@ -2268,9 +2050,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Azimuth_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.Azimuth; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Azimuth Get")); } @@ -2288,9 +2067,7 @@ namespace Meade.net.Telescope.UnitTests var mockHourAngle = 3; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); @@ -2314,9 +2091,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Altitude_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { var result = _telescope.Altitude; }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: Altitude Get")); } @@ -2334,9 +2108,7 @@ namespace Meade.net.Telescope.UnitTests var mockHourAngle = 3; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GC#")).Returns("10/15/20"); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GL#")).Returns("20:15:10"); @@ -2360,9 +2132,6 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AbortSlew_WhenNotConnected_ThenThrowsException() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - var exception = Assert.Throws(() => { _telescope.AbortSlew(); }); Assert.That(exception.Message, Is.EqualTo("Not connected to telescope when trying to execute: AbortSlew")); } @@ -2370,9 +2139,7 @@ namespace Meade.net.Telescope.UnitTests [Test] public void AbortSlew_WhenConnected_ThenSendsStopSlewingToTelescope() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); - _telescope.Connected = true; + ConnectTelescope(); _telescope.AbortSlew(); From 2ce8c4e12341715053434e88407cf0229d0824fd Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 13:12:22 +0100 Subject: [PATCH 103/109] Removed redundant qualifiers --- FocuserTestConsole/Program.cs | 4 +- .../TelescopeUnitTests.cs | 2 +- Meade.net.Telescope/Rates.cs | 26 ++-- Meade.net.Telescope/Telescope.cs | 120 +++++++++--------- Meade.net.focuser/Focuser.cs | 30 ++--- Meade.net/LocalServer.cs | 4 +- Meade.net/SetupDialogForm.cs | 4 +- Meade.net/SharedResources.cs | 24 ++-- TelescopeTestConsole/Program.cs | 4 +- 9 files changed, 109 insertions(+), 109 deletions(-) diff --git a/FocuserTestConsole/Program.cs b/FocuserTestConsole/Program.cs index af644c8..aff0a29 100644 --- a/FocuserTestConsole/Program.cs +++ b/FocuserTestConsole/Program.cs @@ -24,11 +24,11 @@ namespace ASCOM // Uncomment the code that's required #if UseChooser // choose the device - string id = ASCOM.DriverAccess.Focuser.Choose("ASCOM.MeadeGeneric.Focuser"); + string id = Focuser.Choose("ASCOM.MeadeGeneric.Focuser"); if (string.IsNullOrEmpty(id)) return; // create this device - ASCOM.DriverAccess.Focuser device = new ASCOM.DriverAccess.Focuser(id); + Focuser device = new Focuser(id); #else // this can be replaced by this code, it avoids the chooser and creates the driver class directly. ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.MeadeGeneric.Telescope"); diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 9f0a845..ab6cf16 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1200,7 +1200,7 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock.Setup(x => x.SendChar(It.IsAny())).Returns("0"); - var exception = Assert.Throws(() => { _telescope.SiteLatitude = siteLatitude; }); + var exception = Assert.Throws(() => { _telescope.SiteLatitude = siteLatitude; }); Assert.That(exception.Message, Is.EqualTo("Failed to set site latitude.")); } diff --git a/Meade.net.Telescope/Rates.cs b/Meade.net.Telescope/Rates.cs index 2230bf7..0579dc7 100644 --- a/Meade.net.Telescope/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -21,7 +21,7 @@ namespace ASCOM.Meade.net [Guid("288838d1-bbf9-4ce0-9ee1-86ecf38b45c9")] [ClassInterface(ClassInterfaceType.None)] [ComVisible(true)] - public class Rate : ASCOM.DeviceInterface.IRate + public class Rate : IRate { private double maximum = 0; private double minimum = 0; @@ -45,14 +45,14 @@ namespace ASCOM.Meade.net public double Maximum { - get { return this.maximum; } - set { this.maximum = value; } + get { return maximum; } + set { maximum = value; } } public double Minimum { - get { return this.minimum; } - set { this.minimum = value; } + get { return minimum; } + set { minimum = value; } } #endregion @@ -100,16 +100,16 @@ namespace ASCOM.Meade.net // TODO Initialize this array with any Primary axis rates that your driver may provide // Example: m_Rates = new Rate[] { new Rate(10.5, 30.2), new Rate(54.0, 43.6) } //this.rates = new Rate[0]; - this.rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; + rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisSecondary: // TODO Initialize this array with any Secondary axis rates that your driver may provide //this.rates = new Rate[0]; - this.rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; + rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisTertiary: // TODO Initialize this array with any Tertiary axis rates that your driver may provide - this.rates = new Rate[0]; + rates = new Rate[0]; break; } } @@ -118,7 +118,7 @@ namespace ASCOM.Meade.net public int Count { - get { return this.rates.Length; } + get { return rates.Length; } } public void Dispose() @@ -133,7 +133,7 @@ namespace ASCOM.Meade.net public IRate this[int index] { - get { return this.rates[index - 1]; } // 1-based + get { return rates[index - 1]; } // 1-based } #endregion @@ -176,7 +176,7 @@ namespace ASCOM.Meade.net // the tracking rates supported by your telescope. The one value // (tracking rate) that MUST be supported is driveSidereal! // - this.trackingRates = new[] { DriveRates.driveSidereal, DriveRates.driveLunar }; + trackingRates = new[] { DriveRates.driveSidereal, DriveRates.driveLunar }; // TODO Initialize this array with any additional tracking rates that your driver may provide } @@ -184,7 +184,7 @@ namespace ASCOM.Meade.net public int Count { - get { return this.trackingRates.Length; } + get { return trackingRates.Length; } } public IEnumerator GetEnumerator() @@ -200,7 +200,7 @@ namespace ASCOM.Meade.net public DriveRates this[int index] { - get { return this.trackingRates[index - 1]; } // 1-based + get { return trackingRates[index - 1]; } // 1-based } #endregion diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index d9d187c..d57d84a 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -230,12 +230,12 @@ namespace ASCOM.Meade.net break; default: LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException($"{actionName}({actionParameters})"); + throw new ActionNotImplementedException($"{actionName}({actionParameters})"); } break; default: LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException($"{actionName}"); + throw new ActionNotImplementedException($"{actionName}"); } return string.Empty; @@ -258,7 +258,7 @@ namespace ASCOM.Meade.net //string ret = CommandString(command, raw); // TODO decode the return string and return true or false // or - throw new ASCOM.MethodNotImplementedException("CommandBool"); + throw new MethodNotImplementedException("CommandBool"); // DO NOT have both these sections! One or the other } @@ -414,7 +414,7 @@ namespace ASCOM.Meade.net { get { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + Version version = Assembly.GetExecutingAssembly().GetName().Version; string driverVersion = $"{version.Major}.{version.Minor}.{version.Revision}.{version.Build}"; LogMessage("DriverVersion Get", driverVersion); return driverVersion; @@ -580,13 +580,13 @@ namespace ASCOM.Meade.net { var altitudeData = _sharedResourcesWrapper.Lock(() => new AltitudeData { - UtcDateTime = this.UTCDate, - SiteLongitude = this.SiteLongitude, - SiteLatitude = this.SiteLatitude, + UtcDateTime = UTCDate, + SiteLongitude = SiteLongitude, + SiteLatitude = SiteLatitude, equatorialCoordinates = new EquatorialCoordinates() { - RightAscension = this.RightAscension, - Declination = this.Declination + RightAscension = RightAscension, + Declination = Declination } }); @@ -601,7 +601,7 @@ namespace ASCOM.Meade.net get { LogMessage("ApertureArea Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("ApertureArea", false); + throw new PropertyNotImplementedException("ApertureArea", false); } } @@ -610,7 +610,7 @@ namespace ASCOM.Meade.net get { LogMessage("ApertureDiameter Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("ApertureDiameter", false); + throw new PropertyNotImplementedException("ApertureDiameter", false); } } @@ -848,14 +848,14 @@ namespace ASCOM.Meade.net set { LogMessage("DeclinationRate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DeclinationRate", true); + throw new PropertyNotImplementedException("DeclinationRate", true); } } public PierSide DestinationSideOfPier(double rightAscension, double declination) { LogMessage("DestinationSideOfPier Get", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("DestinationSideOfPier"); + throw new MethodNotImplementedException("DestinationSideOfPier"); } public bool DoesRefraction @@ -863,12 +863,12 @@ namespace ASCOM.Meade.net get { LogMessage("DoesRefraction Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DoesRefraction", false); + throw new PropertyNotImplementedException("DoesRefraction", false); } set { LogMessage("DoesRefraction Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("DoesRefraction", true); + throw new PropertyNotImplementedException("DoesRefraction", true); } } @@ -885,7 +885,7 @@ namespace ASCOM.Meade.net public void FindHome() { LogMessage("FindHome", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("FindHome"); + throw new MethodNotImplementedException("FindHome"); } public double FocalLength @@ -893,7 +893,7 @@ namespace ASCOM.Meade.net get { LogMessage("FocalLength Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("FocalLength", false); + throw new PropertyNotImplementedException("FocalLength", false); } } @@ -902,12 +902,12 @@ namespace ASCOM.Meade.net get { LogMessage("GuideRateDeclination Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", false); + throw new PropertyNotImplementedException("GuideRateDeclination", false); } set { LogMessage("GuideRateDeclination Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateDeclination", true); + throw new PropertyNotImplementedException("GuideRateDeclination", true); } } @@ -916,12 +916,12 @@ namespace ASCOM.Meade.net get { LogMessage("GuideRateRightAscension Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", false); + throw new PropertyNotImplementedException("GuideRateRightAscension", false); } set { LogMessage("GuideRateRightAscension Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("GuideRateRightAscension", true); + throw new PropertyNotImplementedException("GuideRateRightAscension", true); } } @@ -972,7 +972,7 @@ namespace ASCOM.Meade.net //Returns: Nothing break; default: - throw new ASCOM.InvalidValueException($"Rate {rate} not supported"); + throw new InvalidValueException($"Rate {rate} not supported"); } switch (axis) @@ -1032,7 +1032,7 @@ namespace ASCOM.Meade.net break; default: - throw new ASCOM.InvalidValueException("Can not move this axis."); + throw new InvalidValueException("Can not move this axis."); } } @@ -1147,14 +1147,14 @@ namespace ASCOM.Meade.net set { LogMessage("RightAscensionRate Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("RightAscensionRate", true); + throw new PropertyNotImplementedException("RightAscensionRate", true); } } public void SetPark() { LogMessage("SetPark", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SetPark"); + throw new MethodNotImplementedException("SetPark"); } public PierSide SideOfPier @@ -1162,12 +1162,12 @@ namespace ASCOM.Meade.net get { LogMessage("SideOfPier Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SideOfPier", false); + throw new PropertyNotImplementedException("SideOfPier", false); } set { LogMessage("SideOfPier Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SideOfPier", true); + throw new PropertyNotImplementedException("SideOfPier", true); } } @@ -1177,13 +1177,13 @@ namespace ASCOM.Meade.net { // Now using NOVAS 3.1 double siderealTime = 0.0; - using (var novas = new ASCOM.Astrometry.NOVAS.NOVAS31()) + using (var novas = new Astrometry.NOVAS.NOVAS31()) { var jd = _utilities.DateUTCToJulian(DateTime.UtcNow); novas.SiderealTime(jd, 0, novas.DeltaT(jd), - ASCOM.Astrometry.GstType.GreenwichApparentSiderealTime, - ASCOM.Astrometry.Method.EquinoxBased, - ASCOM.Astrometry.Accuracy.Reduced, ref siderealTime); + Astrometry.GstType.GreenwichApparentSiderealTime, + Astrometry.Method.EquinoxBased, + Astrometry.Accuracy.Reduced, ref siderealTime); } // Allow for the longitude @@ -1202,12 +1202,12 @@ namespace ASCOM.Meade.net get { LogMessage("SiteElevation Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteElevation", false); + throw new PropertyNotImplementedException("SiteElevation", false); } set { LogMessage("SiteElevation Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SiteElevation", true); + throw new PropertyNotImplementedException("SiteElevation", true); } } @@ -1316,12 +1316,12 @@ namespace ASCOM.Meade.net get { LogMessage("SlewSettleTime Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", false); + throw new PropertyNotImplementedException("SlewSettleTime", false); } set { LogMessage("SlewSettleTime Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("SlewSettleTime", true); + throw new PropertyNotImplementedException("SlewSettleTime", true); } } @@ -1343,10 +1343,10 @@ namespace ASCOM.Meade.net set { if (value > 90) - throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); + throw new InvalidValueException("Altitude cannot be greater than 90."); if (value < 0) - throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + throw new InvalidValueException("Altitide cannot be less than 0."); CheckConnected("TargetAltitude Set"); @@ -1363,7 +1363,7 @@ namespace ASCOM.Meade.net //0 Object out of slew range if (result == "0") - throw new ASCOM.InvalidOperationException("Target altitude out of slew range"); + throw new InvalidOperationException("Target altitude out of slew range"); } } @@ -1372,10 +1372,10 @@ namespace ASCOM.Meade.net set { if (value >= 360) - throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); + throw new InvalidValueException("Azimuth cannot be 360 or higher."); if (value < 0) - throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + throw new InvalidValueException("Azimuth cannot be less than 0."); CheckConnected("TargetAzimuth Set"); @@ -1391,7 +1391,7 @@ namespace ASCOM.Meade.net //1 - Valid if (result == "0") - throw new ASCOM.InvalidOperationException("Target Azimuth out of slew range"); + throw new InvalidOperationException("Target Azimuth out of slew range"); } } @@ -1401,16 +1401,16 @@ namespace ASCOM.Meade.net CheckConnected("SlewToAltAzAsync"); if (altitude > 90) - throw new ASCOM.InvalidValueException("Altitude cannot be greater than 90."); + throw new InvalidValueException("Altitude cannot be greater than 90."); if (altitude < 0) - throw new ASCOM.InvalidValueException("Altitide cannot be less than 0."); + throw new InvalidValueException("Altitide cannot be less than 0."); if (azimuth >= 360) - throw new ASCOM.InvalidValueException("Azimuth cannot be 360 or higher."); + throw new InvalidValueException("Azimuth cannot be 360 or higher."); if (azimuth < 0) - throw new ASCOM.InvalidValueException("Azimuth cannot be less than 0."); + throw new InvalidValueException("Azimuth cannot be less than 0."); LogMessage("SlewToAltAzAsync", $"Az={azimuth} Alt={altitude}"); @@ -1464,15 +1464,15 @@ namespace ASCOM.Meade.net //Below Horizon string belowHorizonMessage = _sharedResourcesWrapper.ReadTerminated(); LogMessage("DoSlewAsync", $"Slew failed \"{belowHorizonMessage}\""); - throw new ASCOM.InvalidOperationException(belowHorizonMessage); + throw new InvalidOperationException(belowHorizonMessage); case "2": //Below Horizon string belowMinimumElevationMessage = _sharedResourcesWrapper.ReadTerminated(); LogMessage("DoSlewAsync", $"Slew failed \"{belowMinimumElevationMessage}\""); - throw new ASCOM.InvalidOperationException(belowMinimumElevationMessage); + throw new InvalidOperationException(belowMinimumElevationMessage); default: LogMessage("DoSlewAsync", $"Slew failed - unknown response \"{response}\""); - throw new ASCOM.DriverException("This error should not happen"); + throw new DriverException("This error should not happen"); } @@ -1487,7 +1487,7 @@ namespace ASCOM.Meade.net if (maResponse == "1") { - throw new ASCOM.InvalidOperationException("fault"); + throw new InvalidOperationException("fault"); } break; @@ -1544,7 +1544,7 @@ namespace ASCOM.Meade.net CheckConnected("SlewToTargetAsync"); if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER) - throw new ASCOM.InvalidOperationException("No target selected to slew to."); + throw new InvalidOperationException("No target selected to slew to."); DoSlewAsync(true); } @@ -1587,7 +1587,7 @@ namespace ASCOM.Meade.net public void SyncToAltAz(double azimuth, double altitude) { LogMessage("SyncToAltAz", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("SyncToAltAz"); + throw new MethodNotImplementedException("SyncToAltAz"); } public void SyncToCoordinates(double rightAscension, double declination) @@ -1616,7 +1616,7 @@ namespace ASCOM.Meade.net // Autostars & Autostar II - A static string: " M31 EX GAL MAG 3.5 SZ178.0'#" if (result == string.Empty) - throw new ASCOM.InvalidOperationException("Unable to perform sync"); + throw new InvalidOperationException("Unable to perform sync"); } private double _targetDeclination = INVALID_PARAMETER; @@ -1625,7 +1625,7 @@ namespace ASCOM.Meade.net get { if (_targetDeclination == INVALID_PARAMETER) - throw new ASCOM.InvalidOperationException("Target not set"); + throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gd#", "#"); ////:Gd# Get Currently Selected Object/Target Declination @@ -1647,10 +1647,10 @@ namespace ASCOM.Meade.net //todo implement low precision version of this. if (value > 90) - throw new ASCOM.InvalidValueException("Declination cannot be greater than 90."); + throw new InvalidValueException("Declination cannot be greater than 90."); if (value < -90) - throw new ASCOM.InvalidValueException("Declination cannot be less than -90."); + throw new InvalidValueException("Declination cannot be less than -90."); var dms = _utilities.DegreesToDMS(value, "*", ":", ":", 2); var s = value < 0 ? string.Empty : "+"; @@ -1667,7 +1667,7 @@ namespace ASCOM.Meade.net if (result == "0") { - throw new ASCOM.InvalidOperationException("Target declination invalid"); + throw new InvalidOperationException("Target declination invalid"); } _targetDeclination = value; @@ -1680,7 +1680,7 @@ namespace ASCOM.Meade.net get { if (_targetRightAscension == INVALID_PARAMETER) - throw new ASCOM.InvalidOperationException("Target not set"); + throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gr#", "#"); ////:Gr# Get current/target object RA @@ -1914,7 +1914,7 @@ namespace ASCOM.Meade.net public void Unpark() { LogMessage("Unpark", "Not implemented"); - throw new ASCOM.MethodNotImplementedException("Unpark"); + throw new MethodNotImplementedException("Unpark"); } #endregion @@ -1935,7 +1935,7 @@ namespace ASCOM.Meade.net /// If true, registers the driver, otherwise unregisters it. private static void RegUnregASCOM(bool bRegister) { - using (var P = new ASCOM.Utilities.Profile()) + using (var P = new Profile()) { P.DeviceType = "Telescope"; if (bRegister) @@ -2010,7 +2010,7 @@ namespace ASCOM.Meade.net { if (!IsConnected) { - throw new ASCOM.NotConnectedException($"Not connected to telescope when trying to execute: {message}"); + throw new NotConnectedException($"Not connected to telescope when trying to execute: {message}"); } } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index 62d4ba3..d39d12c 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -117,7 +117,7 @@ namespace ASCOM.Meade.net public string Action(string actionName, string actionParameters) { LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters); - throw new ASCOM.ActionNotImplementedException("Action " + actionName + " is not implemented by this driver"); + throw new ActionNotImplementedException("Action " + actionName + " is not implemented by this driver"); } public void CommandBlind(string command, bool raw) @@ -137,7 +137,7 @@ namespace ASCOM.Meade.net //string ret = CommandString(command, raw); // TODO decode the return string and return true or false // or - throw new ASCOM.MethodNotImplementedException("CommandBool"); + throw new MethodNotImplementedException("CommandBool"); // DO NOT have both these sections! One or the other } @@ -149,7 +149,7 @@ namespace ASCOM.Meade.net // you need something to ensure that only one command is in progress at a time return _sharedResourcesWrapper.SendString(command); - throw new ASCOM.MethodNotImplementedException("CommandString"); + throw new MethodNotImplementedException("CommandString"); } public void Dispose() @@ -250,7 +250,7 @@ namespace ASCOM.Meade.net { get { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + Version version = Assembly.GetExecutingAssembly().GetName().Version; // TODO customise this driver description string driverInfo = "Information about the driver itself. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); tl.LogMessage("DriverInfo Get", driverInfo); @@ -262,7 +262,7 @@ namespace ASCOM.Meade.net { get { - Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + Version version = Assembly.GetExecutingAssembly().GetName().Version; string driverVersion = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); tl.LogMessage("DriverVersion Get", driverVersion); return driverVersion; @@ -334,13 +334,13 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("Link Get", this.Connected.ToString()); - return this.Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility + tl.LogMessage("Link Get", Connected.ToString()); + return Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility } set { tl.LogMessage("Link Set", value.ToString()); - this.Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility + Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility } } @@ -375,7 +375,7 @@ namespace ASCOM.Meade.net if (Position < -MaxIncrement || Position > MaxIncrement) { - throw new ASCOM.InvalidValueException($"position out of range {-MaxIncrement} < {Position} < {MaxIncrement}"); + throw new InvalidValueException($"position out of range {-MaxIncrement} < {Position} < {MaxIncrement}"); } if (Position == 0) @@ -434,7 +434,7 @@ namespace ASCOM.Meade.net { get { - throw new ASCOM.PropertyNotImplementedException("Position", false); + throw new PropertyNotImplementedException("Position", false); //return focuserPosition; // Return the focuser position } } @@ -444,7 +444,7 @@ namespace ASCOM.Meade.net get { tl.LogMessage("StepSize Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("StepSize", false); + throw new PropertyNotImplementedException("StepSize", false); } } @@ -458,7 +458,7 @@ namespace ASCOM.Meade.net set { tl.LogMessage("TempComp Set", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("TempComp", false); + throw new PropertyNotImplementedException("TempComp", false); } } @@ -476,7 +476,7 @@ namespace ASCOM.Meade.net get { tl.LogMessage("Temperature Get", "Not implemented"); - throw new ASCOM.PropertyNotImplementedException("Temperature", false); + throw new PropertyNotImplementedException("Temperature", false); } } @@ -498,7 +498,7 @@ namespace ASCOM.Meade.net /// If true, registers the driver, otherwise unregisters it. private static void RegUnregASCOM(bool bRegister) { - using (var P = new ASCOM.Utilities.Profile()) + using (var P = new Profile()) { P.DeviceType = "Focuser"; if (bRegister) @@ -573,7 +573,7 @@ namespace ASCOM.Meade.net { if (!IsConnected) { - throw new ASCOM.NotConnectedException(message); + throw new NotConnectedException(message); } } diff --git a/Meade.net/LocalServer.cs b/Meade.net/LocalServer.cs index a4fc2c2..922dbec 100644 --- a/Meade.net/LocalServer.cs +++ b/Meade.net/LocalServer.cs @@ -420,7 +420,7 @@ namespace ASCOM.Meade.net // Pull the display name from the ServedClassName attribute. attr = Attribute.GetCustomAttribute(type, typeof(ServedClassNameAttribute)); //PWGS Changed to search type for attribute rather than assembly string chooserName = ((ServedClassNameAttribute)attr).DisplayName ?? "MultiServer"; - using (var P = new ASCOM.Utilities.Profile()) + using (var P = new Profile()) { P.DeviceType = deviceType; P.Register(progid, chooserName); @@ -490,7 +490,7 @@ namespace ASCOM.Meade.net // // ASCOM // - using (var P = new ASCOM.Utilities.Profile()) + using (var P = new Profile()) { P.DeviceType = deviceType; P.Unregister(progid); diff --git a/Meade.net/SetupDialogForm.cs b/Meade.net/SetupDialogForm.cs index 2a1dac3..aedb020 100644 --- a/Meade.net/SetupDialogForm.cs +++ b/Meade.net/SetupDialogForm.cs @@ -29,12 +29,12 @@ namespace ASCOM.Meade.net { System.Diagnostics.Process.Start("http://ascom-standards.org/"); } - catch (System.ComponentModel.Win32Exception noBrowser) + catch (Win32Exception noBrowser) { if (noBrowser.ErrorCode == -2147467259) MessageBox.Show(noBrowser.Message); } - catch (System.Exception other) + catch (Exception other) { MessageBox.Show(other.Message); } diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 7b7525b..1dd7630 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -35,7 +35,7 @@ namespace ASCOM.Meade.net private static readonly object lockObject = new object(); // Shared serial port. This will allow multiple drivers to use one single serial port. - private static ASCOM.Utilities.Serial s_sharedSerial; // Shared serial port + private static Serial s_sharedSerial; // Shared serial port // // Public access to shared resources @@ -60,7 +60,7 @@ namespace ASCOM.Meade.net /// /// Shared serial port /// - public static ASCOM.Utilities.Serial SharedSerial => s_sharedSerial ?? (s_sharedSerial = new ASCOM.Utilities.Serial()); + public static Serial SharedSerial => s_sharedSerial ?? (s_sharedSerial = new Serial()); /// /// number of connections to the shared serial port @@ -266,15 +266,15 @@ namespace ASCOM.Meade.net if (connectedDevices[deviceId].count == 1) { var profileProperties = ReadProfile(); - SharedResources.SharedSerial.PortName = profileProperties.ComPort; - SharedResources.SharedSerial.DTREnable = false; - SharedResources.SharedSerial.RTSEnable = false; - SharedResources.SharedSerial.DataBits = 8; - SharedResources.SharedSerial.StopBits = SerialStopBits.One; - SharedResources.SharedSerial.Parity = SerialParity.None; - SharedResources.SharedSerial.Speed = SerialSpeed.ps9600; - SharedResources.SharedSerial.Handshake = SerialHandshake.None; - SharedResources.SharedSerial.Connected = true; + SharedSerial.PortName = profileProperties.ComPort; + SharedSerial.DTREnable = false; + SharedSerial.RTSEnable = false; + SharedSerial.DataBits = 8; + SharedSerial.StopBits = SerialStopBits.One; + SharedSerial.Parity = SerialParity.None; + SharedSerial.Speed = SerialSpeed.ps9600; + SharedSerial.Handshake = SerialHandshake.None; + SharedSerial.Connected = true; ProductName = SendString(":GVP#"); FirmwareVersion = SendString(":GVN#"); @@ -295,7 +295,7 @@ namespace ASCOM.Meade.net connectedDevices.Remove(deviceId); if (deviceId == "Serial") { - SharedResources.SharedSerial.Connected = false; + SharedSerial.Connected = false; } } } diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 98c8e2b..6636701 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -22,11 +22,11 @@ namespace ASCOM // Uncomment the code that's required #if UseChooser // choose the device - string id = ASCOM.DriverAccess.Telescope.Choose("ASCOM.MeadeGeneric.Telescope"); + string id = DriverAccess.Telescope.Choose("ASCOM.MeadeGeneric.Telescope"); if (string.IsNullOrEmpty(id)) return; // create this device - ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope(id); + DriverAccess.Telescope device = new DriverAccess.Telescope(id); #else // this can be replaced by this code, it avoids the chooser and creates the driver class directly. ASCOM.DriverAccess.Telescope device = new ASCOM.DriverAccess.Telescope("ASCOM.Meade.net.Telescope"); From c1cae2b0c4da511f9e5d39ffb8bed4371b2d45f5 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 13:13:15 +0100 Subject: [PATCH 104/109] Removed redundant using statements --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 1 - AstroMath.UnitTests/Properties/AssemblyInfo.cs | 1 - FocuserTestConsole/Program.cs | 3 --- FocuserTestConsole/Properties/AssemblyInfo.cs | 1 - Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs | 1 - Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs | 2 -- Meade.net.Telescope/Properties/AssemblyInfo.cs | 1 - Meade.net.Telescope/Rates.cs | 6 +----- Meade.net.focuser/Properties/AssemblyInfo.cs | 1 - Meade.net/LocalServer.cs | 3 --- Meade.net/Properties/AssemblyInfo.cs | 1 - Meade.net/ReferenceCountedObject.cs | 1 - Meade.net/SetupDialogForm.cs | 5 ----- Meade.net/SharedResources.cs | 2 -- Meade.net/Wrapper/SharedResourcesWrapper.cs | 3 --- Meade.net/frmMain.cs | 5 ----- TelescopeTestConsole/Program.cs | 3 --- TelescopeTestConsole/Properties/AssemblyInfo.cs | 1 - 18 files changed, 1 insertion(+), 40 deletions(-) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index a890647..b54ab61 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -1,5 +1,4 @@ using System; -using ASCOM.Meade.net; using ASCOM.Meade.net.AstroMaths; using NUnit.Framework; diff --git a/AstroMath.UnitTests/Properties/AssemblyInfo.cs b/AstroMath.UnitTests/Properties/AssemblyInfo.cs index 2c0f1a3..3bfdd87 100644 --- a/AstroMath.UnitTests/Properties/AssemblyInfo.cs +++ b/AstroMath.UnitTests/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/FocuserTestConsole/Program.cs b/FocuserTestConsole/Program.cs index aff0a29..cfafd57 100644 --- a/FocuserTestConsole/Program.cs +++ b/FocuserTestConsole/Program.cs @@ -9,9 +9,6 @@ #define UseChooser using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using ASCOM.DriverAccess; diff --git a/FocuserTestConsole/Properties/AssemblyInfo.cs b/FocuserTestConsole/Properties/AssemblyInfo.cs index 1349406..b1cdefc 100644 --- a/FocuserTestConsole/Properties/AssemblyInfo.cs +++ b/FocuserTestConsole/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs index b58554d..3b11908 100644 --- a/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index ab6cf16..4cfd9f0 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.Eventing.Reader; using ASCOM; using ASCOM.Astrometry.AstroUtils; using ASCOM.DeviceInterface; @@ -10,7 +9,6 @@ using ASCOM.Utilities.Interfaces; using Moq; using NUnit.Framework; using InvalidOperationException = ASCOM.InvalidOperationException; -using NotImplementedException = ASCOM.NotImplementedException; namespace Meade.net.Telescope.UnitTests { diff --git a/Meade.net.Telescope/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs index 5376198..1a4865e 100644 --- a/Meade.net.Telescope/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Meade.net.Telescope/Rates.cs b/Meade.net.Telescope/Rates.cs index 0579dc7..550f28a 100644 --- a/Meade.net.Telescope/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using ASCOM.DeviceInterface; using System.Collections; using System.Threading; diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs index d74c566..d812c2d 100644 --- a/Meade.net.focuser/Properties/AssemblyInfo.cs +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Meade.net/LocalServer.cs b/Meade.net/LocalServer.cs index 922dbec..8bbee9e 100644 --- a/Meade.net/LocalServer.cs +++ b/Meade.net/LocalServer.cs @@ -15,17 +15,14 @@ using System; using System.IO; using System.Windows.Forms; -using System.Drawing; using System.Collections; using System.Runtime.InteropServices; using System.Reflection; using ASCOM.Utilities; using Microsoft.Win32; -using System.Text; using System.Threading; using System.Security.Principal; using System.Diagnostics; -using ASCOM; namespace ASCOM.Meade.net { diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs index 502789e..0c66435 100644 --- a/Meade.net/Properties/AssemblyInfo.cs +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Meade.net/ReferenceCountedObject.cs b/Meade.net/ReferenceCountedObject.cs index 7c7b7f2..aaf3f23 100644 --- a/Meade.net/ReferenceCountedObject.cs +++ b/Meade.net/ReferenceCountedObject.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.InteropServices; namespace ASCOM.Meade.net diff --git a/Meade.net/SetupDialogForm.cs b/Meade.net/SetupDialogForm.cs index aedb020..c416f5d 100644 --- a/Meade.net/SetupDialogForm.cs +++ b/Meade.net/SetupDialogForm.cs @@ -1,12 +1,7 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; using System.Runtime.InteropServices; -using System.Text; using System.Windows.Forms; -using ASCOM.Utilities; -using ASCOM.Meade.net; namespace ASCOM.Meade.net { diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 1dd7630..b3b15f7 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -15,8 +15,6 @@ // using System; using System.Collections.Generic; -using System.Text; -using ASCOM; using ASCOM.Utilities; namespace ASCOM.Meade.net diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index a7f662c..cbfa0d3 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace ASCOM.Meade.net.Wrapper { diff --git a/Meade.net/frmMain.cs b/Meade.net/frmMain.cs index 92b3be7..7ac44b7 100644 --- a/Meade.net/frmMain.cs +++ b/Meade.net/frmMain.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Text; using System.Windows.Forms; namespace ASCOM.Meade.net diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 6636701..36d0d4a 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -9,9 +9,6 @@ #define UseChooser using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace ASCOM { diff --git a/TelescopeTestConsole/Properties/AssemblyInfo.cs b/TelescopeTestConsole/Properties/AssemblyInfo.cs index a358cd7..cd3bac2 100644 --- a/TelescopeTestConsole/Properties/AssemblyInfo.cs +++ b/TelescopeTestConsole/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following From d6f72c8222a8d99d32643cbbf97786b9cbd9e9fe Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 13:22:15 +0100 Subject: [PATCH 105/109] Code inspections --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 4 +-- .../AstroMaths/AltitudeData.cs | 2 +- Meade.net.Telescope/Rates.cs | 36 +++++++------------ Meade.net.Telescope/Telescope.cs | 21 +++++------ Meade.net.focuser/Focuser.cs | 9 +---- Meade.net/ClassFactory.cs | 16 ++++----- Meade.net/SharedResources.cs | 2 +- 7 files changed, 36 insertions(+), 54 deletions(-) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index b54ab61..a72f498 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -58,7 +58,7 @@ namespace AstroMath.UnitTests } [Test] - public void UTtoGST() + public void UTtoGst() { DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); double gst = _astroMath.UTtoGST(dateTime); @@ -76,7 +76,7 @@ namespace AstroMath.UnitTests } [Test] - public void GSTtoLST() + public void GsTtoLst() { double gst = 14.257589512545053; var longitude = -1.7833333333333332; diff --git a/Meade.net.Telescope/AstroMaths/AltitudeData.cs b/Meade.net.Telescope/AstroMaths/AltitudeData.cs index a00f7db..6ca2890 100644 --- a/Meade.net.Telescope/AstroMaths/AltitudeData.cs +++ b/Meade.net.Telescope/AstroMaths/AltitudeData.cs @@ -7,6 +7,6 @@ namespace ASCOM.Meade.net.AstroMaths public DateTime UtcDateTime { get; set; } public double SiteLatitude { get; set; } public double SiteLongitude { get; set; } - public EquatorialCoordinates equatorialCoordinates { get; set; } + public EquatorialCoordinates EquatorialCoordinates { get; set; } } } \ No newline at end of file diff --git a/Meade.net.Telescope/Rates.cs b/Meade.net.Telescope/Rates.cs index 550f28a..bf75539 100644 --- a/Meade.net.Telescope/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -19,8 +19,8 @@ namespace ASCOM.Meade.net [ComVisible(true)] public class Rate : IRate { - private double maximum = 0; - private double minimum = 0; + private double _maximum = 0; + private double _minimum = 0; // // Default constructor - Internal prevents public creation @@ -28,8 +28,8 @@ namespace ASCOM.Meade.net // internal Rate(double minimum, double maximum) { - this.maximum = maximum; - this.minimum = minimum; + _maximum = maximum; + _minimum = minimum; } #region Implementation of IRate @@ -41,14 +41,14 @@ namespace ASCOM.Meade.net public double Maximum { - get { return maximum; } - set { maximum = value; } + get => _maximum; + set => _maximum = value; } public double Minimum { - get { return minimum; } - set { minimum = value; } + get => _minimum; + set => _minimum = value; } #endregion @@ -112,10 +112,7 @@ namespace ASCOM.Meade.net #region IAxisRates Members - public int Count - { - get { return rates.Length; } - } + public int Count => rates.Length; public void Dispose() { @@ -127,10 +124,7 @@ namespace ASCOM.Meade.net return rates.GetEnumerator(); } - public IRate this[int index] - { - get { return rates[index - 1]; } // 1-based - } + public IRate this[int index] => rates[index - 1]; #endregion } @@ -178,10 +172,7 @@ namespace ASCOM.Meade.net #region ITrackingRates Members - public int Count - { - get { return trackingRates.Length; } - } + public int Count => trackingRates.Length; public IEnumerator GetEnumerator() { @@ -194,10 +185,7 @@ namespace ASCOM.Meade.net // TODO Add any required object cleanup here } - public DriveRates this[int index] - { - get { return trackingRates[index - 1]; } // 1-based - } + public DriveRates this[int index] => trackingRates[index - 1]; #endregion diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index d57d84a..c082f33 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -6,6 +6,7 @@ using ASCOM.Astrometry.AstroUtils; using ASCOM.Utilities; using ASCOM.DeviceInterface; using System.Collections; +using System.Globalization; using System.Reflection; using ASCOM.Meade.net.AstroMaths; using ASCOM.Meade.net.Wrapper; @@ -38,15 +39,15 @@ namespace ASCOM.Meade.net /// The DeviceID is used by ASCOM applications to load the driver at runtime. /// //internal static string driverID = "ASCOM.Meade.net.Telescope"; - internal static string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); // TODO Change the descriptive string for your driver then remove this line /// /// Driver description that displays in the ASCOM Chooser. /// - private static string driverDescription = "Meade Generic"; + private static readonly string driverDescription = "Meade Generic"; - internal static string comPort; // Variables to hold the currrent device configuration + private static string comPort; // Variables to hold the currrent device configuration /// /// Private variable to hold an ASCOM Utilities object @@ -583,7 +584,7 @@ namespace ASCOM.Meade.net UtcDateTime = UTCDate, SiteLongitude = SiteLongitude, SiteLatitude = SiteLatitude, - equatorialCoordinates = new EquatorialCoordinates() + EquatorialCoordinates = new EquatorialCoordinates() { RightAscension = RightAscension, Declination = Declination @@ -591,8 +592,8 @@ namespace ASCOM.Meade.net }); double hourAngle = _astroMaths.RightAscensionToHourAngle(altitudeData.UtcDateTime, altitudeData.SiteLongitude, - altitudeData.equatorialCoordinates.RightAscension); - var altAz = _astroMaths.ConvertEqToHoz(hourAngle, altitudeData.SiteLatitude, altitudeData.equatorialCoordinates); + altitudeData.EquatorialCoordinates.RightAscension); + var altAz = _astroMaths.ConvertEqToHoz(hourAngle, altitudeData.SiteLatitude, altitudeData.EquatorialCoordinates); return altAz; } @@ -632,7 +633,7 @@ namespace ASCOM.Meade.net LogMessage("AtPark", "Get - " + _atPark); return _atPark; } - private set { _atPark = value; } + private set => _atPark = value; } public IAxisRates AxisRates(TelescopeAxes Axis) @@ -842,7 +843,7 @@ namespace ASCOM.Meade.net get { double declination = 0.0; - LogMessage("DeclinationRate", "Get - " + declination.ToString()); + LogMessage("DeclinationRate", "Get - " + declination.ToString(CultureInfo.InvariantCulture)); return declination; } set @@ -1141,7 +1142,7 @@ namespace ASCOM.Meade.net get { double rightAscensionRate = 0.0; - LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString()); + LogMessage("RightAscensionRate", "Get - " + rightAscensionRate.ToString(CultureInfo.InvariantCulture)); return rightAscensionRate; } set @@ -1192,7 +1193,7 @@ namespace ASCOM.Meade.net // Reduce to the range 0 to 24 hours siderealTime = _astroUtilities.ConditionRA(siderealTime); - LogMessage("SiderealTime", "Get - " + siderealTime.ToString()); + LogMessage("SiderealTime", "Get - " + siderealTime.ToString(CultureInfo.InvariantCulture)); return siderealTime; } } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index d39d12c..de1c03b 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -430,14 +430,7 @@ namespace ASCOM.Meade.net }); } - public int Position - { - get - { - throw new PropertyNotImplementedException("Position", false); - //return focuserPosition; // Return the focuser position - } - } + public int Position => throw new PropertyNotImplementedException("Position", false); public double StepSize { diff --git a/Meade.net/ClassFactory.cs b/Meade.net/ClassFactory.cs index 1626f5c..7b61d4f 100644 --- a/Meade.net/ClassFactory.cs +++ b/Meade.net/ClassFactory.cs @@ -109,9 +109,9 @@ namespace ASCOM.Meade.net #region Constructor and Private ClassFactory Data - protected Type m_ClassType; + protected readonly Type m_ClassType; protected Guid m_ClassId; - protected ArrayList m_InterfaceTypes; + protected readonly ArrayList m_InterfaceTypes; protected uint m_ClassContext; protected uint m_Flags; protected UInt32 m_locked = 0; @@ -140,20 +140,20 @@ namespace ASCOM.Meade.net #region Common ClassFactory Methods public uint ClassContext { - get { return m_ClassContext; } - set { m_ClassContext = value; } + get => m_ClassContext; + set => m_ClassContext = value; } public Guid ClassId { - get { return m_ClassId; } - set { m_ClassId = value; } + get => m_ClassId; + set => m_ClassId = value; } public uint Flags { - get { return m_Flags; } - set { m_Flags = value; } + get => m_Flags; + set => m_Flags = value; } public bool RegisterClassObject() diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index b3b15f7..1d5a709 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -146,7 +146,7 @@ namespace ASCOM.Meade.net } } } - get { return SharedSerial.Connected; } + get => SharedSerial.Connected; } #endregion From 9cf63c4912a6e7c9d3eb25754c72c1a63c7864e5 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 14:23:27 +0100 Subject: [PATCH 106/109] Code inspections --- AstroMath.UnitTests/AstroMathsUnitTests.cs | 8 +- .../TelescopeUnitTests.cs | 20 +- Meade.net.Telescope/AstroMaths/AstroMaths.cs | 12 +- Meade.net.Telescope/AstroMaths/IAstroMaths.cs | 4 +- Meade.net.Telescope/Rates.cs | 44 ++--- Meade.net.Telescope/Telescope.cs | 120 ++++++------ Meade.net.focuser/Focuser.cs | 108 +++++------ Meade.net/ClassFactory.cs | 126 ++++++------- Meade.net/GarbageCollection.cs | 30 +-- Meade.net/LocalServer.cs | 174 +++++++++--------- Meade.net/SharedResources.cs | 82 ++++----- Meade.net/Wrapper/SharedResourcesWrapper.cs | 12 +- Meade.net/frmMain.Designer.cs | 4 +- Meade.net/frmMain.cs | 4 +- 14 files changed, 374 insertions(+), 374 deletions(-) diff --git a/AstroMath.UnitTests/AstroMathsUnitTests.cs b/AstroMath.UnitTests/AstroMathsUnitTests.cs index a72f498..c6c0082 100644 --- a/AstroMath.UnitTests/AstroMathsUnitTests.cs +++ b/AstroMath.UnitTests/AstroMathsUnitTests.cs @@ -52,7 +52,7 @@ namespace AstroMath.UnitTests public void UTtoGST_book() { DateTime dateTime = new DateTime(1980, 04, 22, 14, 36, 51, 670, DateTimeKind.Utc); - double gst = _astroMath.UTtoGST(dateTime); + double gst = _astroMath.UTtoGst(dateTime); Assert.That(gst, Is.EqualTo(4.667932706211154)); } @@ -61,7 +61,7 @@ namespace AstroMath.UnitTests public void UTtoGst() { DateTime dateTime = new DateTime(2019, 05, 18, 22, 26, 15, DateTimeKind.Utc); - double gst = _astroMath.UTtoGST(dateTime); + double gst = _astroMath.UTtoGst(dateTime); Assert.That(gst, Is.EqualTo(14.191879687876451)); } @@ -71,7 +71,7 @@ namespace AstroMath.UnitTests { double gst = 4.668119; var longitude = -64; - var lst = _astroMath.GSTtoLST(gst, longitude); + var lst = _astroMath.GsTtoLst(gst, longitude); Assert.That(lst, Is.EqualTo(0.4014523333333333)); } @@ -80,7 +80,7 @@ namespace AstroMath.UnitTests { double gst = 14.257589512545053; var longitude = -1.7833333333333332; - var lst = _astroMath.GSTtoLST(gst, longitude); + var lst = _astroMath.GsTtoLst(gst, longitude); Assert.That(lst, Is.EqualTo(14.138700623656163)); } diff --git a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs index 4cfd9f0..1f29a92 100644 --- a/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs +++ b/Meade.net.Telescope.UnitTests/TelescopeUnitTests.cs @@ -37,9 +37,9 @@ namespace Meade.net.Telescope.UnitTests _sharedResourcesWrapperMock = new Mock(); _sharedResourcesWrapperMock.Setup(x => x.SendString(":GZ#")).Returns("DDD*MM’SS"); - _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497).Returns(() => "AUTOSTAR"); - _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_31EE).Returns(() => "31Ee"); - _sharedResourcesWrapperMock.Setup(x => x.AUTOSTAR497_43EG) .Returns(() => "43Eg"); + _sharedResourcesWrapperMock.Setup(x => x.Autostar497).Returns(() => "AUTOSTAR"); + _sharedResourcesWrapperMock.Setup(x => x.Autostar49731Ee).Returns(() => "31Ee"); + _sharedResourcesWrapperMock.Setup(x => x.Autostar49743Eg) .Returns(() => "43Eg"); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny())).Callback(action => { action(); }); _sharedResourcesWrapperMock.Setup(x => x.Lock(It.IsAny>())).Returns>( (func) => func()); @@ -56,8 +56,8 @@ namespace Meade.net.Telescope.UnitTests private void ConnectTelescope() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.Autostar497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.Autostar49731Ee); _telescope.Connected = true; } @@ -238,8 +238,8 @@ namespace Meade.net.Telescope.UnitTests [TestCase(false)] public void Connected_Get_ReturnsExpectedValue(bool expectedConnected) { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.Autostar497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.Autostar49731Ee); _telescope.Connected = expectedConnected; Assert.That(_telescope.Connected, Is.EqualTo(expectedConnected)); @@ -275,8 +275,8 @@ namespace Meade.net.Telescope.UnitTests [Test] public void Connected_Set_WhenFailsToConnect_ThenDisconnects() { - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); - _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497_31EE); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.Autostar497); + _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => _sharedResourcesWrapperMock.Object.Autostar49731Ee); _sharedResourcesWrapperMock.Setup(x => x.SendString(It.IsAny())).Throws(new Exception("TestFailed")); @@ -999,7 +999,7 @@ namespace Meade.net.Telescope.UnitTests public void PulseGuide_WhenConnectedAndNewerPulseGuidingNotAvailable_ThenSendsOldCommandsAndWaits(GuideDirections direction) { var duration = 0; - _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.AUTOSTAR497); + _sharedResourcesWrapperMock.Setup(x => x.ProductName).Returns(() => _sharedResourcesWrapperMock.Object.Autostar497); _sharedResourcesWrapperMock.Setup(x => x.FirmwareVersion).Returns(() => "31Ed"); _telescope.Connected = true; diff --git a/Meade.net.Telescope/AstroMaths/AstroMaths.cs b/Meade.net.Telescope/AstroMaths/AstroMaths.cs index 45fea5f..17e168b 100644 --- a/Meade.net.Telescope/AstroMaths/AstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths/AstroMaths.cs @@ -10,8 +10,8 @@ namespace ASCOM.Meade.net.AstroMaths public double RightAscensionToHourAngle(DateTime utcDateTime, double longitude, double rightAscension) { var ut = DateTimeToDecimalHours( utcDateTime); - var gst = UTtoGST( utcDateTime); - var lst = GSTtoLST( gst, longitude); + var gst = UTtoGst( utcDateTime); + var lst = GsTtoLst( gst, longitude); var raHours = rightAscension; var h1 = lst - raHours; var h = h1; @@ -24,8 +24,8 @@ namespace ASCOM.Meade.net.AstroMaths public double HourAngleToRightAscension(DateTime utcDateTime, double longitude, double hourAngle ) { - var gst = UTtoGST(utcDateTime); - var lst = GSTtoLST( gst, longitude); + var gst = UTtoGst(utcDateTime); + var lst = GsTtoLst( gst, longitude); var raHours = hourAngle; var h1 = lst - raHours; var h = h1; @@ -129,7 +129,7 @@ namespace ASCOM.Meade.net.AstroMaths } //todo convert to extension method - public double UTtoGST(DateTime utcDateTime) + public double UTtoGst(DateTime utcDateTime) { Util util = new Util(); @@ -171,7 +171,7 @@ namespace ASCOM.Meade.net.AstroMaths return t1; } - public double GSTtoLST(double gst, double longitude) + public double GsTtoLst(double gst, double longitude) { var l = longitude/ 15; diff --git a/Meade.net.Telescope/AstroMaths/IAstroMaths.cs b/Meade.net.Telescope/AstroMaths/IAstroMaths.cs index ff4ef4e..dfcab3a 100644 --- a/Meade.net.Telescope/AstroMaths/IAstroMaths.cs +++ b/Meade.net.Telescope/AstroMaths/IAstroMaths.cs @@ -11,7 +11,7 @@ namespace ASCOM.Meade.net.AstroMaths double DegreesToRadians(double degrees); double RadiansToDegrees(double radians); double DateTimeToDecimalHours( DateTime utcDateTime); - double UTtoGST(DateTime utcDateTime); - double GSTtoLST(double gst, double longitude); + double UTtoGst(DateTime utcDateTime); + double GsTtoLst(double gst, double longitude); } } \ No newline at end of file diff --git a/Meade.net.Telescope/Rates.cs b/Meade.net.Telescope/Rates.cs index bf75539..8d9e970 100644 --- a/Meade.net.Telescope/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -70,8 +70,8 @@ namespace ASCOM.Meade.net [ComVisible(true)] public class AxisRates : IAxisRates, IEnumerable { - private TelescopeAxes axis; - private readonly Rate[] rates; + private TelescopeAxes _axis; + private readonly Rate[] _rates; // // Constructor - Internal prevents public creation @@ -79,7 +79,7 @@ namespace ASCOM.Meade.net // internal AxisRates(TelescopeAxes axis) { - this.axis = axis; + this._axis = axis; // // This collection must hold zero or more Rate objects describing the // rates of motion ranges for the Telescope.MoveAxis() method @@ -96,23 +96,23 @@ namespace ASCOM.Meade.net // TODO Initialize this array with any Primary axis rates that your driver may provide // Example: m_Rates = new Rate[] { new Rate(10.5, 30.2), new Rate(54.0, 43.6) } //this.rates = new Rate[0]; - rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; + _rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisSecondary: // TODO Initialize this array with any Secondary axis rates that your driver may provide //this.rates = new Rate[0]; - rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; + _rates = new Rate[] { new Rate(1, 1), new Rate(2, 2), new Rate(3, 3), new Rate(4, 4) }; break; case TelescopeAxes.axisTertiary: // TODO Initialize this array with any Tertiary axis rates that your driver may provide - rates = new Rate[0]; + _rates = new Rate[0]; break; } } #region IAxisRates Members - public int Count => rates.Length; + public int Count => _rates.Length; public void Dispose() { @@ -121,10 +121,10 @@ namespace ASCOM.Meade.net public IEnumerator GetEnumerator() { - return rates.GetEnumerator(); + return _rates.GetEnumerator(); } - public IRate this[int index] => rates[index - 1]; + public IRate this[int index] => _rates[index - 1]; #endregion } @@ -149,11 +149,11 @@ namespace ASCOM.Meade.net [ComVisible(true)] public class TrackingRates : ITrackingRates, IEnumerable, IEnumerator { - private readonly DriveRates[] trackingRates; + private readonly DriveRates[] _trackingRates; // this is used to make the index thread safe - private readonly ThreadLocal pos = new ThreadLocal(() => { return -1; }); - private static readonly object lockObj = new object(); + private readonly ThreadLocal _pos = new ThreadLocal(() => { return -1; }); + private static readonly object LockObj = new object(); // // Default constructor - Internal prevents public creation @@ -166,17 +166,17 @@ namespace ASCOM.Meade.net // the tracking rates supported by your telescope. The one value // (tracking rate) that MUST be supported is driveSidereal! // - trackingRates = new[] { DriveRates.driveSidereal, DriveRates.driveLunar }; + _trackingRates = new[] { DriveRates.driveSidereal, DriveRates.driveLunar }; // TODO Initialize this array with any additional tracking rates that your driver may provide } #region ITrackingRates Members - public int Count => trackingRates.Length; + public int Count => _trackingRates.Length; public IEnumerator GetEnumerator() { - pos.Value = -1; + _pos.Value = -1; return this as IEnumerator; } @@ -185,7 +185,7 @@ namespace ASCOM.Meade.net // TODO Add any required object cleanup here } - public DriveRates this[int index] => trackingRates[index - 1]; + public DriveRates this[int index] => _trackingRates[index - 1]; #endregion @@ -195,22 +195,22 @@ namespace ASCOM.Meade.net { get { - lock (lockObj) + lock (LockObj) { - if (pos.Value < 0 || pos.Value >= trackingRates.Length) + if (_pos.Value < 0 || _pos.Value >= _trackingRates.Length) { throw new System.InvalidOperationException(); } - return trackingRates[pos.Value]; + return _trackingRates[_pos.Value]; } } } public bool MoveNext() { - lock (lockObj) + lock (LockObj) { - if (++pos.Value >= trackingRates.Length) + if (++_pos.Value >= _trackingRates.Length) { return false; } @@ -220,7 +220,7 @@ namespace ASCOM.Meade.net public void Reset() { - pos.Value = -1; + _pos.Value = -1; } #endregion } diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index c082f33..264dacb 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -39,15 +39,15 @@ namespace ASCOM.Meade.net /// The DeviceID is used by ASCOM applications to load the driver at runtime. /// //internal static string driverID = "ASCOM.Meade.net.Telescope"; - private static readonly string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string DriverId = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); // TODO Change the descriptive string for your driver then remove this line /// /// Driver description that displays in the ASCOM Chooser. /// - private static readonly string driverDescription = "Meade Generic"; + private static readonly string DriverDescription = "Meade Generic"; - private static string comPort; // Variables to hold the currrent device configuration + private static string _comPort; // Variables to hold the currrent device configuration /// /// Private variable to hold an ASCOM Utilities object @@ -65,7 +65,7 @@ namespace ASCOM.Meade.net /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) /// - private TraceLogger tl; + private TraceLogger _tl; private readonly ISharedResourcesWrapper _sharedResourcesWrapper; @@ -100,7 +100,7 @@ namespace ASCOM.Meade.net private void Initialise() { //todo move the TraceLogger out to a factory class. - tl = new TraceLogger("", "Meade.net.Telescope"); + _tl = new TraceLogger("", "Meade.net.Telescope"); LogMessage("Telescope", "Starting initialisation"); ReadProfile(); // Read device configuration from the ASCOM Profile store @@ -279,9 +279,9 @@ namespace ASCOM.Meade.net Connected = false; // Clean up the tracelogger and util objects - tl.Enabled = false; - tl.Dispose(); - tl = null; + _tl.Enabled = false; + _tl.Dispose(); + _tl = null; } public bool Connected @@ -299,18 +299,18 @@ namespace ASCOM.Meade.net if (value) { - LogMessage("Connected Set", "Connecting to port {0}", comPort); + LogMessage("Connected Set", "Connecting to port {0}", _comPort); try { _sharedResourcesWrapper.Connect("Serial"); try { - LogMessage("Connected Set", $"Connected to port {comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); + LogMessage("Connected Set", $"Connected to port {_comPort}. Product: {_sharedResourcesWrapper.ProductName} Version:{_sharedResourcesWrapper.FirmwareVersion}"); SetLongFormat(true); _userNewerPulseGuiding = IsNewPulseGuidingSupported(); - _targetDeclination = INVALID_PARAMETER; - _targetRightAscension = INVALID_PARAMETER; + _targetDeclination = InvalidParameter; + _targetRightAscension = InvalidParameter; _tracking = true; LogMessage("Connected Set", $"New Pulse Guiding Supported: {_userNewerPulseGuiding}"); @@ -324,12 +324,12 @@ namespace ASCOM.Meade.net } catch (Exception ex) { - LogMessage("Connected Set", "Error connecting to port {0} - {1}", comPort, ex.Message); + LogMessage("Connected Set", "Error connecting to port {0} - {1}", _comPort, ex.Message); } } else { - LogMessage("Connected Set", "Disconnecting from port {0}", comPort); + LogMessage("Connected Set", "Disconnecting from port {0}", _comPort); _sharedResourcesWrapper.Disconnect("Serial"); IsConnected = false; } @@ -338,9 +338,9 @@ namespace ASCOM.Meade.net public bool IsNewPulseGuidingSupported() { - if (_sharedResourcesWrapper.ProductName == _sharedResourcesWrapper.AUTOSTAR497) + if (_sharedResourcesWrapper.ProductName == _sharedResourcesWrapper.Autostar497) { - return FirmwareIsGreaterThan(_sharedResourcesWrapper.AUTOSTAR497_31EE); + return FirmwareIsGreaterThan(_sharedResourcesWrapper.Autostar49731Ee); } return false; @@ -395,8 +395,8 @@ namespace ASCOM.Meade.net // TODO customise this device description get { - LogMessage("Description Get", driverDescription); - return driverDescription; + LogMessage("Description Get", DriverDescription); + return DriverDescription; } } @@ -447,7 +447,7 @@ namespace ASCOM.Meade.net ////Returns: dd.d# //string name = $"{telescopeProduceName} - {firmwareVersion}"; - string name = driverDescription; + string name = DriverDescription; LogMessage("Name Get", name); return name; } @@ -525,7 +525,7 @@ namespace ASCOM.Meade.net CheckConnected("AlignmentMode Set"); //todo tidy this up into a better solution that means can :GW#, :AL#, :AA#, & :AP# and checked for Autostar properly - if (!FirmwareIsGreaterThan(_sharedResourcesWrapper.AUTOSTAR497_43EG)) + if (!FirmwareIsGreaterThan(_sharedResourcesWrapper.Autostar49743Eg)) throw new PropertyNotImplementedException("AlignmentMode",true ); //todo make this only try with Autostar 43Eg and above. @@ -636,10 +636,10 @@ namespace ASCOM.Meade.net private set => _atPark = value; } - public IAxisRates AxisRates(TelescopeAxes Axis) + public IAxisRates AxisRates(TelescopeAxes axis) { - LogMessage("AxisRates", "Get - " + Axis.ToString()); - return new AxisRates(Axis); + LogMessage("AxisRates", "Get - " + axis.ToString()); + return new AxisRates(axis); } public double Azimuth @@ -673,15 +673,15 @@ namespace ASCOM.Meade.net } } - public bool CanMoveAxis(TelescopeAxes Axis) + public bool CanMoveAxis(TelescopeAxes axis) { - LogMessage("CanMoveAxis", "Get - " + Axis.ToString()); - switch (Axis) + LogMessage("CanMoveAxis", "Get - " + axis.ToString()); + switch (axis) { case TelescopeAxes.axisPrimary: return true; //RA or AZ case TelescopeAxes.axisSecondary: return true; //Dev or Alt case TelescopeAxes.axisTertiary: return false; //rotator / derotator - default: throw new InvalidValueException("CanMoveAxis", Axis.ToString(), "0 to 2"); + default: throw new InvalidValueException("CanMoveAxis", axis.ToString(), "0 to 2"); } } @@ -1538,19 +1538,19 @@ namespace ASCOM.Meade.net } } - private const double INVALID_PARAMETER = -1000; + private const double InvalidParameter = -1000; public void SlewToTargetAsync() { CheckConnected("SlewToTargetAsync"); - if (TargetDeclination == INVALID_PARAMETER || TargetRightAscension == INVALID_PARAMETER) + if (TargetDeclination == InvalidParameter || TargetRightAscension == InvalidParameter) throw new InvalidOperationException("No target selected to slew to."); DoSlewAsync(true); } - private bool movingAxis() + private bool MovingAxis() { return _movingPrimary || _movingSecondary; } @@ -1562,7 +1562,7 @@ namespace ASCOM.Meade.net if (!Connected) return false; - if (movingAxis()) + if (MovingAxis()) return true; CheckConnected("Slewing Get"); @@ -1620,12 +1620,12 @@ namespace ASCOM.Meade.net throw new InvalidOperationException("Unable to perform sync"); } - private double _targetDeclination = INVALID_PARAMETER; + private double _targetDeclination = InvalidParameter; public double TargetDeclination { get { - if (_targetDeclination == INVALID_PARAMETER) + if (_targetDeclination == InvalidParameter) throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gd#", "#"); @@ -1675,12 +1675,12 @@ namespace ASCOM.Meade.net } } - private double _targetRightAscension = INVALID_PARAMETER; + private double _targetRightAscension = InvalidParameter; public double TargetRightAscension { get { - if (_targetRightAscension == INVALID_PARAMETER) + if (_targetRightAscension == InvalidParameter) throw new InvalidOperationException("Target not set"); //var result = SerialPort.CommandTerminated(":Gr#", "#"); @@ -1820,9 +1820,9 @@ namespace ASCOM.Meade.net public class TelescopeDateDetails { - public string telescopeDate { get; set; } - public string telescopeTime { get; set; } - public TimeSpan utcCorrection { get; set; } + public string TelescopeDate { get; set; } + public string TelescopeTime { get; set; } + public TimeSpan UtcCorrection { get; set; } } public DateTime UTCDate @@ -1836,34 +1836,34 @@ namespace ASCOM.Meade.net TelescopeDateDetails telescopeDateDetails = _sharedResourcesWrapper.Lock(() => { TelescopeDateDetails tdd = new TelescopeDateDetails(); - tdd.telescopeDate = _sharedResourcesWrapper.SendString(":GC#"); + tdd.TelescopeDate = _sharedResourcesWrapper.SendString(":GC#"); //:GC# Get current date. //Returns: MM/DD/YY# //The current local calendar date for the telescope. - tdd.telescopeTime = _sharedResourcesWrapper.SendString(":GL#"); + tdd.TelescopeTime = _sharedResourcesWrapper.SendString(":GL#"); //:GL# Get Local Time in 24 hour format //Returns: HH:MM:SS# //The Local Time in 24 - hour Format - tdd.utcCorrection = GetUtcCorrection(); + tdd.UtcCorrection = GetUtcCorrection(); return tdd; }); - int month = telescopeDateDetails.telescopeDate.Substring(0, 2).ToInteger(); - int day = telescopeDateDetails.telescopeDate.Substring(3, 2).ToInteger(); - int year = telescopeDateDetails.telescopeDate.Substring(6, 2).ToInteger(); + int month = telescopeDateDetails.TelescopeDate.Substring(0, 2).ToInteger(); + int day = telescopeDateDetails.TelescopeDate.Substring(3, 2).ToInteger(); + int year = telescopeDateDetails.TelescopeDate.Substring(6, 2).ToInteger(); if (year < 2000) //todo fix this hack that will create a Y2K100 bug { year = year + 2000; } - int hour = telescopeDateDetails.telescopeTime.Substring(0, 2).ToInteger(); - int minute = telescopeDateDetails.telescopeTime.Substring(3, 2).ToInteger(); - int second = telescopeDateDetails.telescopeTime.Substring(6, 2).ToInteger(); + int hour = telescopeDateDetails.TelescopeTime.Substring(0, 2).ToInteger(); + int minute = telescopeDateDetails.TelescopeTime.Substring(3, 2).ToInteger(); + int second = telescopeDateDetails.TelescopeTime.Substring(6, 2).ToInteger(); var utcDate = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc) + - telescopeDateDetails.utcCorrection; + telescopeDateDetails.UtcCorrection; LogMessage("UTCDate", "Get - " + utcDate.ToString("MM/dd/yy HH:mm:ss")); @@ -1934,18 +1934,18 @@ namespace ASCOM.Meade.net /// This is harmless if the driver is already registered/unregistered. /// /// If true, registers the driver, otherwise unregisters it. - private static void RegUnregASCOM(bool bRegister) + private static void RegUnregAscom(bool bRegister) { - using (var P = new Profile()) + using (var p = new Profile()) { - P.DeviceType = "Telescope"; + p.DeviceType = "Telescope"; if (bRegister) { - P.Register(driverID, driverDescription); + p.Register(DriverId, DriverDescription); } else { - P.Unregister(driverID); + p.Unregister(DriverId); } } } @@ -1968,9 +1968,9 @@ namespace ASCOM.Meade.net /// This technique should mean that it is never necessary to manually register a driver with ASCOM. /// [ComRegisterFunction] - public static void RegisterASCOM(Type t) + public static void RegisterAscom(Type t) { - RegUnregASCOM(true); + RegUnregAscom(true); } /// @@ -1991,9 +1991,9 @@ namespace ASCOM.Meade.net /// This technique should mean that it is never necessary to manually unregister a driver from ASCOM. /// [ComUnregisterFunction] - public static void UnregisterASCOM(Type t) + public static void UnregisterAscom(Type t) { - RegUnregASCOM(false); + RegUnregAscom(false); } #endregion @@ -2021,8 +2021,8 @@ namespace ASCOM.Meade.net internal void ReadProfile() { var profileProperties = _sharedResourcesWrapper.ReadProfile(); - tl.Enabled = profileProperties.TraceLogger; - comPort = profileProperties.ComPort; + _tl.Enabled = profileProperties.TraceLogger; + _comPort = profileProperties.ComPort; } /// @@ -2034,7 +2034,7 @@ namespace ASCOM.Meade.net internal void LogMessage(string identifier, string message, params object[] args) { var msg = string.Format(message, args); - tl.LogMessage(identifier, msg); + _tl.LogMessage(identifier, msg); } #endregion } diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index de1c03b..f2dc2ab 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -38,14 +38,14 @@ namespace ASCOM.Meade.net /// The DeviceID is used by ASCOM applications to load the driver at runtime. /// //internal static string driverID = "ASCOM.Meade.net.Focuser"; - internal static string driverID = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + internal static string DriverId = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); // TODO Change the descriptive string for your driver then remove this line /// /// Driver description that displays in the ASCOM Chooser. /// - private static string driverDescription = "Meade Generic"; + private static string _driverDescription = "Meade Generic"; - internal static string comPort; // Variables to hold the currrent device configuration + internal static string ComPort; // Variables to hold the currrent device configuration /// /// Private variable to hold an ASCOM Utilities object @@ -55,7 +55,7 @@ namespace ASCOM.Meade.net /// /// Variable to hold the trace logger object (creates a diagnostic log file with information that you specify) /// - internal static TraceLogger tl; + internal static TraceLogger Tl; private readonly ISharedResourcesWrapper _sharedResourcesWrapper; @@ -74,14 +74,14 @@ namespace ASCOM.Meade.net private void Initialise() { - tl = new TraceLogger("", "Meade.net.focusser"); + Tl = new TraceLogger("", "Meade.net.focusser"); - tl.LogMessage("Focuser", "Starting initialisation"); + Tl.LogMessage("Focuser", "Starting initialisation"); ReadProfile(); // Read device configuration from the ASCOM Profile store IsConnected = false; // Initialise connected to false - tl.LogMessage("Focuser", "Completed initialisation"); + Tl.LogMessage("Focuser", "Completed initialisation"); } @@ -99,17 +99,17 @@ namespace ASCOM.Meade.net /// public void SetupDialog() { - tl.LogMessage("SetupDialog", "Opening setup dialog"); + Tl.LogMessage("SetupDialog", "Opening setup dialog"); _sharedResourcesWrapper.SetupDialog(); ReadProfile(); - tl.LogMessage("SetupDialog", "complete"); + Tl.LogMessage("SetupDialog", "complete"); } public ArrayList SupportedActions { get { - tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); + Tl.LogMessage("SupportedActions Get", "Returning empty arraylist"); return new ArrayList(); } } @@ -155,9 +155,9 @@ namespace ASCOM.Meade.net public void Dispose() { // Clean up the tracelogger and util objects - tl.Enabled = false; - tl.Dispose(); - tl = null; + Tl.Enabled = false; + Tl.Dispose(); + Tl = null; } public bool Connected @@ -169,7 +169,7 @@ namespace ASCOM.Meade.net } set { - tl.LogMessage("Connected", "Set {0}", value); + Tl.LogMessage("Connected", "Set {0}", value); if (value == IsConnected) return; @@ -193,12 +193,12 @@ namespace ASCOM.Meade.net } catch (Exception ex) { - LogMessage("Connected Set", "Error connecting to port {0} - {1}", comPort, ex.Message); + LogMessage("Connected Set", "Error connecting to port {0} - {1}", ComPort, ex.Message); } } else { - LogMessage("Connected Set", "Disconnecting from port {0}", comPort); + LogMessage("Connected Set", "Disconnecting from port {0}", ComPort); _sharedResourcesWrapper.Disconnect("Serial"); IsConnected = false; } @@ -241,8 +241,8 @@ namespace ASCOM.Meade.net // TODO customise this device description get { - tl.LogMessage("Description Get", driverDescription); - return driverDescription; + Tl.LogMessage("Description Get", _driverDescription); + return _driverDescription; } } @@ -253,7 +253,7 @@ namespace ASCOM.Meade.net Version version = Assembly.GetExecutingAssembly().GetName().Version; // TODO customise this driver description string driverInfo = "Information about the driver itself. Version: " + String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverInfo Get", driverInfo); + Tl.LogMessage("DriverInfo Get", driverInfo); return driverInfo; } } @@ -264,7 +264,7 @@ namespace ASCOM.Meade.net { Version version = Assembly.GetExecutingAssembly().GetName().Version; string driverVersion = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version.Major, version.Minor); - tl.LogMessage("DriverVersion Get", driverVersion); + Tl.LogMessage("DriverVersion Get", driverVersion); return driverVersion; } } @@ -284,8 +284,8 @@ namespace ASCOM.Meade.net get { //string name = "Short driver name - please customise"; - string name = driverDescription; - tl.LogMessage("Name Get", name); + string name = _driverDescription; + Tl.LogMessage("Name Get", name); return name; } } @@ -298,14 +298,14 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("Absolute Get", false.ToString()); + Tl.LogMessage("Absolute Get", false.ToString()); return false; // This is a relative focuser } } public void Halt() { - tl.LogMessage("Halt", "Halting"); + Tl.LogMessage("Halt", "Halting"); CheckConnected("Halt"); @@ -325,7 +325,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("IsMoving Get", false.ToString()); + Tl.LogMessage("IsMoving Get", false.ToString()); return false; // This focuser always moves instantaneously so no need for IsMoving ever to be True } } @@ -334,12 +334,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("Link Get", Connected.ToString()); + Tl.LogMessage("Link Get", Connected.ToString()); return Connected; // Direct function to the connected method, the Link method is just here for backwards compatibility } set { - tl.LogMessage("Link Set", value.ToString()); + Tl.LogMessage("Link Set", value.ToString()); Connected = value; // Direct function to the connected method, the Link method is just here for backwards compatibility } } @@ -349,7 +349,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("MaxIncrement Get", _maxIncrement.ToString()); + Tl.LogMessage("MaxIncrement Get", _maxIncrement.ToString()); return _maxIncrement; // Maximum change in one move } } @@ -359,37 +359,37 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("MaxStep Get", _maxStep.ToString()); + Tl.LogMessage("MaxStep Get", _maxStep.ToString()); return _maxStep; } } - public void Move(int Position) + public void Move(int position) { - tl.LogMessage("Move", Position.ToString()); + Tl.LogMessage("Move", position.ToString()); CheckConnected("Move"); //todo implement backlash compensation //todo implement direction reverse //todo implement dynamic braking - if (Position < -MaxIncrement || Position > MaxIncrement) + if (position < -MaxIncrement || position > MaxIncrement) { - throw new InvalidValueException($"position out of range {-MaxIncrement} < {Position} < {MaxIncrement}"); + throw new InvalidValueException($"position out of range {-MaxIncrement} < {position} < {MaxIncrement}"); } - if (Position == 0) + if (position == 0) return; - if (Position > 0) + if (position > 0) { //desired move direction is out - MoveFocuser(true, Math.Abs(Position)); + MoveFocuser(true, Math.Abs(position)); } else { //desired move direction is in - MoveFocuser(false, Math.Abs(Position)); + MoveFocuser(false, Math.Abs(position)); } } @@ -436,7 +436,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("StepSize Get", "Not implemented"); + Tl.LogMessage("StepSize Get", "Not implemented"); throw new PropertyNotImplementedException("StepSize", false); } } @@ -445,12 +445,12 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("TempComp Get", false.ToString()); + Tl.LogMessage("TempComp Get", false.ToString()); return false; } set { - tl.LogMessage("TempComp Set", "Not implemented"); + Tl.LogMessage("TempComp Set", "Not implemented"); throw new PropertyNotImplementedException("TempComp", false); } } @@ -459,7 +459,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("TempCompAvailable Get", false.ToString()); + Tl.LogMessage("TempCompAvailable Get", false.ToString()); return false; // Temperature compensation is not available in this driver } } @@ -468,7 +468,7 @@ namespace ASCOM.Meade.net { get { - tl.LogMessage("Temperature Get", "Not implemented"); + Tl.LogMessage("Temperature Get", "Not implemented"); throw new PropertyNotImplementedException("Temperature", false); } } @@ -489,18 +489,18 @@ namespace ASCOM.Meade.net /// This is harmless if the driver is already registered/unregistered. /// /// If true, registers the driver, otherwise unregisters it. - private static void RegUnregASCOM(bool bRegister) + private static void RegUnregAscom(bool bRegister) { - using (var P = new Profile()) + using (var p = new Profile()) { - P.DeviceType = "Focuser"; + p.DeviceType = "Focuser"; if (bRegister) { - P.Register(driverID, driverDescription); + p.Register(DriverId, _driverDescription); } else { - P.Unregister(driverID); + p.Unregister(DriverId); } } } @@ -523,9 +523,9 @@ namespace ASCOM.Meade.net /// This technique should mean that it is never necessary to manually register a driver with ASCOM. /// [ComRegisterFunction] - public static void RegisterASCOM(Type t) + public static void RegisterAscom(Type t) { - RegUnregASCOM(true); + RegUnregAscom(true); } /// @@ -546,9 +546,9 @@ namespace ASCOM.Meade.net /// This technique should mean that it is never necessary to manually unregister a driver from ASCOM. /// [ComUnregisterFunction] - public static void UnregisterASCOM(Type t) + public static void UnregisterAscom(Type t) { - RegUnregASCOM(false); + RegUnregAscom(false); } #endregion @@ -576,8 +576,8 @@ namespace ASCOM.Meade.net internal void ReadProfile() { var profileProperties = _sharedResourcesWrapper.ReadProfile(); - tl.Enabled = profileProperties.TraceLogger; - comPort = profileProperties.ComPort; + Tl.Enabled = profileProperties.TraceLogger; + ComPort = profileProperties.ComPort; } /// @@ -589,7 +589,7 @@ namespace ASCOM.Meade.net internal static void LogMessage(string identifier, string message, params object[] args) { var msg = string.Format(message, args); - tl.LogMessage(identifier, msg); + Tl.LogMessage(identifier, msg); } #endregion } diff --git a/Meade.net/ClassFactory.cs b/Meade.net/ClassFactory.cs index 7b61d4f..1f5c265 100644 --- a/Meade.net/ClassFactory.cs +++ b/Meade.net/ClassFactory.cs @@ -33,43 +33,43 @@ namespace ASCOM.Meade.net #region Access to ole32.dll functions for class factories // Define two common GUID objects for public usage. - public static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); - public static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); + public static Guid IidIUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); + public static Guid IidIDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); [Flags] - enum CLSCTX : uint + enum Clsctx : uint { - CLSCTX_INPROC_SERVER = 0x1, - CLSCTX_INPROC_HANDLER = 0x2, - CLSCTX_LOCAL_SERVER = 0x4, - CLSCTX_INPROC_SERVER16 = 0x8, - CLSCTX_REMOTE_SERVER = 0x10, - CLSCTX_INPROC_HANDLER16 = 0x20, - CLSCTX_RESERVED1 = 0x40, - CLSCTX_RESERVED2 = 0x80, - CLSCTX_RESERVED3 = 0x100, - CLSCTX_RESERVED4 = 0x200, - CLSCTX_NO_CODE_DOWNLOAD = 0x400, - CLSCTX_RESERVED5 = 0x800, - CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, - CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, - CLSCTX_NO_FAILURE_LOG = 0x4000, - CLSCTX_DISABLE_AAA = 0x8000, - CLSCTX_ENABLE_AAA = 0x10000, - CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, - CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, - CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, - CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER + ClsctxInprocServer = 0x1, + ClsctxInprocHandler = 0x2, + ClsctxLocalServer = 0x4, + ClsctxInprocServer16 = 0x8, + ClsctxRemoteServer = 0x10, + ClsctxInprocHandler16 = 0x20, + ClsctxReserved1 = 0x40, + ClsctxReserved2 = 0x80, + ClsctxReserved3 = 0x100, + ClsctxReserved4 = 0x200, + ClsctxNoCodeDownload = 0x400, + ClsctxReserved5 = 0x800, + ClsctxNoCustomMarshal = 0x1000, + ClsctxEnableCodeDownload = 0x2000, + ClsctxNoFailureLog = 0x4000, + ClsctxDisableAaa = 0x8000, + ClsctxEnableAaa = 0x10000, + ClsctxFromDefaultContext = 0x20000, + ClsctxInproc = ClsctxInprocServer | ClsctxInprocHandler, + ClsctxServer = ClsctxInprocServer | ClsctxLocalServer | ClsctxRemoteServer, + ClsctxAll = ClsctxServer | ClsctxInprocHandler } [Flags] - enum REGCLS : uint + enum Regcls : uint { - REGCLS_SINGLEUSE = 0, - REGCLS_MULTIPLEUSE = 1, - REGCLS_MULTI_SEPARATE = 2, - REGCLS_SUSPENDED = 4, - REGCLS_SURROGATE = 8 + RegclsSingleuse = 0, + RegclsMultipleuse = 1, + RegclsMultiSeparate = 2, + RegclsSuspended = 4, + RegclsSurrogate = 8 } // // CoRegisterClassObject() is used to register a Class Factory @@ -109,30 +109,30 @@ namespace ASCOM.Meade.net #region Constructor and Private ClassFactory Data - protected readonly Type m_ClassType; - protected Guid m_ClassId; - protected readonly ArrayList m_InterfaceTypes; - protected uint m_ClassContext; - protected uint m_Flags; - protected UInt32 m_locked = 0; - protected uint m_Cookie; - protected string m_progid; + protected readonly Type MClassType; + protected Guid MClassId; + protected readonly ArrayList MInterfaceTypes; + protected uint MClassContext; + protected uint MFlags; + protected UInt32 MLocked = 0; + protected uint MCookie; + protected string MProgid; public ClassFactory(Type type) { if (type == null) throw new ArgumentNullException("type"); - m_ClassType = type; + MClassType = type; //PWGS Get the ProgID from the MetaData - m_progid = Marshal.GenerateProgIdForType(type); - m_ClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)] - m_ClassContext = (uint)CLSCTX.CLSCTX_LOCAL_SERVER; // Default - m_Flags = (uint)REGCLS.REGCLS_MULTIPLEUSE | // Default - (uint)REGCLS.REGCLS_SUSPENDED; - m_InterfaceTypes = new ArrayList(); + MProgid = Marshal.GenerateProgIdForType(type); + MClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)] + MClassContext = (uint)Clsctx.ClsctxLocalServer; // Default + MFlags = (uint)Regcls.RegclsMultipleuse | // Default + (uint)Regcls.RegclsSuspended; + MInterfaceTypes = new ArrayList(); foreach (Type T in type.GetInterfaces()) // Save all of the implemented interfaces - m_InterfaceTypes.Add(T); + MInterfaceTypes.Add(T); } #endregion @@ -140,20 +140,20 @@ namespace ASCOM.Meade.net #region Common ClassFactory Methods public uint ClassContext { - get => m_ClassContext; - set => m_ClassContext = value; + get => MClassContext; + set => MClassContext = value; } public Guid ClassId { - get => m_ClassId; - set => m_ClassId = value; + get => MClassId; + set => MClassId = value; } public uint Flags { - get => m_Flags; - set => m_Flags = value; + get => MFlags; + set => MFlags = value; } public bool RegisterClassObject() @@ -161,18 +161,18 @@ namespace ASCOM.Meade.net // Register the class factory int i = CoRegisterClassObject ( - ref m_ClassId, + ref MClassId, this, - m_ClassContext, - m_Flags, - out m_Cookie + MClassContext, + MFlags, + out MCookie ); return (i == 0); } public bool RevokeClassObject() { - int i = CoRevokeClassObject(m_Cookie); + int i = CoRevokeClassObject(MCookie); return (i == 0); } @@ -201,25 +201,25 @@ namespace ASCOM.Meade.net // // Handle specific requests for implemented interfaces // - foreach (Type iType in m_InterfaceTypes) + foreach (Type iType in MInterfaceTypes) { if (riid == Marshal.GenerateGuidForType(iType)) { - ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(m_ClassType), iType); + ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(MClassType), iType); return; } } // // Handle requests for IDispatch or IUnknown on the class // - if (riid == IID_IDispatch) + if (riid == IidIDispatch) { - ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(m_ClassType)); + ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(MClassType)); return; } - else if (riid == IID_IUnknown) + else if (riid == IidIUnknown) { - ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(m_ClassType)); + ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(MClassType)); } else { diff --git a/Meade.net/GarbageCollection.cs b/Meade.net/GarbageCollection.cs index 99aba52..714af79 100644 --- a/Meade.net/GarbageCollection.cs +++ b/Meade.net/GarbageCollection.cs @@ -8,35 +8,35 @@ namespace ASCOM.Meade.net /// class GarbageCollection { - protected bool m_bContinueThread; - protected bool m_GCWatchStopped; - protected int m_iInterval; - protected ManualResetEvent m_EventThreadEnded; + protected bool MBContinueThread; + protected bool MGcWatchStopped; + protected int MIInterval; + protected ManualResetEvent MEventThreadEnded; public GarbageCollection(int iInterval) { - m_bContinueThread = true; - m_GCWatchStopped = false; - m_iInterval = iInterval; - m_EventThreadEnded = new ManualResetEvent(false); + MBContinueThread = true; + MGcWatchStopped = false; + MIInterval = iInterval; + MEventThreadEnded = new ManualResetEvent(false); } - public void GCWatch() + public void GcWatch() { // Pause for a moment to provide a delay to make threads more apparent. while (ContinueThread()) { GC.Collect(); - Thread.Sleep(m_iInterval); + Thread.Sleep(MIInterval); } - m_EventThreadEnded.Set(); + MEventThreadEnded.Set(); } protected bool ContinueThread() { lock (this) { - return m_bContinueThread; + return MBContinueThread; } } @@ -44,14 +44,14 @@ namespace ASCOM.Meade.net { lock (this) { - m_bContinueThread = false; + MBContinueThread = false; } } public void WaitForThreadToStop() { - m_EventThreadEnded.WaitOne(); - m_EventThreadEnded.Reset(); + MEventThreadEnded.WaitOne(); + MEventThreadEnded.Reset(); } } } diff --git a/Meade.net/LocalServer.cs b/Meade.net/LocalServer.cs index 8bbee9e..ddafa39 100644 --- a/Meade.net/LocalServer.cs +++ b/Meade.net/LocalServer.cs @@ -31,52 +31,52 @@ namespace ASCOM.Meade.net #region Access to kernel32.dll, user32.dll, and ole32.dll functions [Flags] - enum CLSCTX : uint + enum Clsctx : uint { - CLSCTX_INPROC_SERVER = 0x1, - CLSCTX_INPROC_HANDLER = 0x2, - CLSCTX_LOCAL_SERVER = 0x4, - CLSCTX_INPROC_SERVER16 = 0x8, - CLSCTX_REMOTE_SERVER = 0x10, - CLSCTX_INPROC_HANDLER16 = 0x20, - CLSCTX_RESERVED1 = 0x40, - CLSCTX_RESERVED2 = 0x80, - CLSCTX_RESERVED3 = 0x100, - CLSCTX_RESERVED4 = 0x200, - CLSCTX_NO_CODE_DOWNLOAD = 0x400, - CLSCTX_RESERVED5 = 0x800, - CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, - CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, - CLSCTX_NO_FAILURE_LOG = 0x4000, - CLSCTX_DISABLE_AAA = 0x8000, - CLSCTX_ENABLE_AAA = 0x10000, - CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, - CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, - CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, - CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER + ClsctxInprocServer = 0x1, + ClsctxInprocHandler = 0x2, + ClsctxLocalServer = 0x4, + ClsctxInprocServer16 = 0x8, + ClsctxRemoteServer = 0x10, + ClsctxInprocHandler16 = 0x20, + ClsctxReserved1 = 0x40, + ClsctxReserved2 = 0x80, + ClsctxReserved3 = 0x100, + ClsctxReserved4 = 0x200, + ClsctxNoCodeDownload = 0x400, + ClsctxReserved5 = 0x800, + ClsctxNoCustomMarshal = 0x1000, + ClsctxEnableCodeDownload = 0x2000, + ClsctxNoFailureLog = 0x4000, + ClsctxDisableAaa = 0x8000, + ClsctxEnableAaa = 0x10000, + ClsctxFromDefaultContext = 0x20000, + ClsctxInproc = ClsctxInprocServer | ClsctxInprocHandler, + ClsctxServer = ClsctxInprocServer | ClsctxLocalServer | ClsctxRemoteServer, + ClsctxAll = ClsctxServer | ClsctxInprocHandler } [Flags] - enum COINIT : uint + enum Coinit : uint { /// Initializes the thread for multi-threaded object concurrency. - COINIT_MULTITHREADED = 0x0, + CoinitMultithreaded = 0x0, /// Initializes the thread for apartment-threaded object concurrency. - COINIT_APARTMENTTHREADED = 0x2, + CoinitApartmentthreaded = 0x2, /// Disables DDE for Ole1 support. - COINIT_DISABLE_OLE1DDE = 0x4, + CoinitDisableOle1Dde = 0x4, /// Trades memory for speed. - COINIT_SPEED_OVER_MEMORY = 0x8 + CoinitSpeedOverMemory = 0x8 } [Flags] - enum REGCLS : uint + enum Regcls : uint { - REGCLS_SINGLEUSE = 0, - REGCLS_MULTIPLEUSE = 1, - REGCLS_MULTI_SEPARATE = 2, - REGCLS_SUSPENDED = 4, - REGCLS_SURROGATE = 8 + RegclsSingleuse = 0, + RegclsMultipleuse = 1, + RegclsMultiSeparate = 2, + RegclsSuspended = 4, + RegclsSurrogate = 8 } @@ -94,7 +94,7 @@ namespace ASCOM.Meade.net // We will need this API to post a WM_QUIT message to the main // thread in order to terminate this application. [DllImport("user32.dll")] - static extern bool PostThreadMessage(uint idThread, uint Msg, UIntPtr wParam, + static extern bool PostThreadMessage(uint idThread, uint msg, UIntPtr wParam, IntPtr lParam); // GetCurrentThreadId() allows us to obtain the thread id of the @@ -105,21 +105,21 @@ namespace ASCOM.Meade.net #endregion #region Private Data - private static int objsInUse; // Keeps a count on the total number of objects alive. - private static int serverLocks; // Keeps a lock count on this application. - private static frmMain s_MainForm = null; // Reference to our main form - private static ArrayList s_ComObjectAssys; // Dynamically loaded assemblies containing served COM objects - private static ArrayList s_ComObjectTypes; // Served COM object types - private static ArrayList s_ClassFactories; // Served COM object class factories - private static string s_appId = "{4e68ec46-5ffc-49e7-b298-38a548df0bfd}"; // Our AppId - private static readonly Object lockObject = new object(); + private static int _objsInUse; // Keeps a count on the total number of objects alive. + private static int _serverLocks; // Keeps a lock count on this application. + private static FrmMain _sMainForm = null; // Reference to our main form + private static ArrayList _sComObjectAssys; // Dynamically loaded assemblies containing served COM objects + private static ArrayList _sComObjectTypes; // Served COM object types + private static ArrayList _sClassFactories; // Served COM object class factories + private static string _sAppId = "{4e68ec46-5ffc-49e7-b298-38a548df0bfd}"; // Our AppId + private static readonly Object LockObject = new object(); #endregion // This property returns the main thread's id. public static uint MainThreadId { get; private set; } // Stores the main thread's thread id. // Used to tell if started by COM or manually - public static bool StartedByCOM { get; private set; } // True if server started by COM (-embedding) + public static bool StartedByCom { get; private set; } // True if server started by COM (-embedding) #region Server Lock, Object Counting, and AutoQuit on COM startup @@ -128,9 +128,9 @@ namespace ASCOM.Meade.net { get { - lock (lockObject) + lock (LockObject) { - return objsInUse; + return _objsInUse; } } } @@ -139,14 +139,14 @@ namespace ASCOM.Meade.net public static int CountObject() { // Increment the global count of objects. - return Interlocked.Increment(ref objsInUse); + return Interlocked.Increment(ref _objsInUse); } // This method performs a thread-safe decrementation the objects count. public static int UncountObject() { // Decrement the global count of objects. - return Interlocked.Decrement(ref objsInUse); + return Interlocked.Decrement(ref _objsInUse); } // Returns the current server lock count. @@ -154,9 +154,9 @@ namespace ASCOM.Meade.net { get { - lock (lockObject) + lock (LockObject) { - return serverLocks; + return _serverLocks; } } } @@ -166,7 +166,7 @@ namespace ASCOM.Meade.net public static int CountLock() { // Increment the global lock count of this server. - return Interlocked.Increment(ref serverLocks); + return Interlocked.Increment(ref _serverLocks); } // This method performs a thread-safe decrementation the @@ -174,7 +174,7 @@ namespace ASCOM.Meade.net public static int UncountLock() { // Decrement the global lock count of this server. - return Interlocked.Decrement(ref serverLocks); + return Interlocked.Decrement(ref _serverLocks); } // AttemptToTerminateServer() will check to see if the objects count and the server @@ -186,11 +186,11 @@ namespace ASCOM.Meade.net // public static void ExitIf() { - lock (lockObject) + lock (LockObject) { if ((ObjectsCount <= 0) && (ServerLockCount <= 0)) { - if (StartedByCOM) + if (StartedByCom) { UIntPtr wParam = new UIntPtr(0); IntPtr lParam = new IntPtr(0); @@ -213,8 +213,8 @@ namespace ASCOM.Meade.net // private static bool LoadComObjectAssemblies() { - s_ComObjectAssys = new ArrayList(); - s_ComObjectTypes = new ArrayList(); + _sComObjectAssys = new ArrayList(); + _sComObjectTypes = new ArrayList(); // put everything into one folder, the same as the server. string assyPath = Assembly.GetEntryAssembly().Location; @@ -243,8 +243,8 @@ namespace ASCOM.Meade.net if (attrbutes.Length > 0) { //MessageBox.Show("Adding Type: " + type.Name + " " + type.FullName); - s_ComObjectTypes.Add(type); //PWGS - much simpler - s_ComObjectAssys.Add(so); + _sComObjectTypes.Add(type); //PWGS - much simpler + _sComObjectAssys.Add(so); } } } @@ -339,10 +339,10 @@ namespace ASCOM.Meade.net // // HKCR\APPID\appid // - using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("APPID\\" + s_appId)) + using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("APPID\\" + _sAppId)) { key.SetValue(null, assyDescription); - key.SetValue("AppID", s_appId); + key.SetValue("AppID", _sAppId); key.SetValue("AuthenticationLevel", 1, RegistryValueKind.DWord); } // @@ -351,7 +351,7 @@ namespace ASCOM.Meade.net using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("APPID\\{0}", Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1)))) { - key.SetValue("AppID", s_appId); + key.SetValue("AppID", _sAppId); } } catch (Exception ex) @@ -367,7 +367,7 @@ namespace ASCOM.Meade.net // // For each of the driver assemblies // - foreach (Type type in s_ComObjectTypes) + foreach (Type type in _sComObjectTypes) { bool bFail = false; try @@ -383,7 +383,7 @@ namespace ASCOM.Meade.net using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("CLSID\\{0}", clsid))) { key.SetValue(null, progid); // Could be assyTitle/Desc??, but .NET components show ProgId here - key.SetValue("AppId", s_appId); + key.SetValue("AppId", _sAppId); using (RegistryKey key2 = key.CreateSubKey("Implemented Categories")) { key2.CreateSubKey("{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"); @@ -417,10 +417,10 @@ namespace ASCOM.Meade.net // Pull the display name from the ServedClassName attribute. attr = Attribute.GetCustomAttribute(type, typeof(ServedClassNameAttribute)); //PWGS Changed to search type for attribute rather than assembly string chooserName = ((ServedClassNameAttribute)attr).DisplayName ?? "MultiServer"; - using (var P = new Profile()) + using (var p = new Profile()) { - P.DeviceType = deviceType; - P.Register(progid, chooserName); + p.DeviceType = deviceType; + p.Register(progid, chooserName); } } catch (Exception ex) @@ -453,14 +453,14 @@ namespace ASCOM.Meade.net // // Local server's DCOM/AppID information // - Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", s_appId), false); + Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", _sAppId), false); Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1)), false); // // For each of the driver assemblies // - foreach (Type type in s_ComObjectTypes) + foreach (Type type in _sComObjectTypes) { string clsid = Marshal.GenerateGuidForType(type).ToString("B"); string progid = Marshal.GenerateProgIdForType(type); @@ -487,10 +487,10 @@ namespace ASCOM.Meade.net // // ASCOM // - using (var P = new Profile()) + using (var p = new Profile()) { - P.DeviceType = deviceType; - P.Unregister(progid); + p.DeviceType = deviceType; + p.Unregister(progid); } } catch (Exception) { } @@ -506,11 +506,11 @@ namespace ASCOM.Meade.net // private static bool RegisterClassFactories() { - s_ClassFactories = new ArrayList(); - foreach (Type type in s_ComObjectTypes) + _sClassFactories = new ArrayList(); + foreach (Type type in _sComObjectTypes) { ClassFactory factory = new ClassFactory(type); // Use default context & flags - s_ClassFactories.Add(factory); + _sClassFactories.Add(factory); if (!factory.RegisterClassObject()) { MessageBox.Show("Failed to register class factory for " + type.Name, @@ -525,7 +525,7 @@ namespace ASCOM.Meade.net private static void RevokeClassFactories() { ClassFactory.SuspendClassObjects(); // Prevent race conditions - foreach (ClassFactory factory in s_ClassFactories) + foreach (ClassFactory factory in _sClassFactories) factory.RevokeClassObject(); } #endregion @@ -549,7 +549,7 @@ namespace ASCOM.Meade.net switch (args[0].ToLower()) { case "-embedding": - StartedByCOM = true; // Indicate COM started us + StartedByCom = true; // Indicate COM started us break; case "-register": @@ -575,7 +575,7 @@ namespace ASCOM.Meade.net } } else - StartedByCOM = false; + StartedByCom = false; return bRet; } @@ -595,24 +595,24 @@ namespace ASCOM.Meade.net if (!ProcessArguments(args)) return; // Register/Unregister // Initialize critical member variables. - objsInUse = 0; - serverLocks = 0; + _objsInUse = 0; + _serverLocks = 0; MainThreadId = GetCurrentThreadId(); Thread.CurrentThread.Name = "Main Thread"; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - s_MainForm = new frmMain(); - if (StartedByCOM) s_MainForm.WindowState = FormWindowState.Minimized; + _sMainForm = new FrmMain(); + if (StartedByCom) _sMainForm.WindowState = FormWindowState.Minimized; // Register the class factories of the served objects RegisterClassFactories(); // Start up the garbage collection thread. - GarbageCollection GarbageCollector = new GarbageCollection(1000); - Thread GCThread = new Thread(new ThreadStart(GarbageCollector.GCWatch)); - GCThread.Name = "Garbage Collection Thread"; - GCThread.Start(); + GarbageCollection garbageCollector = new GarbageCollection(1000); + Thread gcThread = new Thread(new ThreadStart(garbageCollector.GcWatch)); + gcThread.Name = "Garbage Collection Thread"; + gcThread.Start(); // // Start the message loop. This serializes incoming calls to our @@ -620,7 +620,7 @@ namespace ASCOM.Meade.net // try { - Application.Run(s_MainForm); + Application.Run(_sMainForm); } finally { @@ -630,8 +630,8 @@ namespace ASCOM.Meade.net RevokeClassFactories(); // Now stop the Garbage Collector thread. - GarbageCollector.StopThread(); - GarbageCollector.WaitForThreadToStop(); + garbageCollector.StopThread(); + garbageCollector.WaitForThreadToStop(); } } #endregion diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 1d5a709..d42147e 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -30,10 +30,10 @@ namespace ASCOM.Meade.net public static class SharedResources { // object used for locking to prevent multiple drivers accessing common code at the same time - private static readonly object lockObject = new object(); + private static readonly object LockObject = new object(); // Shared serial port. This will allow multiple drivers to use one single serial port. - private static Serial s_sharedSerial; // Shared serial port + private static Serial _sSharedSerial; // Shared serial port // // Public access to shared resources @@ -58,7 +58,7 @@ namespace ASCOM.Meade.net /// /// Shared serial port /// - public static Serial SharedSerial => s_sharedSerial ?? (s_sharedSerial = new Serial()); + public static Serial SharedSerial => _sSharedSerial ?? (_sSharedSerial = new Serial()); /// /// number of connections to the shared serial port @@ -67,7 +67,7 @@ namespace ASCOM.Meade.net public static void SendBlind(string message) { - lock (lockObject) + lock (LockObject) { SharedSerial.ClearBuffers(); SharedSerial.Transmit(message); @@ -90,7 +90,7 @@ namespace ASCOM.Meade.net /// public static string SendString(string message) { - lock (lockObject) + lock (LockObject) { SharedSerial.ClearBuffers(); SharedSerial.Transmit(message); @@ -100,7 +100,7 @@ namespace ASCOM.Meade.net public static string SendChar(string message) { - lock (lockObject) + lock (LockObject) { SharedSerial.ClearBuffers(); SharedSerial.Transmit(message); @@ -110,7 +110,7 @@ namespace ASCOM.Meade.net public static string ReadTerminated() { - lock (lockObject) + lock (LockObject) { return SharedSerial.ReceiveTerminated("#"); } @@ -128,7 +128,7 @@ namespace ASCOM.Meade.net { set { - lock (lockObject) + lock (LockObject) { if (value) { @@ -153,40 +153,40 @@ namespace ASCOM.Meade.net #region Profile - internal static string driverID = "ASCOM.MeadeGeneric.Telescope"; + internal static string DriverId = "ASCOM.MeadeGeneric.Telescope"; // Constants used for Profile persistence - internal static string comPortProfileName = "COM Port"; - internal static string traceStateProfileName = "Trace Level"; + internal static string ComPortProfileName = "COM Port"; + internal static string TraceStateProfileName = "Trace Level"; public static void WriteProfile(ProfileProperties profileProperties) { - lock (lockObject) + lock (LockObject) { using (Profile driverProfile = new Profile()) { driverProfile.DeviceType = "Telescope"; - driverProfile.WriteValue(driverID, traceStateProfileName, profileProperties.TraceLogger.ToString()); - driverProfile.WriteValue(driverID, comPortProfileName, profileProperties.ComPort); + driverProfile.WriteValue(DriverId, TraceStateProfileName, profileProperties.TraceLogger.ToString()); + driverProfile.WriteValue(DriverId, ComPortProfileName, profileProperties.ComPort); } } } - private static readonly string comPortDefault = "COM1"; - internal static string traceStateDefault = "false"; + private static readonly string ComPortDefault = "COM1"; + internal static string TraceStateDefault = "false"; public static ProfileProperties ReadProfile() { - lock (lockObject) + lock (LockObject) { ProfileProperties profileProperties = new ProfileProperties(); using (Profile driverProfile = new Profile()) { driverProfile.DeviceType = "Telescope"; profileProperties.ComPort = - driverProfile.GetValue(driverID, comPortProfileName, string.Empty, comPortDefault); - profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(driverID, - traceStateProfileName, string.Empty, traceStateDefault)); + driverProfile.GetValue(DriverId, ComPortProfileName, string.Empty, ComPortDefault); + profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(DriverId, + TraceStateProfileName, string.Empty, TraceStateDefault)); } return profileProperties; @@ -209,14 +209,14 @@ namespace ASCOM.Meade.net var profileProperties = ReadProfile(); - using (SetupDialogForm F = new SetupDialogForm()) + using (SetupDialogForm f = new SetupDialogForm()) { - F.SetProfile(profileProperties); + f.SetProfile(profileProperties); - var result = F.ShowDialog(); + var result = f.ShowDialog(); if (result == System.Windows.Forms.DialogResult.OK) { - profileProperties = F.GetProfile(); + profileProperties = f.GetProfile(); WriteProfile(profileProperties); // Persist device configuration values to the ASCOM Profile store } @@ -244,7 +244,7 @@ namespace ASCOM.Meade.net /// The Key is the connection number that identifies the device, it could be the COM port name, /// USB ID or IP Address, the Value is the DeviceHardware class /// - private static Dictionary connectedDevices = new Dictionary(); + private static Dictionary _connectedDevices = new Dictionary(); /// /// This is called in the driver Connect(true) property, @@ -253,15 +253,15 @@ namespace ASCOM.Meade.net /// public static void Connect(string deviceId) { - lock (lockObject) + lock (LockObject) { - if (!connectedDevices.ContainsKey(deviceId)) - connectedDevices.Add(deviceId, new DeviceHardware()); - connectedDevices[deviceId].count++; // increment the value + if (!_connectedDevices.ContainsKey(deviceId)) + _connectedDevices.Add(deviceId, new DeviceHardware()); + _connectedDevices[deviceId].Count++; // increment the value if (deviceId == "Serial") { - if (connectedDevices[deviceId].count == 1) + if (_connectedDevices[deviceId].Count == 1) { var profileProperties = ReadProfile(); SharedSerial.PortName = profileProperties.ComPort; @@ -283,14 +283,14 @@ namespace ASCOM.Meade.net public static void Disconnect(string deviceId) { - lock (lockObject) + lock (LockObject) { - if (connectedDevices.ContainsKey(deviceId)) + if (_connectedDevices.ContainsKey(deviceId)) { - connectedDevices[deviceId].count--; - if (connectedDevices[deviceId].count <= 0) + _connectedDevices[deviceId].Count--; + if (_connectedDevices[deviceId].Count <= 0) { - connectedDevices.Remove(deviceId); + _connectedDevices.Remove(deviceId); if (deviceId == "Serial") { SharedSerial.Connected = false; @@ -302,8 +302,8 @@ namespace ASCOM.Meade.net public static bool IsConnected(string deviceId) { - if (connectedDevices.ContainsKey(deviceId)) - return (connectedDevices[deviceId].count > 0); + if (_connectedDevices.ContainsKey(deviceId)) + return (_connectedDevices[deviceId].Count > 0); else return false; } @@ -312,7 +312,7 @@ namespace ASCOM.Meade.net public static void Lock(Action action) { - lock (lockObject) + lock (LockObject) { action(); } @@ -320,7 +320,7 @@ namespace ASCOM.Meade.net public static T Lock(Func func) { - lock (lockObject) + lock (LockObject) { return func(); } @@ -334,7 +334,7 @@ namespace ASCOM.Meade.net { private int _count; - internal int count + internal int Count { set => _count = value; get => _count; @@ -342,7 +342,7 @@ namespace ASCOM.Meade.net internal DeviceHardware() { - count = 0; + Count = 0; } } diff --git a/Meade.net/Wrapper/SharedResourcesWrapper.cs b/Meade.net/Wrapper/SharedResourcesWrapper.cs index cbfa0d3..c49454c 100644 --- a/Meade.net/Wrapper/SharedResourcesWrapper.cs +++ b/Meade.net/Wrapper/SharedResourcesWrapper.cs @@ -4,10 +4,10 @@ namespace ASCOM.Meade.net.Wrapper { public interface ISharedResourcesWrapper { - string AUTOSTAR497 { get; } - string AUTOSTAR497_31EE { get; } + string Autostar497 { get; } + string Autostar49731Ee { get; } - string AUTOSTAR497_43EG { get;} + string Autostar49743Eg { get;} void Connect(string deviceId); void Disconnect(string deviceId); @@ -34,10 +34,10 @@ namespace ASCOM.Meade.net.Wrapper { #region AutostarProducts - public string AUTOSTAR497 => "Autostar"; + public string Autostar497 => "Autostar"; - public string AUTOSTAR497_31EE => "31Ee"; - public string AUTOSTAR497_43EG => "43Eg"; + public string Autostar49731Ee => "31Ee"; + public string Autostar49743Eg => "43Eg"; #endregion diff --git a/Meade.net/frmMain.Designer.cs b/Meade.net/frmMain.Designer.cs index 83c8dd1..e8bef51 100644 --- a/Meade.net/frmMain.Designer.cs +++ b/Meade.net/frmMain.Designer.cs @@ -2,7 +2,7 @@ using System; namespace ASCOM.Meade.net { - partial class frmMain + partial class FrmMain { /// /// Required designer variable. @@ -48,7 +48,7 @@ namespace ASCOM.Meade.net this.ClientSize = new System.Drawing.Size(233, 52); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "frmMain"; + this.Name = "FrmMain"; this.Text = "Meade.net Driver Server"; this.ResumeLayout(false); diff --git a/Meade.net/frmMain.cs b/Meade.net/frmMain.cs index 7ac44b7..2ae5c27 100644 --- a/Meade.net/frmMain.cs +++ b/Meade.net/frmMain.cs @@ -2,11 +2,11 @@ using System.Windows.Forms; namespace ASCOM.Meade.net { - public partial class frmMain : Form + public partial class FrmMain : Form { delegate void SetTextCallback(string text); - public frmMain() + public FrmMain() { InitializeComponent(); } From 0e98f0e3709a92b999586ba3896433a399a54110 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 14:33:41 +0100 Subject: [PATCH 107/109] Code inspections --- Meade.net.Telescope/Rates.cs | 2 +- Meade.net.focuser/Focuser.cs | 20 +++++----- Meade.net/ClassFactory.cs | 70 +++++++++++++++------------------- Meade.net/GarbageCollection.cs | 28 +++++++------- Meade.net/SharedResources.cs | 10 ++--- 5 files changed, 60 insertions(+), 70 deletions(-) diff --git a/Meade.net.Telescope/Rates.cs b/Meade.net.Telescope/Rates.cs index 8d9e970..b3f6f22 100644 --- a/Meade.net.Telescope/Rates.cs +++ b/Meade.net.Telescope/Rates.cs @@ -79,7 +79,7 @@ namespace ASCOM.Meade.net // internal AxisRates(TelescopeAxes axis) { - this._axis = axis; + _axis = axis; // // This collection must hold zero or more Rate objects describing the // rates of motion ranges for the Telescope.MoveAxis() method diff --git a/Meade.net.focuser/Focuser.cs b/Meade.net.focuser/Focuser.cs index f2dc2ab..bf3a891 100644 --- a/Meade.net.focuser/Focuser.cs +++ b/Meade.net.focuser/Focuser.cs @@ -38,14 +38,14 @@ namespace ASCOM.Meade.net /// The DeviceID is used by ASCOM applications to load the driver at runtime. /// //internal static string driverID = "ASCOM.Meade.net.Focuser"; - internal static string DriverId = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string DriverId = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType); // TODO Change the descriptive string for your driver then remove this line /// /// Driver description that displays in the ASCOM Chooser. /// - private static string _driverDescription = "Meade Generic"; + private static readonly string DriverDescription = "Meade Generic"; - internal static string ComPort; // Variables to hold the currrent device configuration + private static string _comPort; // Variables to hold the currrent device configuration /// /// Private variable to hold an ASCOM Utilities object @@ -193,12 +193,12 @@ namespace ASCOM.Meade.net } catch (Exception ex) { - LogMessage("Connected Set", "Error connecting to port {0} - {1}", ComPort, ex.Message); + LogMessage("Connected Set", "Error connecting to port {0} - {1}", _comPort, ex.Message); } } else { - LogMessage("Connected Set", "Disconnecting from port {0}", ComPort); + LogMessage("Connected Set", "Disconnecting from port {0}", _comPort); _sharedResourcesWrapper.Disconnect("Serial"); IsConnected = false; } @@ -241,8 +241,8 @@ namespace ASCOM.Meade.net // TODO customise this device description get { - Tl.LogMessage("Description Get", _driverDescription); - return _driverDescription; + Tl.LogMessage("Description Get", DriverDescription); + return DriverDescription; } } @@ -284,7 +284,7 @@ namespace ASCOM.Meade.net get { //string name = "Short driver name - please customise"; - string name = _driverDescription; + string name = DriverDescription; Tl.LogMessage("Name Get", name); return name; } @@ -496,7 +496,7 @@ namespace ASCOM.Meade.net p.DeviceType = "Focuser"; if (bRegister) { - p.Register(DriverId, _driverDescription); + p.Register(DriverId, DriverDescription); } else { @@ -577,7 +577,7 @@ namespace ASCOM.Meade.net { var profileProperties = _sharedResourcesWrapper.ReadProfile(); Tl.Enabled = profileProperties.TraceLogger; - ComPort = profileProperties.ComPort; + _comPort = profileProperties.ComPort; } /// diff --git a/Meade.net/ClassFactory.cs b/Meade.net/ClassFactory.cs index 1f5c265..4b7feca 100644 --- a/Meade.net/ClassFactory.cs +++ b/Meade.net/ClassFactory.cs @@ -33,8 +33,8 @@ namespace ASCOM.Meade.net #region Access to ole32.dll functions for class factories // Define two common GUID objects for public usage. - public static Guid IidIUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); - public static Guid IidIDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); + private static Guid _iidIUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); + private static Guid _iidIDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); [Flags] enum Clsctx : uint @@ -109,70 +109,60 @@ namespace ASCOM.Meade.net #region Constructor and Private ClassFactory Data - protected readonly Type MClassType; - protected Guid MClassId; - protected readonly ArrayList MInterfaceTypes; - protected uint MClassContext; - protected uint MFlags; - protected UInt32 MLocked = 0; - protected uint MCookie; - protected string MProgid; + private readonly Type _mClassType; + private Guid _mClassId; + private readonly ArrayList _mInterfaceTypes; + private UInt32 _mLocked = 0; + private uint _mCookie; + private readonly string _mProgid; public ClassFactory(Type type) { if (type == null) throw new ArgumentNullException("type"); - MClassType = type; + _mClassType = type; //PWGS Get the ProgID from the MetaData - MProgid = Marshal.GenerateProgIdForType(type); - MClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)] - MClassContext = (uint)Clsctx.ClsctxLocalServer; // Default - MFlags = (uint)Regcls.RegclsMultipleuse | // Default + _mProgid = Marshal.GenerateProgIdForType(type); + _mClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)] + ClassContext = (uint)Clsctx.ClsctxLocalServer; // Default + Flags = (uint)Regcls.RegclsMultipleuse | // Default (uint)Regcls.RegclsSuspended; - MInterfaceTypes = new ArrayList(); + _mInterfaceTypes = new ArrayList(); foreach (Type T in type.GetInterfaces()) // Save all of the implemented interfaces - MInterfaceTypes.Add(T); + _mInterfaceTypes.Add(T); } #endregion #region Common ClassFactory Methods - public uint ClassContext - { - get => MClassContext; - set => MClassContext = value; - } + public uint ClassContext { get; set; } public Guid ClassId { - get => MClassId; - set => MClassId = value; + get => _mClassId; + set => _mClassId = value; } - public uint Flags - { - get => MFlags; - set => MFlags = value; - } + public uint Flags { get; set; } public bool RegisterClassObject() { // Register the class factory int i = CoRegisterClassObject ( - ref MClassId, + ref _mClassId, this, - MClassContext, - MFlags, - out MCookie + ClassContext, + Flags, + out _mCookie ); return (i == 0); } public bool RevokeClassObject() { - int i = CoRevokeClassObject(MCookie); + int i = CoRevokeClassObject(_mCookie); return (i == 0); } @@ -201,25 +191,25 @@ namespace ASCOM.Meade.net // // Handle specific requests for implemented interfaces // - foreach (Type iType in MInterfaceTypes) + foreach (Type iType in _mInterfaceTypes) { if (riid == Marshal.GenerateGuidForType(iType)) { - ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(MClassType), iType); + ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(_mClassType), iType); return; } } // // Handle requests for IDispatch or IUnknown on the class // - if (riid == IidIDispatch) + if (riid == _iidIDispatch) { - ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(MClassType)); + ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(_mClassType)); return; } - else if (riid == IidIUnknown) + else if (riid == _iidIUnknown) { - ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(MClassType)); + ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(_mClassType)); } else { diff --git a/Meade.net/GarbageCollection.cs b/Meade.net/GarbageCollection.cs index 714af79..f6d5e82 100644 --- a/Meade.net/GarbageCollection.cs +++ b/Meade.net/GarbageCollection.cs @@ -8,17 +8,17 @@ namespace ASCOM.Meade.net /// class GarbageCollection { - protected bool MBContinueThread; - protected bool MGcWatchStopped; - protected int MIInterval; - protected ManualResetEvent MEventThreadEnded; + private bool _mbContinueThread; + private bool _mGcWatchStopped; + private readonly int _miInterval; + private readonly ManualResetEvent _mEventThreadEnded; public GarbageCollection(int iInterval) { - MBContinueThread = true; - MGcWatchStopped = false; - MIInterval = iInterval; - MEventThreadEnded = new ManualResetEvent(false); + _mbContinueThread = true; + _mGcWatchStopped = false; + _miInterval = iInterval; + _mEventThreadEnded = new ManualResetEvent(false); } public void GcWatch() @@ -27,16 +27,16 @@ namespace ASCOM.Meade.net while (ContinueThread()) { GC.Collect(); - Thread.Sleep(MIInterval); + Thread.Sleep(_miInterval); } - MEventThreadEnded.Set(); + _mEventThreadEnded.Set(); } protected bool ContinueThread() { lock (this) { - return MBContinueThread; + return _mbContinueThread; } } @@ -44,14 +44,14 @@ namespace ASCOM.Meade.net { lock (this) { - MBContinueThread = false; + _mbContinueThread = false; } } public void WaitForThreadToStop() { - MEventThreadEnded.WaitOne(); - MEventThreadEnded.Reset(); + _mEventThreadEnded.WaitOne(); + _mEventThreadEnded.Reset(); } } } diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index d42147e..5598146 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -153,11 +153,11 @@ namespace ASCOM.Meade.net #region Profile - internal static string DriverId = "ASCOM.MeadeGeneric.Telescope"; + private const string DriverId = "ASCOM.MeadeGeneric.Telescope"; // Constants used for Profile persistence - internal static string ComPortProfileName = "COM Port"; - internal static string TraceStateProfileName = "Trace Level"; + private const string ComPortProfileName = "COM Port"; + private const string TraceStateProfileName = "Trace Level"; public static void WriteProfile(ProfileProperties profileProperties) { @@ -172,8 +172,8 @@ namespace ASCOM.Meade.net } } - private static readonly string ComPortDefault = "COM1"; - internal static string TraceStateDefault = "false"; + private const string ComPortDefault = "COM1"; + private const string TraceStateDefault = "false"; public static ProfileProperties ReadProfile() { From ac887ccdfff75eea5dc32dca26a707ef21161dc6 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 14:42:25 +0100 Subject: [PATCH 108/109] Code inspections --- FocuserTestConsole/Program.cs | 2 +- Meade.net.Telescope/Telescope.cs | 2 +- Meade.net/ClassFactory.cs | 8 ++++---- Meade.net/Localization/LocalisationHelper.cs | 2 +- Meade.net/SharedResources.cs | 2 +- TelescopeTestConsole/Program.cs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/FocuserTestConsole/Program.cs b/FocuserTestConsole/Program.cs index cfafd57..d7cfce5 100644 --- a/FocuserTestConsole/Program.cs +++ b/FocuserTestConsole/Program.cs @@ -12,7 +12,7 @@ using System; using System.Threading; using ASCOM.DriverAccess; -namespace ASCOM +namespace ASCOM.MeadeGeneric { class Program { diff --git a/Meade.net.Telescope/Telescope.cs b/Meade.net.Telescope/Telescope.cs index 264dacb..0ce3b53 100644 --- a/Meade.net.Telescope/Telescope.cs +++ b/Meade.net.Telescope/Telescope.cs @@ -349,7 +349,7 @@ namespace ASCOM.Meade.net private bool FirmwareIsGreaterThan(string minVersion) { var currentVersion = _sharedResourcesWrapper.FirmwareVersion; - var comparison = currentVersion.CompareTo(minVersion); + var comparison = String.Compare(currentVersion, minVersion, StringComparison.Ordinal); return (comparison >= 0); } diff --git a/Meade.net/ClassFactory.cs b/Meade.net/ClassFactory.cs index 4b7feca..431e2d0 100644 --- a/Meade.net/ClassFactory.cs +++ b/Meade.net/ClassFactory.cs @@ -33,8 +33,8 @@ namespace ASCOM.Meade.net #region Access to ole32.dll functions for class factories // Define two common GUID objects for public usage. - private static Guid _iidIUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); - private static Guid _iidIDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); + private static readonly Guid _iidIUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); + private static readonly Guid _iidIDispatch = new Guid("{00020400-0000-0000-C000-000000000046}"); [Flags] enum Clsctx : uint @@ -136,7 +136,7 @@ namespace ASCOM.Meade.net #endregion #region Common ClassFactory Methods - public uint ClassContext { get; set; } + public uint ClassContext { get; } public Guid ClassId { @@ -144,7 +144,7 @@ namespace ASCOM.Meade.net set => _mClassId = value; } - public uint Flags { get; set; } + public uint Flags { get; } public bool RegisterClassObject() { diff --git a/Meade.net/Localization/LocalisationHelper.cs b/Meade.net/Localization/LocalisationHelper.cs index 9c4b4bf..d193826 100644 --- a/Meade.net/Localization/LocalisationHelper.cs +++ b/Meade.net/Localization/LocalisationHelper.cs @@ -8,7 +8,7 @@ namespace ASCOM.Meade.net.Localization internal class LocalisationHelper { private const string LocalizationNamespace = "LocalisationTest.Localization.Resources.Localization"; - ResourceManager _resourceManager; + private readonly ResourceManager _resourceManager; public LocalisationHelper() { diff --git a/Meade.net/SharedResources.cs b/Meade.net/SharedResources.cs index 5598146..9068cf3 100644 --- a/Meade.net/SharedResources.cs +++ b/Meade.net/SharedResources.cs @@ -244,7 +244,7 @@ namespace ASCOM.Meade.net /// The Key is the connection number that identifies the device, it could be the COM port name, /// USB ID or IP Address, the Value is the DeviceHardware class /// - private static Dictionary _connectedDevices = new Dictionary(); + private static readonly Dictionary _connectedDevices = new Dictionary(); /// /// This is called in the driver Connect(true) property, diff --git a/TelescopeTestConsole/Program.cs b/TelescopeTestConsole/Program.cs index 36d0d4a..f9cc60b 100644 --- a/TelescopeTestConsole/Program.cs +++ b/TelescopeTestConsole/Program.cs @@ -10,7 +10,7 @@ using System; -namespace ASCOM +namespace ASCOM.Meade.net { class Program { From 53150f94009568ce83b9e92c36c2839c9c0a3d01 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 19 Jul 2019 16:51:13 +0100 Subject: [PATCH 109/109] Reset all version info's to 0.0.0.0 as TeamCity deals with version numbering now. --- AstroMath.UnitTests/Properties/AssemblyInfo.cs | 4 ++-- FocuserTestConsole/Properties/AssemblyInfo.cs | 4 ++-- Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs | 4 ++-- Meade.net.Telescope/Properties/AssemblyInfo.cs | 4 ++-- Meade.net.focuser/Properties/AssemblyInfo.cs | 4 ++-- Meade.net/Properties/AssemblyInfo.cs | 4 ++-- TelescopeTestConsole/Properties/AssemblyInfo.cs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/AstroMath.UnitTests/Properties/AssemblyInfo.cs b/AstroMath.UnitTests/Properties/AssemblyInfo.cs index 3bfdd87..fa399cc 100644 --- a/AstroMath.UnitTests/Properties/AssemblyInfo.cs +++ b/AstroMath.UnitTests/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/FocuserTestConsole/Properties/AssemblyInfo.cs b/FocuserTestConsole/Properties/AssemblyInfo.cs index b1cdefc..fcf75bf 100644 --- a/FocuserTestConsole/Properties/AssemblyInfo.cs +++ b/FocuserTestConsole/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs index 3b11908..3d960cb 100644 --- a/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope.UnitTests/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/Meade.net.Telescope/Properties/AssemblyInfo.cs b/Meade.net.Telescope/Properties/AssemblyInfo.cs index 1a4865e..ab1142a 100644 --- a/Meade.net.Telescope/Properties/AssemblyInfo.cs +++ b/Meade.net.Telescope/Properties/AssemblyInfo.cs @@ -34,5 +34,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/Meade.net.focuser/Properties/AssemblyInfo.cs b/Meade.net.focuser/Properties/AssemblyInfo.cs index d812c2d..46c7ed0 100644 --- a/Meade.net.focuser/Properties/AssemblyInfo.cs +++ b/Meade.net.focuser/Properties/AssemblyInfo.cs @@ -34,5 +34,5 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // // TODO - Set your driver's version here -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] diff --git a/Meade.net/Properties/AssemblyInfo.cs b/Meade.net/Properties/AssemblyInfo.cs index 0c66435..c121a1e 100644 --- a/Meade.net/Properties/AssemblyInfo.cs +++ b/Meade.net/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")] [assembly: ComVisibleAttribute(false)] diff --git a/TelescopeTestConsole/Properties/AssemblyInfo.cs b/TelescopeTestConsole/Properties/AssemblyInfo.cs index cd3bac2..f82ea1d 100644 --- a/TelescopeTestConsole/Properties/AssemblyInfo.cs +++ b/TelescopeTestConsole/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.7.0.0")] -[assembly: AssemblyFileVersion("0.7.0.0")] +[assembly: AssemblyVersion("0.0.0.0")] +[assembly: AssemblyFileVersion("0.0.0.0")]

    Prior to developing your first driver, please +familiarize yourself with the developer +information we've provided at the ASCOM Initiative web site +(internet required). +

    wNI))^Rfsnh#!tW@7qgXfY<_&n30YQx7`(0&6D+ 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

    yBXjJq&wZlJJR;gaeOEY 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