quisk-3.6.11/0000775000175000017500000000000012164330433012317 5ustar jimjim00000000000000quisk-3.6.11/docs1.html0000644000175000017500000000236012071314115014211 0ustar jimjim00000000000000 Documentation contents for Quisk Welcome
Credits
Installation
    Linux
    Windows
    Quisk Files
Configuration
Sound Cards
    Linux
    Windows
SDR-IQ as Input
Timing
USB Control
Custom Hardware
Extension Packages
    Shared Libraries
    New Packages
    Installing Packages
Digital Modes
Vector Network Analyzer

quisk-3.6.11/_quisk.pyd0000666000175000017500000027701612162640501014345 0ustar jimjim00000000000000MZ@ !L!This program cannot be run in DOS mode. $PEL AAQ~# zHf0 $ H  l t.text`P`.dataHkl@`.rdata`P<@`@/4pT@0.bss F`.edataHV@0@.idata X@0.CRTf@0.tls h@0.relocl j@0BUED$fD$f$Í'UED$fD$f$ɃÐ&USft4f9wtЋf9v$襼f$藼[]É'U8]] uu}}tC|$\$4$c ufEVE]u}] t&$$ftbfeft|$D$4$Ѓ 莿|$D$4$ u1낐t&1v輻 1dU$PfRteD$Pf$ytD$ f$pfЋ DKft1$)PfCRt*D$7Pf$6t $DKfø말U$PfQt%D$KPf$t $pfÍvUVSË $f5dfMEEES $4$4$d$l]f}fU fUm]mUx9~9} fB9 ـE@tfEظ[^UEE|]fEt 5]fp]fDfR<$d$5fEuك=fu0u=l]f=l]f~=ftDТf f=l]fEut31آfu=x]f UD$ TfD$dfD$hPfE $tft%df@fXf`ffUD$lfD$kPfE $tft fUD$mPfE $tft fUD$mPfE $tft fUD$mPfE $tft fUD$ fD$pfD$hPfE $tft fUD$tfD$kPfE $tft fUD$(fD$nPfE $tft fUD$fD$kPfE $tft fUD$fD$nPfE $tft fU(D$fD$ fD$fD$pPfE $tft fU(D$fD$ fD$fD$tPfE $tftfffUD$ԉfD$kPfE $tft fUD$mPfE $tft fU(ED$D$kPfE $tftE$貐fUS$fEssD$mPfE $tf`fD$$誴]D$ D$\$`f$苴D$ D$\$`f$g$-豦`f$/`fPf=DftDf'f]UWVS$EE]E]Ѓ=fu!f`űfqq5fuEEEX!U܍);4`űf)`űf ))щ`űfEhűf`űfEf`űfE~[}܍ߍ<+}܍hűf `1ff jfA9@9u)ЋUB`űf h]fɋEXE$[^_UWVS$EE]E]Ѓ=Љfu!Љffqq5fuEEEXU܍);4Šf)Šf )f)эˠfEYEYfE~Z}܍ߍ<+}`1f;fKK@9A9u)ЋUBŠfEXE$[^_UWVPED$ ED$D$xPfE $tfD$$ΰt"p|Pf*$fwDfD$D$$臰 `fDž\D$\T$ D$D$$J`fDž`E$)fbE$dD$t$`f$ tUD$`f$覯`f$肽`fED$ ED$D$Pfp$:ED$ ED$D$Pfp$pPf󤍅p$fe^_U(ED$D$QfE $tftE$w$fU(ED$D$kPfE $tftE`$fUSED$ED$ ED$D$QfE $tft=D$h\$EUD$T$ ED$E$豉$fĴ[UD$mPfE $tftufUVSD$mPfE $tft#f hƉ$f4$f[^UD$mPfE $tftOpfUXED$D$kPfE $tfEtfdft\EEԉUEԍE h]f ]f\$\$ $޺E؋UܣffEUfffffUWVSEUM=,1fD$ D$qfD$ f$,fӣ,1fD$ D$ fD$qf$5(f֣(1fD$ D$࠭fD$f$ӣ$1fD$ D$fD$࠭f$֣ 1f]fS $d$5]f$Zl]f1fCuʃ}uk01ff81f@1f41f<1f f@ ff@ff +=f}EEXb U ]Uyډ Q‰UEE01fu]L f $f f $fL@01f=V01f,1f$fE}EԋE}E}t E}qf؉E]ES$T$CS D$T$ ]f f ]ffy9E}EEu ]ȉuFGu]ĉ+@1fw<1f <1f<1f~ <1f} <1fy@1fEuԉ]ԋ]}؅y9}%ȅy9}fEuىUBCAu؋]ԋE+81fw41f 41f41fEԃ~41fE(}}41fE}y Uȉ81f <1f~}~uȍ E9fTfE}ƃݐ࠭fݘ蠭f=u؍C…yPׅ~e9࠭f8wR@9}9|&࠭fwPA9}ء 1f$fff ff ffHBuݸ]ff 1f ]ff@=uf@=uء$1f$f蠭f젭fD$T$ ࠭f䠭fD$T$qf qfD$ T$qfqfD$T$E؉$蒯E؋U܉qfqfEU䉃qf qf@o(1f$f f0!f]f f f@=uEU9UU%Eȃ…yPƒ}(Me[^_UXED$D$ xfD$fD$tPfE $tf]f f$W%x]f5]ffxfy؉EEDf]ȍE h]fu ]fu\$\$ $PE؋UܣffEU䣐ffE ]fMl]f}fEҴ fEmfm҃=fw$CfUD$fD$kPfE $tft$$fUD$fD$kPfE $tftfU8ED$D$kPfE $tf:E t=D1fuV]f\$$Qf> Df ]f]f}fE fEm]mEH1f$D1fL1fP1fT1fX1fHf^HfR=X1ftL1f@P1f;H1f|P1f P1fP1fT1fHf Hf=Hf$fUWVSD$\1fED$ ED$D$QfE $tfE$ft D$QfLf$fE$ft D$:QfLf$fcE$fӉƋE$Ӊd9t D$XQfLf$f!d'dGD$ 'D$QfD$b~$l\$Lf$fftfpflfht$E$tÉ$p`1ftHu C$Pt$E$lÉ$hjftHu C$PF9ddffļ[^_UWVSP8gEƉ$ ffD$D$ D$D$$.$ff$wƣf$w٠£fw]fS $d$5]f$辠l]fC.uD$`fT$$D$@fD$$ٙD$ fD$$ř~j f.lf2zZr @A9~.~ f=f.f fBLBB\B=wuߡf$fff@ff=fwwww$T$www wD$T$ 脬33u=fff7T7$T$D7T7 D$T$ @܃ݛwuáf9yfxf)p)ø[)9.5f]fEuىB9~fDD ]fQ$]fɉ<$ $d$ l]fpffw f<[^_UWVS,ljӉ΅EE@43) f׹ 3+Uff 3+Uୱff D$rD$f3+Ef$D$7D$` f3+E f$D$D$ f3+E@f$ǎD$D$Ef3+E`f$螎D$D$ f3+Ef$uD$rD$ %f3+Ef$LD$D$(f3+Ef$#D$bD$0f3+Eఱf$E}NFfEf@fEdMb)=!=R`` 05)=U=o==&=r= =g==5=AE䣘fD$ v) fD$\$<$}t2D$ v)ఱfD$\$<$舑v)fD$\$<$͓EEfD$ v)fD$\$<$jEEfD$ v)@fD$\$<$ڐ(VUUUEE)‰fD$ v)fD$\$<$萐v)fD$\$<$Ւ}t3D$ v)ఱfT$D$<$4v) fT$D$<$xW}t2D$ v)fD$\$<$яD$ v)fD$\$<$蟏*EE)‰fvEEEE)fD$\$<$D$ UU)€fT$D$<$%svEE܋EE)fD$\$<$^UU)ୱfT$D$<$:}t3D$ v)ఱfT$D$<$虎v) fT$D$<$ݐD$ v)fD$\$<$<}t3D$ v)ఱfT$D$<$ Xv) fT$D$<$N-*EE)‰fvEEEE)fD$\$<$UU)ୱfT$D$<$ڏD$ UU)€fT$D$<$?vEE܋EE)fD$\$<$xD$ UU) fT$D$<$݌}t3D$ v)ఱfT$D$<$諌v) fT$D$<$*EE)‰fvEEEE)fD$\$<$螎UU)fT$D$<$zUU)ୱfT$D$<$VD$ UU)`fT$D$<$軋 $QfŔ؃,[^_UWVSlÉ׉΅~EԘfEUЍ43иf׹ 3ff 3ffװD$]D$Bf3(f$XD$/D$3f3Hf$6D$/D$3f3hf$D$$D$ 5f3ňf$D$5D$8f3Ũf$ЅD$bD$0fȾf$V]fUZZ^f^fRRZB L^B$EЁhUԃ} f`f=f f$Qf…yP`fhfU‰EEȋEEȍfD$t$$UUȍиfT$D$$D$ UUȍȾfT$D$$_EЅ~<S$T$CS D$T$ UEEEF9uɃ}uhf$ xfUЉD$ U43hfD$EЉD$<$gfT$D$<$%`f…yP`fhfU‰EEȋEEȍfD$t$$ʊUUȍиfT$D$$譊D$ UUȍȾfT$D$$EЅ~<S$T$CS D$T$ UE>EmF9uɃ}uhf$ xfUЉyD$ U43hfD$EЉD$<$!fT$D$<$躌%`fZ…yP`fhfU‰EEȋEEȍfD$t$$脉D$ UUȍȾfT$D$$EЅ~<S$T$CS D$T$ UEEEF9uɃ}uhf$UЉQD$ UHfD$EЉD$<$%`fS…yP`fhfU‰EEȋEEȍfD$t$$}D$ UUȍȾfT$D$$EЅ~<S$T$CS D$T$ UEEmF9uɃ}uhf$UЉJD$ UHfD$EЉD$<$%`fL`fhfD$ UȾfD$L$$EЅU}ȉNjS$T$CS D$T$ UEE؋U܉$T$EUD$T$ ݇f ^fݗfEF9uNjUňfD$EЉD$<$ƃ}Ghf$,`fhfD$ UȾfD$L$$EEU}V$T$FV D$T$ UEE]EU\$E\$fG\$ ffD$T$E؉$蝔EݛfE_`f]ȋE؋U܉D$T$ EU$T$FM܋ff݃f܋f@܋fPEЋUݛf@EЃ9ED$ U43(fD$ED$<$蘃3ըfT$D$<$HfT$D$<$辇ƃ}`hf$ Ehf~IEMоS$T$CS D$T$ UE`EmF9uɋuЃ}hf$hf~IEMоS$T$CS D$T$ UEEEF9uɋuЃ}uvhf$#^hf=\1f7JM~IS$T$CS D$T$ UEE؋U܉SEUCS G9e[^_UWVSulE Uܵ`܍p}t}tO}E]Q<$d$HXJyUJA9MEb\tYEڽ\K [\\9E1Dž\%[uDž\EEF9uE|9EÉ5䐻fEfE萻f\f좱fx u@ @x uz좱fU]ˋHrz qy HAH; Ģf|0@ @x u@ @]좱fhfC9]]좱f=fV pf EE@fE ^f ^f\$\$ $!sE]E]f]f]uE}؉]E\$E\$FV D$ T$VD$T$<$mE؋U܉VEUFV E\$E\$E\$ E\$<$ZmEUEUC;]qɋ]ff=fu&Df=@f\$\$E$9cڋEƃ=ft f‹E($ؐfEǃ=f  =tfu  f@fE ^f ^f\$\$ $qE]E]f]f]5Аf}]E\$E\$FV D$ T$VD$T$E؉$kEUM؋]܉^FV E\$E\$E\$ E\$E؉$kEUEUG;}kɋ}]ffڡАfl$ԐfАf}tftt uFpf9 f| Aphؐf ԐfUZ@9u4Ԑf ؐfUZ@9upf9 f} Aؐf ԐfUZ@9uԐf ؐfUZ@9u| ؐfUZ@9uR ԐfUZ@9u( ؐfUZ@9uءf=^fP<$d$]= fx]ECS ffffEt^fuE\$ \$$Rfaf^fE1%^f%^fEE0f]8f] f](f]f]f] Hf5^fE ]f]E^fE]E5_fE @f5^fM ]fMM5_fXEfmfE@fEHfE0fE8fE fE(f^fEu\$$Sf_ء0f4f@fDf8fM܋Eԃ} .u}EE}fU¶ fUuEmm‹EOmm‹H~ EM؋EкuF9u }~uM܋Eԃ} u}Ebfu֋EEOH~ EM؋EкuF9u ~}~؋u؋u u؋uUЉT$U؉T$ UԉT$U܉T$4$PLe[^_UUUUUEÐUUUfU}fÐUWVS,׃=ft ff fþf}fU fUmߜ fmCmߜ"fmf=W=ft(D$ D$D$ ff$#,HfD$ D$D$!ff$^#f9tD$$bf'$fF9-e[^_USE~* cfɉQC9u[UWVStUE]fEă@fEă@uvf\/f$?fuSgf ?fz2fL?fXBfٜ?cfffff؃}$f]f]f]fݝx5f=ff]f]f]tEE\$E\$E\$ t$|$E؉$j*E]EUuȋ}]݅x\$E\$E\$ E\$E؉$(*EEUUEMEM[EԃE9E^5f=fEfEfEfUte[^_UWVSLUE]t ZD$ED$`f$f=fD$ D$D$?$fEƿD$ f(cf>\$E؉$cEUEU$\$ .EuE]}]cfEMMM[G9}wEe[^_UWVS\EUM f$f8ff pfpfD$ @f\$<$}EUEU$\$$+ـE@tlDcf=f(fEt8fEuhf- cf8f`f- cf8f8fEUMU$\$*Eu}]D$ fE\$<$EUEUȃ}t$\$-*]EEEu]EE[EE9EtԿf}E=Hcf]EEu]0fEEu+58cf$Y 0fM0f)5@cf$. 0fM0f}~}0f]]E UEKUUU$\$)EuE]}]cfEM^G;}uܿf~!D$ D$fED$E$tEEe[^_Կf}UWVS|D$bfE $tfc$f$ fD$D$ D$D$$f$$fE$f( $á$f$E$( E$( E$fEЅ~W؉E]ȉ}]]XcfW $d$u$W cfcfFG;uuы}]EEE~`cfU@9|E `cf%@cf]EE=Xcf]E}ދ}M]ȅ~E]лE$EEUXcfEu]C9|EEEEt؋}ع $f~&݄( EuB9u=cf]иE GTG=( uعE~$f~(E܌( Q@$f9ع@=$f~)MHXB9$fE$f$fhcfP4$d$u]Ѕ~qE}ĉ߻V$T$FV D$T$ g%Mpcfu xcf $!C$f9}ĉ$fEС$f9~UEfEfE܉}ĉ߻cf $UD$\$EЉ$UFC95$f։]ȉ}E=$f~YfEfE܉}ĉߋ]ȍcf $UD$\$EЉ$UF$f9Ɖ}ċE$E$$E$E$f<$fEEЃ|[^_UWVSL}]~RE cf}fMֵ fM@Xm]m֋M9}B9u;5f~5ff)أf5Mb)Ѝffff=f f$bf=Hfu*$D$?ڋE 'ɋE fu ڋE ɋE cfR<$d$$ڋE v=HftڋE Å~)E cf `cfXB9u؉ڋE  =HftڋE jÅ~d@f]ȋu 5(cfM5(cfM\$\$ E؉$!(cfM(cfM^G9uڋE ~fu$ڋE ɋE ThcfR<$d$$ڋE SH$ڋE 4$;fD$?ڋE f`cf$ڋE N؍e[^_Uft$ f=ftUE䀻D$D$?$bf1@fcf\$$bf(f@cf\$$cf f=f;Uf=|fTD$$\fD$D$$3 fD$UT$ D$D$$fEf$fE$|fED$ED$f$ tf$ffU$qUD$fD$cfE $tft!=fufUVS] =@ftJfu@ED$@f$fƅt$fËHuF4$Pf؃[^US$E ]=@ftKfuAED$@f$fÅt $f]HuC$PfE$[UWVS] =@ftXfuNED$@f$fƅt)$fNjHu F4$Puf f؃[^_U8E$7EUE؉Um؅ydf]E dfUVS@u] f fu9E$tEUffffE$tm-f]]C @yE f+u#EpfE f@ u>tIt$E$ fdf\$E% f\$ E%pf\$$cfIE$ fdf\$E% f\$ E%pf\$$cfc>t2t$E% f df\$ E%pf\$$cf,E% f df\$ E%pf\$$cfE fe[^UMMb)ȅ$ÐUWVS]E Cu4$ ‰C׉SEC CCC[^_UWVS]E CE44$u ‰C׉SEC CCC[^_UWVS\]E ]Ѓ{uC $ CE df]E df]ЋC P,$d$ df]~EV,$d$EM\$\$ E؉$#EEʃ}t C8\8C df8\8F9s e[^_UWVS}GU MHW_ ~4wLM J9sEA9t GGW 9rɉWɋEX[^_UWVSk;??{z>?nȫ@?A?x{ hIB=P>BŶS kW;2YwKZ!6Hl8]JcX_p`7ԁ\a\JU0bjWUbDJtbEUW3aTtԜ`Um^dXi[N,W$CSc0>MHN&C|w}1J6 ?rhű5?>PC?9͑Y L?p-iQ?jc*(T?||ٜU?~K'V?VP\V?ą!U?,)UkR?oNcpO?m`[G?54;?1ⲹ&?A0e %WDȗHPRhUȌ%9[/_ƺfaJbpc糿4cHb*@&ar,^-AyYY!Sв'oG|,\?RR?+mA??8/AL0|bPar:y\3:dair[n)3q-+Vkr7p"ss(sH surp]qF+mwRxbh i>aܔIR7,b>EYP?~a?`Jj?+q?0%u?x?[I{?;@|?#s}?dm|?r9C{? mqx?c)t?o?9o\%c?t[F?kW9Qڗu(h}]sTBg{`A\\m& -ZKe s ;6j;EYP?7,bܔIR i>awRxbhF+mp]qH surs(s7p"s-+Vkr)3qr[nai3:dar:y\|bP8/AL0+mA??RR?IK:>\?icb?ȇ\Ce?KzuBh?Pi?fj?Ü^pi?*Mqg?e?nTb?Zͦ~^??V?Z{R4K?PC?rhű5?J6 ?|w}1HN&Cc0>M$CSN,WdXi[Um^TtԜ`EUW3aDJtbjWUb\JU0b7ԁ\ap`JcX_!6Hl8];2YwKZ kW>BŶSB=P>{ hIFBq88r:q(#;W ?Ɠ0?1 8?ob=?f A?/*jB?bq?gC?rC?(dCC?x?!>k;?FMV8?zi&5?h1+1?XV]-?YW(?eBV#? 0Z?-|<?t$X?Fi+Y?8 Z A%[I. ھS{F?o|Y?X^?*lP?ԋ}AP`*DV֝SA*KH*U?ncsn`?)76?۠(aѷd[Nj5?R!l?VDh?g=XZgIz@uLf1v"]o?wڕ|?_~[?CŠ|4ac|qL?'[3 ?i[t?OXQzv6C~{Z5LI?=?Z2.Mk?{ {IDnsd:w{?. /Z?\Z_Wm?jתƵ泿aRx&O?q`;}9?UzY?q`;}9?O?aRx&תƵ泿j\Z_Wm?. /Z?d:w{?Dns{ {IZ2.Mk?=?Z5LI?{6C~OXQzvi[t?'[3 ?c|qL?4aCŠ|_~[?wڕ|?1v"]o?LfgIz@ug=XZVDh?R!l?[Nj5?ѷd۠(a)76?ncsn`?*KH*U?֝SAP`*DVԋ}A*lP?X^?o|Y?S{F? ھ[I. A%8 Z م.u*K1Kiay Ѿ̼'Gn-~`o/b3n*d;ӽ2ޢ?f)?8?FF?6jQ?U?#Nq'X?vX?v9,U?{OyK?,/?X >5gf&RoYp\wW=$0mJWf3}m ?I0 S?[7a?f?<wC|g?u $nb?,/R?,G@_bٌX8nx@Qr qi*P-SmZ?wf)Nq?ȧay?KB|?vC dy?9iEo?oD%1?g6o28sԄ_~@>2w-ks M p6 _?]|L?`Ł?b4P?RSЈ?Xe?/V:i?]d=) |4\:gy`$bTR5rorvFTa?߁_ ?Xr 6?曎: ?JȠ$/?A̲w?Bun;?Bun;?A̲w?JȠ$/?曎: ?Xr 6?߁_ ?rvFTa?robTR5\:gy`$ |4)]d=/V:i?Xe?RSЈ?b4P?`Ł?]|L?6 _? M p2w-ks_~@>Ԅ28sg6ooD%1?9iEo?vC dy?KB|?ȧay?wf)Nq?-SmZ?*Pi qx@QrٌX8n_b,G@,/R?u $nb?<wC|g?f?[7a?I0 S?Wf3}m ?=$0mJwWp\oY5gf&RX >,/?{OyK?v9,U?vX?#Nq'X?U?6jQ?FF?f)?8?2ޢ?d;ӽb3n*~`o/Gn-Ѿ̼'ay 1Ki.u*KمU6 ?L)3"??+?lH ?$mk@l߅-Vq"^AUف??*7Ce? mi?GUL?5kIuɓ#y'Uq߆׸d?NNͶr?#x`?u4O? TfⒿ6kjMgy?Bnѝ?l%kh?EDIWU vּ>e$`7yGж?\%У?Hgn?Hgn?\%У?yGж?e$`7ּ>U vEDIWl%kh?Bnѝ?y?6kjMgfⒿ Tu4O?#x`?NNͶr?߆׸d?'UqIuɓ#y5kGUL? mi?*7Ce?ف??AUq"^l߅-V$mk@lH ??+?L)3"?U6 ?^3>BH.:件2J"0oqiF@5qɳ?͉?UAn?0?0?UAn?͉?qɳ?5>@I|.qn 2mi;Kˆ?*RX?^HL?8u4?o7ՠb.#OKђZ]Ra}Be?G(z&1ib1WŇ6ꀙ N^45]f4?.˸L?j0>W? A\?8PgZ?osЊL?1Z:?rVpn^(0hɨQi[){g`ş3?׷5 i?^?v?/y?=r?D@?ZspL>!~XAX <Ӑ`] }?Z/2G?/~?8m%?t'u? # hʇ/wຠCI-SbPo _?;=dM? *%?2_? SBk? SBk?2_? *%?;=dM? _?SbPoCI-ຠ/w # hʇt'u?8m%?/~?Z/2G?] }?<Ӑ`X !~XApL>ZsD@?=r?/y?^?v?׷5 i?ş3?[){g`ɨQi(0h?rVpn^1Z:osЊL?8PgZ? A\?j0>W?.˸L?5]f4?ꀙ N^4WŇ61ib1z&(GI0L>V;>My1?Efޖm?3D?dC!?(%&?J_,?(2?1?'W&3?%\H4?xd3?w;1?:sDA*?̛? ֕ '8/ݱ>09 '?]7?.>vPB?+mB]F?F?p5D?s=:ʣUv9?+ G?o^ P?}SR? #ZR?FhP?XjF?90A4?ٱ s?B쫯(OF 8T3 HW!`V kS41` Kk6d4-?pNI?/BT?0D Z?Tt]?oA( \??.QW?򋫭N?4F93?Ccqj: cQ}[aqA_:bnqt&a$I•[J2PI.V,%%IF?G6qX?lw b?`K+ƿe?īEf?xcd?6)]`?z;FQ?njP?1Q6[3a_֊gvokJ0 2lCh٧$\b*=4Q<0?pZ?ՍqŸg?!xfo?4mq? wq?Wm?ꀭHd?I1JP?nmH\d%?`pր7t.OAvMu.lLqY'\ef6V4HMcX?*n?7v?!{?[,}?`m6f{?j~u?q)h? z@-?x!>f6r)wQd$U}FDy[ۃ)+؁Any˒zUEj ּI?BBt?x^e?Onˈ?|9{?Cx?8t ?혁?T\Wzk?"hzh<^OςH77Xm7[Иzl>o=RP9lA+?ʯ?PF^h?bþ?5:/,?7mV?_;XDۺ?'{۳?2U?'{۳?_;XDۺ?7mV?5:/,?bþ?PF^h?ʯ?A+?o=RP9l>zl7[ИXmH77<^Oςzh"hT\Wzk?혁?8t ?Cx?|9{?Onˈ?x^e?BBt? ּI?UEjAny˒z)+؁y[ۃ}FDQd$U6r)wx!>f z@-?q)h?j~u?`m6f{?[,}?!{?7v?*n?McX?6V4HY'\ef.lLqMu.OAvր7t%?`p\dnmHI1JP?ꀭHd?Wm? wq?4mq?!xfo?ՍqŸg?pZ?<0?*=4Q٧$\bChJ0 2lvok_֊g6[3a1QnjP?z;FQ?6)]`?xcd?īEf?`K+ƿe?lw b?G6qX?%%IF?I.V,J2P$I•[nqt&aqA_:ba}[ cQCcqj:4F93?򋫭N??.QW?oA( \?Tt]?0D Z?/BT?pNI?d4-?k641` K kS!`V3 HWF 8T쫯(Os?Bٱ 90A4?XjF?FhP? #ZR?}SR?o^ P?+ G?:ʣUv9?C>Ņ6;E+L^dP%fP(]%M(dnFBp(;9(Em$X&'?s=vPB?]7?9 '?|r>0gICjNIZ".SZvjWc,YeSZJKRFZ `D"Ye!@V50'6SبlN'8/ ֕ ̛?:sDA*?w;1?xd3?%\H4?'W&3?(2?1?J_,?(%&?dC!?3D?Efޖm?My1?V;>I0L>j0Q> OFT>\0^U>3T5"#Ea/Or7pPVtkC]K`?Dxv"E?F쫑@E?%?v~E-!L”)A1,۴6F?R? Y;B?hGXDMO0SD?eIr_?t }X?Z!3l>>a1bn(eaM$?4U 8f?a1bZ!3l>t }X?eIr_?0SD?DMOXhG Y;B?R?,۴6F?”)A1-!Lv~E%?F쫑@E?Dxv"E?]K`?VtkCr7pPa/OT5"#E^U>3\0 OFT>j0Q>vXg>ۨt??$ /H{&? 2?dMz#:?3F]A?s,E?(CsG?λ~G?YD?sjC|9?A9}?uz`R:2t>M~ W֢^OMa^aJaib`R {[#h?Rڏ|Ao~ ?ۓ@?S>H?s=G? ư;?̒^ l5D6rR/KԱWq1XxTmGp_{IL-E?$`T?z6gX?#V?{d@M?@I`Tn!?ŭѴHЈHXO]P`[kL`~4YLt%lFʗ9?.0ۓW?o2a?rd?Qa?wOaS?0MH,>A~(WZâd_t8i;1?g%iXq`ϴA*"J;S?,=6f?L!n?xd o?pD3h?P6,U?YMʈI) 0gmq]s qF+wciꦮ?SHf?IM)C;t?G׉ax?B (w?Wޙ[o?QߠJ!M?dBCBvᇎ#AU~ ~PMM0Ƞwaz]Ixc^+O_?4hrx?oe`e?p}?%BxU?|ׇr?mހ!JHzMuϢө ISF!A~(W0MH,wOaS?Qa?rd?o2a?.0ۓW?ʗ9?Lt%lF~4Y[kL`O]P`ЈHXŭѴH@I`Tn!?{d@M?#V?z6gX?$`T?IL-E?p_{mGxTq1X/KԱW6rRl5D̒^ ư;?s=G?S>H?ۓ@?o~ ?ڏ|A#h?RR {[ib`^aJaOMa֢^~ W2t>Muz`R:A9}?sjC|9?YD?λ~G?(CsG?s,E?3F]A?dMz#:? 2?$ /H{&??ۨt?vXg>n;T?iZg4r?@)2>Kx&5@+ O?u,Ji{@FƋIvMmN?z,Ȍ?txsUPN+a YyZ:??1TBr?\6 0mE񛿐~Ŋ?怂X5?fݕ?ϔ)iH@0B@?PK+ O?LhY*?=ZxލN8n&z!p?_ cw?cw7? AsvkJ _[?&뽼p?u9S?}Eg,dapu }eͼN#H-3?զUSKc?Q:U? G Q*.]_G( 7S6S?. R?9Eh}. BWyTQ8A &@?c-J?=W?-  ,L2=M/T@iZg4r?n;T?j>p|jk?Ȼ%?l˵F3?/0^??F?ۂwL?^MP?UN?%F?IǷ`*? =MSg_?_c]a6e14]c<VQG]DOo[0Q B?lK?/E9F?^UB!?׈pdEj>VJ4V^F8%$s3]1QSfe1!XH?_߾uX?Χ\?W͡U?[)5?q{MzA%`Au?01dGagYlQѷJEV׈pdE^UB!?/E9F?lK?0Q B?o[DO<VQG]14]c]a6e?_cg_MS =IǷ`*?%F?UN?^MP?ۂwL?F?/0^??l˵F3?Ȼ%?p|jk?j>8\4?k;[?3{xLL9|[?9TB`1V?k@?%FoA9i؛yu?Y+ wigj?)R^?5P񀿼 3?^3dタ?Ojn?oNDtOތ?BU¡aQ?sCCv?`򨿽aw?`oG¿]z;?m?]z;?`oG¿aw?`sCCv?aQ?BU¡tOތ?oNDOjn?タ?^3d 3?5P)R^?igj?Y+ w؛yu?%FoA9ik@?1V?9TB`9|[?{xLL3k;[?8\4? 5h;M?B/;??G?l 715?Rf>W ιp΁!Pywsqah=;Md? @[?9Bf]Nn%k-lC]k?ti?R{rz\GQt`)8Y[DP s?ţu?=(b;_n0 YG#j0Xy|?O?ęa`4% WCx #l?"\^ь?W`Qaߥsa,|6M?aLb?ɾrda/8Do>}Y?:՜?T-aS&K@-Z®^NN?,10P?v v?,10P?^NN?-Z®S&K@T-a:՜?Y?o>}/8DɾrdaaLb?6M?,|ߥsaW`Qa"\^ь? #l?WCx4% ęa`O?0Xy|?G#jn0 Y=(b;_ţu?[DP s?`)8YGQtR{rz\ti?]k?-lCNn%k9Bf] @[?Md?ah=;sq΁!Pyw ιpRf>Wl 715??G?B/;? 5h;M?RJ /(("*ZNq0ZZ+0^iN *b ti(?u*ԭ@?kVy-.L?7P0S?Ͳ2V?>U? _P?PVʌ=?a:I6sSIiO^/`!`a.cf>$jTcCW[5 ]>0T S?qvXTjg? Eq?8 s?Qq?L Pf?Un'?n!GhxhI4$a}PUO˳m?;nY?v}?J"u?E?*w?M7 ?\>i?Q9o|g. 횿t.6(!Rbϣ0#\?j? Em"ʭ?"i?%}%?ꏽ?OSVF?OSVF?ꏽ?%}%?"i? Em"ʭ?j?0#\?Rbϣ(!t.6. 횿gQ9o|\>i?M7 ?*w?E?J"u?v}??;nY?PUO˳m}4$ahIxn!GhUn'?L Pf?Qq?8 s? Eq?qvXTjg?0T S?5 ]>CW[f>$jTc!`a.cIiO^/`sSa:I6PVʌ=? _P?>U?Ͳ2V?7P0S?kVy-.L?u*ԭ@?ti(?b ^iN *ZZ+0ZNq0*/((" RJt–>#>:N>Js/n>)/B>S:u.'W݄3@"D;3t@qB2VA{NmL=I6Y2 7(VZ"?~/M4?i9?z:*7?qr({+?\y}۾|,1w/`xx;!4j@ a;%\r`+jyK?a_ 9?AVw^C?foJD?m ~@?>f'9'?"IUl-+%C_CwJzPyJ.[Av#r t=?#N.QM?&eR?'m P?KlA? AY|E\Idu%TbIBW;n]fR9*5=ER)io|? -y?嬙jm?~<94Q0 s:;{Ҷⁿ8mp|L(ѐft>Ff?P ?<|m?KU;/?Sy}?[}OsK?erz3g0|m9sl}5 zD{(ҊKh?&<?ґA|Ŕ?%J?_#E?.s?ǁ'kҸ r~ }墿C:C&ߢqWm9c#i?OTf Ф?`or?Έ5 ? EB?G'?G'? EB?Έ5 ?`or?OTf Ф?c#i?qWm9C:C&ߢ~ }墿Ҹ rǁ'k.s?_#E?%J?ґA|Ŕ?&<?(ҊKh? zD{sl}5|m93g0erz[}OsK?Sy}?KU;/?<|m?P ?t>Ff?L(ѐf8mp|Ҷⁿ:;{4Q0 s~<9嬙jm? -y?>o|?Ogu?Ιc?mCtP tpXZ+v<Su5"+ڂli"cLMJ]?M%n?UN;r?Un?R9\R`?;%BaVj♙k &5lsĻ6e6%3P%7p6I?{ a?ODVUg?HA|e?}Z? fh?1?yDGQhl`&9b~Xq^mNG)?=}QS?./o\?HK{\?8T?ER)if'9'?m ~@?foJD?AVw^C?a_ 9?jyK?%\r`+ a;!4j@`xx;|,1w/\y}۾qr({+?z:*7?i9?~/M4?VZ"? 7(I6Y2{NmL=2VAqB3t@@"D;W݄3.'S:u)/B>Js/n>:N>#>t–> S?;X+ˬ>}^g5;hȈPFsWB'36=I=eB+A?jqO?v.]&x]~S]XIF6V?P ?Q?9n` UR:_O7>lJ?&-f?-#?gxk?'BYTm?@k?#;hDuAY?,a}?p֥n%L?W1#sq?WRu`@?{7ꑋ}JaxAo?t&\? \?^w%K/s[yzL [?M6da?iUA &5 's?b[f?0tb? 琂0sfEO?~)xL?~)xL?O?0sfE 琂0tb?b[f? 's? &5iUAM6da? [?s[yzL^w%K/ \?t&\?Ao?Jax{7ꑋ}WRu`@??#sqW1p֥n%L?,a}?AY?Du#;h@k?Tm??'BYgxk-#?&-f?O7>lJ?R:_9n` UP ?Q?V?]XIF6x]~Sv.]&jqO?=eB+A?B'36=IFsW;hȈP}^g5;X+ˬ> S?MZ1)`Eq_ӝh^jԸd S?#}42s?hNf?R?KEr{4OF0h?d<s?gb}DYHX֞aq?N\ ?ҏ7A qRi4F|5????4F|5?qRi ҏ7AN\ ?aq?DYHX֞gb}d<s?F0h?4O{R?KErhNf?#}42s? S?Ըdӝh^jq_)`EMZ1ǎS?F??R`5?.>5?ַ(?[8$x$&⌿f00?F]݁vUXƸT2?T?F??{i?zW!e 4|꧁?ӊ?R%Je}?UOJzdǒv{`j0ss.?47o^?>u;?׊>}\\b}AfSɭ}GhNYy?y?-d"}0?pD>@?-d"}0?y?hNYy?}G}AfSɭ\\b׊>}>u;?47o^?.?j0ssv{`dǒUOJzR%Je}?;>ӊ?Gf?}I5OПsv1ǃ~@xud R?N5;oN%t?,6]q?!g3?S$p m Yw\ {ms$ 4^:?Ab>>?@?SB?P pC?I5D? [E?nwŽE?Xt6TE?`D?ōCC?\\A? ϼ??љuP:?Gs5?ͨ+?[?]^<'`k"N-2tG;fʊAgp[R3q Nq ;qDtVp'( >oX l%ieۘ(aV} #XzeI\92 ɂnH?VtY?{c?'H:{j?M_p?7rMs?Dw? Qy?/|?C6].~?I?;Ƃ?Pr0K?Z?u*5?HFy?lBy~?~ZۑpM|?,KEx?%Zt?bRMo?Dc?cn{L?5fL P!ofo-\sb̛j|ng6Ⴟղǣ}.֐r_O ;畿cgΑeٚ݋5vlv&&sʠơD«\`^wj(A X`0>ǣwߗKK4{?ߗK>ǣwX`0A j(\`^wD«ơ&&sʠvlv݋5ΑeٚcgO ;畿r_}.֐ǣղng6Ⴟb̛j|o-\s P!of5fLcn{L?Dc?bRMo?%Zt?,KEx?~ZۑpM|?lBy~?HFy?u*5?Z?Pr0K?;Ƃ?I?C6].~?/|? Qy?Dw?7rMs?M_p?'H:{j?{c?VtY?ɂnH?\92 zeIV} #Xۘ(ae%iX l'( >oDtVp ;q Nq[R3qc/>p} zxp'Cne.k5Km#iPf!ୱbBt^TI >?{>:?Ƭ&5?d⌺n1??h/)?Ys $ ?#N! ?#f rd.%.l}3\v7?)%0rխ w큾f3?#7?HA6?/c,?HA6?#7?f3? w큾'>խ.X|o6M} e?nҝ?᥄? #rT{3^IQ LyQp?M̍?o'? =&?́BhR.7˓sҾBe1d?{??Ix?^wX?Ҁ@Qi_b tKEj`Ws ?{ĝf?j?m]Y? JGqOy`KxX^Ez= J=S?X±a?X^2b?;Z?`<I?Sޱ8 ?ӎܼ%pRb){ 4"H">#?L:h$?E}r,?^Y~Q,??k)?KuN$E]@蘃I]ONXIDI-9Ұ)? uǖ? ȲM?4窮4?-B}dTFw0aS+UҾ9W )#& I?g=Z?" X?oa0Xs?(( z?"n}q?EjcnP}5nyW^Bdl/Ws#O{_?oRՀ?L:0Xs?FW8? 'jNٱn..NuF&44%mSQ^?GG}j?ddKq?$e?824 yff"[k9%`n%du:?Ს}b?L*^e?[5W?T$㓧N=;r=^짪X`XQoa ȲM?u$hM?6t}9?]vw34jHHHE~8 ?=? uǖ?$@$@۬flibgcc_s_dw2-1.dll__register_frame_infolibgcj-11.dll_Jv_RegisterClasses__deregister_frame_infoiiididdiidsiFailed to initialize Winsock (WSAStartup)Failed to connect to UDP %s port 0x%XCapture from UDP %s port 0x%XFailed to open socketssidmax_record_minutesOOiFilter I is not a sequenceFilter Q is not a sequenceThe size of filters I and Q must be equalFilter size must be less than %dFailure in quisk.c in integer decimation~:f;f =f>f?f8@f>fBfBfCfOOiiiilrx_udp_clockagc_max_gainagc_off_gainThe sound device is closed.iiiiisisiiiiiiiiissiiissiiiidsiplayback_ratemic_preemphasismic_clipDFT input data is not a sequenceDFT input data is not a complex/float/int numberO|idindex %.5f fdecim %.8f Skip at %.2f Failure in quisk.c in integer interpolation_quiskPy_InitModule of _quisk failed!quisk.errorerror_quisk.QUISK_C_APIQUISK_C_APIadd_toneAdd a test tone to the data.dftCalculate the discrete Fourier transform.idftCalculate the inverse discrete Fourier transform.is_key_downCheck whether the key is down; return 0 or 1.get_stateReturn a count of read and write errors.get_graphReturn a tuple of graph data.get_filterReturn the frequency response of the receive filter.get_filter_rateReturn the sample rate used for the filters.get_tx_filterReturn the frequency response of the transmit filter.get_audio_graphReturn a tuple of the audio graph data.measure_frequencySet the method, return the measured frequency.get_overrangeReturn the count of overrange (clip) for the ADC.get_smeterReturn the S meter reading.invert_spectrumInvert the input RF spectrumrecord_appSave the App instance.record_graphRecord graph parameters.set_ampl_phaseSet the sound card amplitude and phase corrections.set_agcSet the AGC parameters.set_squelchSet the squelch parameter.get_squelchGet the squelch state, 0 or 1.set_file_recordSet the state and names of the recording files.set_filtersSet the receive audio I and Q channel filters.set_auto_notchSet the auto notch on or off.set_noise_blankerSet the noise blanker level.set_record_stateSet the temp buffer record and playback state.set_rx_modeSet the receive mode: CWL, USB, AM, etc.set_spot_levelSet the spot mode: 0, 1, ... or -1 for no spotset_sidetoneSet the sidetone volume and frequency.set_volumeSet the audio output volume.set_split_rxtxSet split for rx/tx.set_tuneSet the tuning frequency.test_1Test 1 function.test_2Test 2 function.test_3Test 3 function.set_fdxSet full duplex mode; ignore the key status.sound_devicesReturn a list of available sound device names.sound_errorsReturn a list of text strings with sound devices and error countsopen_soundOpen the the soundcard device.close_soundStop the soundcard and release resources.capt_channelsSet the I and Q capture channel numbersplay_channelsSet the I and Q playback channel numbersmicplay_channelsSet the I and Q microphone playback channel numberschange_rateChange to a new sample rateread_soundRead from the soundcard.start_soundStart the soundcard.mixer_setSet microphone mixer parameters such as volume.open_keyOpen access to the state of the key (CW or PTT).open_rx_udpOpen a UDP port for capture.close_rx_udpClose the UDP port used for capture.set_key_downChange the key up/down state for method ""?>@>?DA-DT!@:>B@?cJ!K|?zDMbP?pB?#B ;(\?;Fo@ AN9?[|&M?Gz?`L`jFDHz>A4@H{Gz?? > d, @/~"@ffffff?@@-DT!)@zG?{Gz? @@@V!O{Gzt? Jp/@Mb@?-DT!;G333333@@ffffff?@ư>(ssiii)wbRIFFWAVEfmt factdataptimer: %d counts in %d microseconds %.3f counts/sec The sound device is closed.digital_input_namedigital_output_namedigital_output_levelchannel_delaytx_channel_delayddiiiCapture radio samplesCapture microphone samplesCapture digital Tx samplesPlay radio soundPlay microphone soundPlay digital mode soundisA>$tI?-DT!{Gzt?Fư>?C-DT! @DirectSound play device name %s not foundDirectSound play device %s open failedDirectSound play device %s cooperative level failedDirectSound play device %s buffer create failed (0x%X)DirectSound capture device name %s not foundDirectSound capture device %s open failedDirectSound capture device %s buffer create failed (0x%lX)DirectSound capture device %s capture start failed8q8qKffffff?7ASend socket returned %d ffff(f~fffffVfjffmodulation_indexmic_max_gainmic_avg_gainiFF?@ư>{Gz? A @?ș@-DT!@?333333?Hz>?4@?>zDB%12.6lf %9.3lf %9.3lf %s %12.6lf %9.3lf %9.3lf %12.6lf %9.3lf %s %12.6lf %9.3lf _Hz>zDRw> ]GH=?@Vb܀f6k?|}^ _|?Z wɨ?I<'??Rw> ]GH=?@Vb܀f6k?|}^ _|?Z wɨ?I<'??-DT!@?<'?Iwɨ?Z ^ _|?|}b܀f6k?@VGH=?Rw> ]MbP?mingwm10.dll__mingwthr_remove_key_dtor__mingwthr_key_dtor@άfMingw runtime failure: VirtualQuery failed for %d bytes at address %p Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. AAQ2(,0{{=_quisk.pydinit_quisk$t@DT|DH4pT4HXp(<Rbr*<Pft  8FT^frz$>Zr&.4:DNV^fnx ,<HXl4HXp(<Rbr*<Pft  8FT^frz$>Zr&.4:DNV^fnx ,<HXlPyArg_ParseTuple@PyCapsule_NewdPyComplex_AsCComplexePyComplex_FromCComplexfPyComplex_FromDoublesiPyComplex_TypePyErr_ClearPyErr_NewExceptionPyErr_OccurredPyErr_SetStringPyEval_RestoreThreadPyEval_SaveThreadPyFloat_AsDoublePyFloat_FromDoublePyFloat_TypeLPyInt_AsLongOPyInt_AsUnsignedLongMaskRPyInt_FromLong`PyList_AppendfPyList_NewhPyList_SetItemPyModule_AddObject PyObject_GetAttrStringPPySequence_CheckWPySequence_GetItembPySequence_SizewPyString_AsStringPyString_FromStringPyTuple_NewPyTuple_SetItemPyType_IsSubtype6Py_BuildValueVPy_InitModule4_Py_NoneStructDirectSoundCaptureCreate8DirectSoundCaptureEnumerateADirectSoundCreate8DirectSoundEnumerateAWSACleanupTWSAStartupconnecthtonsinet_addrrecvselectsendsetsockoptshutdownsocketDeleteCriticalSectionEnterCriticalSection`FreeLibraryGetLastErrorGetModuleHandleAAGetProcAddressuGetSystemTimeAsFileTimeInitializeCriticalSection.LeaveCriticalSection1LoadLibraryAQueryPerformanceCounterQueryPerformanceFrequencySleepTlsGetValueVirtualProtectVirtualQuery_cabs_close8__dllonexit_errno_snprintfqatan2{cosexpfclosefflushfloorfopenfreefseekfwritelog10mallocmemmoveprintfputsreallocsprintfstrncpystrstrtan _iob_winmajorGabortScallocmemcpysinvfprintffftw_destroy_planfftw_executefftw_freefftw_mallocfftw_plan_dft_1dfftw_plan_dft_c2r_1dfftw_plan_dft_r2c_1dpython27.dlldsound.dll(((((((((((WS2_32.dll<<<<<<<<<<<<<<<<KERNEL32.dllPPmsvcrt.dlldddddddddddddddddddddddmsvcr90.dllxxxxxxxmsvcrt.dlllibfftw3-3.dll@άfάfffff 00=0E0i0s0000/1<1A11111112$2E2W2m2222343b3s3}333333333304O4k4s4{44444444444455)555>5W5c5l555555555556 66/676C6L6e6m6y666666666666777757=7I7R7k7w7777777718U8q888888888959R9999999999$:,:a:j:s::::;;$;Z;f;;;;<*<5<]<<==,=F=l======>>%>U>a>>>>>>> ??$?@?L?d????????? 0 000>0U0]0j0q00000000000011101:1D1N1X1b1k1{11112222)2:2C2L2y2222233'3,373H3X333333344$4T4_4444455 5%5?5F5M5T5f5m5t5|55555555555556#6/656I6R6W6\6p6w6666667 77!7'7,7>7L7W7z77777777778868O8W8c8q888888899%959;9E9O9Y9c9o9{9999999999999::0:=:B:K:a:n:s:|::::::;;.;9;D;O;y;;;;%<*I>>>>>>)?;?R?f?n?t????0 0"030K0\0t000000011)1A1R1v111w2222363]3x33334I44445-5c55556H6s66667I7u7778#8G8k888899)9C9M9e9o999999999:::[:`:f:s:z::::::Q;Z;;;;;;;<9<<<<<=====b===> >%>D>i>>>?#?(?C?????@0C0H0c000011I1O1U1[1f1z11112 2|2223 3{3333333333333334 44"4'4,424F4M4X4a4q4v444444444444 555595E5Q5Y5v555555555556 666$6/6@6Q6a6g6|666666666 7p777777788898E8U8Z8`8m88888889)929@9I99999:_:::;4;E;N;s;;;;;<<<6<><>F>O>x>>>>>>>>??>?G?{??P:000001 1+1{11111112222B2{22222222222222223330363?3L3U3d3}3333333#4,494B4K4T4]4f4o4x44444444444445 55535;5C5Y5e5s5y55555555556 6;6V6q6|666666777777K7X7j7s7z77777777777888*8\8s888888899.9;9S9z99999999 :::M:}:::::::::: ;\;;;;;<<<$!>'>X>>>>> ???%?+?1?F?L?R?k?q?w??????????`90?0E0K0i0t0~0000000121811111111222222223 3344#4)41474=4^4j4p4{44444444444555)5666666 73797L7R7^7r7}7777m8s8y88888888999)9R9[9d9::&:::?:I:|::::::; ;";(;V;\;;;;<<$=S=^=d=o============ >>>>>%>*>0>5>;>@>F>K>Q>V>\>a>g>l>r>w>}>>>>>>>>> ??$?Q?{???pT0 0$0*0R00000001g1m1111111122&2:2o222222223 33 3.34393A3s3y33333333333444#4,474[4a4{4444444444 555 5&5n5x55555556 6-666666J777777888Q9$:9:E:K:Q:`:e:t:::::::::::; ;;;/;5;;;;;;;;;;<<<%<.0>K>U>p>>>>>> ?G?n????? 0+0F0W0y0000000000 1>1O1111111222222222393C3^3o33333 444[4|444444455'5.5C5P5Z555556Z6h6~666666677&7.7?7D7O7_7i7|7777777777777888%8A8M8e8w888888888889 99(939?9E9]9h9s9|99999999999::.:?:I:W:`:f:q:x:::::::::::;B;H;V;`;;;;;;;;;< <<1&>->>>L>p>|>>>>>>? ???&?1?6?A?Z?h????????0000/0B0I0^0e0z000000000000011$1+1@1G1Q1V1[1`1e1j1o1t1y1~1111111111 222 2&20292C2M2W2a2k2222222222222223'3-373A3K3T3p3w3333333333 444&414:4B4G4L4Q4V4[4`4e4l4q4v4{4444444445*5n55555555555666#6,6F6R6c6j6q6{666666666667;7X7e7q7z777889D9}999999::E::::::;;&;F;c;r; >">)>>>E>R>]>o>x>>>>>>>>>>>?.?C?K?Q?[?c??????????L00Q0000 11,161J1W1c11112/2;2H2T2s2|2222233C3[3a3~334J44444445U5f5|5555555 66636S6666(70757<7a7f7k7q777777 8*8P8Z88888889;999999:::$:*:5:@:F:U:[::::;&;:;H;;;;;;;;;;<*->3>D>S>^>r>x>>>>>>>>>>>??<0H0^0077778'8=8O8a8s8889-9<9K9Z9i9O:s:I;};;< <&<,<\W>`>>>>>>>>>>>>?9?C?X?g?w?}??????0011$121:1D1N1W1~111111Y22222222383D3i3{33344414;4S4x4444445:5L5R5_57::";*;2;:;B;J;R;Z;b;j;r;z;;;;;;;;;;;;P00 0000 0$0,00040<0@0D0L0P0T0\0`0d0l0p0t0|000000000000000000000000011 1111 1$1,10141<1@1D1L1P1T1\1`1d1l1p1t1|111111111111111111111111122 2222 2$2,20242<2@2D2L2P2T2\2`2d2l2p2t2|222222222222222222222222233 3333@3D3H3L3P3T3X3\3333333@ @;P1111111111`$22222222222225 00 000 0.eh_framequisk-3.6.11/sound.c0000666000175000017500000005406312121126163013621 0ustar jimjim00000000000000/* * Sound modules that do not depend on alsa or portaudio */ #include #include #include #include #include #include "quisk.h" #include "filter.h" // Thanks to Franco Spinelli for this fix: // The H101 hardware using the PCM2904 chip has a one-sample delay between // channels that must be fixed in software. If you have this problem, // set channel_delay in your config file. The FIX_H101 #define is obsolete // but still works. It is equivalent to channel_delay = channel_q. // The structure sound_dev represents a sound device to open. If portaudio_index // is -1, it is an ALSA sound device; otherwise it is a portaudio device with that // index. Portaudio devices have names that start with "portaudio". A device name // can be the null string, meaning the device should not be opened. The sound_dev // "handle" is either an alsa handle or a portaudio stream if the stream is open; // otherwise it is NULL for a closed device. // This sends the microphone samples to the FFT instead of the radio samples. #define DEBUG_MIC 0 #if DEBUG_IO static int debug_timer = 1; // count up number of samples #endif static struct sound_dev Capture, Playback, MicCapture, MicPlayback, DigitalInput, DigitalOutput; // These are arrays of all capture and playback devices, and MUST end with NULL: static struct sound_dev * CaptureDevices[] = {&Capture, &MicCapture, &DigitalInput, NULL}; static struct sound_dev * PlaybackDevices[] = {&Playback, &MicPlayback, &DigitalOutput, NULL}; struct sound_conf quisk_sound_state; // Current sound status static char file_name_audio[QUISK_PATH_SIZE]; // file name for recording speaker output static char file_name_samples[QUISK_PATH_SIZE]; // file name for recording samples static int is_recording_audio; static int is_recording_samples; static int want_record; static double digital_output_level = 0.7; static ty_sample_start pt_sample_start; static ty_sample_stop pt_sample_stop; static ty_sample_read pt_sample_read; static complex cSamples[SAMP_BUFFER_SIZE]; // Complex buffer for samples void ptimer(int counts) // used for debugging { // print the number of counts per second static unsigned int calls=0, total=0; static time_t time0=0; time_t dt; if (time0 == 0) { time0 = (int)(QuiskTimeSec() * 1.e6); return; } total += counts; calls++; if (calls % 1000 == 0) { dt = (int)(QuiskTimeSec() * 1.e6) - time0; printf("ptimer: %d counts in %d microseconds %.3f counts/sec\n", total, (unsigned)dt, (double)total * 1E6 / dt); } } static void delay_sample (struct sound_dev * dev, double * dSamp, int nSamples) { // Delay the I or Q data stream by one sample. // cSamples is double D[nSamples][2] double d; double * first, * last; if (nSamples < 1) return; if (dev->channel_Delay == dev->channel_I) { first = dSamp; last = dSamp + nSamples * 2 - 2; } else if (dev->channel_Delay == dev->channel_Q) { first = dSamp + 1; last = dSamp + nSamples * 2 - 1; } else { return; } d = dev->save_sample; dev->save_sample = *last; while (--nSamples) { *last = *(last - 2); last -= 2; } *first = d; } static void correct_sample (struct sound_dev * dev, complex * cSamples, int nSamples) { // Correct the amplitude and phase int i; double re, im; if (dev->doAmplPhase) { // amplitude and phase corrections for (i = 0; i < nSamples; i++) { re = creal(cSamples[i]); im = cimag(cSamples[i]); re = re * dev->AmPhAAAA; im = re * dev->AmPhCCCC + im * dev->AmPhDDDD; cSamples[i] = re + I * im; } } } static int record_audio(complex * cSamples, int nSamples) { // Record the speaker audio to a WAV file, PCM, 16 bits, one channel static FILE * fp = NULL; // TODO: correct for big-endian byte order static unsigned int samples=0, remain=0; int j; short samp; // must be 2 bytes unsigned int u; // must be 4 bytes unsigned short s; // must be 2 bytes switch (nSamples) { case -1: // Open the file fp = fopen(file_name_audio, "wb"); if ( ! fp) return 0; if (fwrite("RIFF", 1, 4, fp) != 4) { fclose(fp); fp = NULL; return 0; } // pcm data, 16-bit samples, one channel u = 36; fwrite(&u, 4, 1, fp); fwrite("WAVE", 1, 4, fp); fwrite("fmt ", 1, 4, fp); u = 16; fwrite(&u, 4, 1, fp); s = 1; // wave_format_pcm fwrite(&s, 2, 1, fp); s = 1; // number of channels fwrite(&s, 2, 1, fp); u = Playback.sample_rate; // sample rate fwrite(&u, 4, 1, fp); u *= 2; fwrite(&u, 4, 1, fp); s = 2; fwrite(&s, 2, 1, fp); s = 16; fwrite(&s, 2, 1, fp); fwrite("data", 1, 4, fp); u = 0; fwrite(&u, 4, 1, fp); samples = 0; remain = 2147483000; break; case -2: // close the file if (fp) fclose(fp); fp = NULL; remain = 0; break; default: // write the sound data to the file u = (unsigned int)nSamples; if (u >= remain) return 0; samples += u; remain -= u; fseek(fp, 40, SEEK_SET); // seek from the beginning u = 2 * samples; fwrite(&u, 4, 1, fp); fseek(fp, 4, SEEK_SET); // seek from the beginning u += 36; fwrite(&u, 4, 1, fp); fseek(fp, 0, SEEK_END); // seek to the end for (j = 0; j < nSamples; j++) { samp = (short)(creal(cSamples[j]) / 65536.0); fwrite(&samp, 2, 1, fp); } break; } return 1; } static int record_samples(complex * cSamples, int nSamples) { // Record the samples to a WAV file, two float samples I/Q static FILE * fp = NULL; // TODO: correct for big-endian byte order static unsigned int samples=0, remain=0; int j; float samp; // must be 4 bytes unsigned int u; // must be 4 bytes unsigned short s; // must be 2 bytes switch (nSamples) { case -1: // Open the file fp = fopen(file_name_samples, "wb"); if ( ! fp) return 0; if (fwrite("RIFF", 1, 4, fp) != 4) { fclose(fp); fp = NULL; return 0; } // IEEE float data, two channels u = 50; fwrite(&u, 4, 1, fp); fwrite("WAVE", 1, 4, fp); fwrite("fmt ", 1, 4, fp); u = 18; fwrite(&u, 4, 1, fp); s = 3; // wave_format_ieee_float fwrite(&s, 2, 1, fp); s = 2; // number of channels fwrite(&s, 2, 1, fp); u = quisk_sound_state.sample_rate; // sample rate fwrite(&u, 4, 1, fp); u *= 8; fwrite(&u, 4, 1, fp); s = 8; fwrite(&s, 2, 1, fp); s = 32; fwrite(&s, 2, 1, fp); s = 0; fwrite(&s, 2, 1, fp); fwrite("fact", 1, 4, fp); u = 4; fwrite(&u, 4, 1, fp); u = 0; fwrite(&u, 4, 1, fp); fwrite("data", 1, 4, fp); u = 0; fwrite(&u, 4, 1, fp); samples = 0; remain = 536870000; break; case -2: // close the file if (fp) fclose(fp); fp = NULL; remain = 0; break; default: // write the sound data to the file u = (unsigned int)nSamples; if (u >= remain) return 0; samples += u; remain -= u; fseek(fp, 54, SEEK_SET); // seek from the beginning u = 8 * samples; fwrite(&u, 4, 1, fp); fseek(fp, 4, SEEK_SET); // seek from the beginning u += 50 ; fwrite(&u, 4, 1, fp); fseek(fp, 46, SEEK_SET); // seek from the beginning u = samples * 2; fwrite(&u, 4, 1, fp); fseek(fp, 0, SEEK_END); // seek to the end for (j = 0; j < nSamples; j++) { samp = creal(cSamples[j]) / CLIP32; fwrite(&samp, 4, 1, fp); samp = cimag(cSamples[j]) / CLIP32; fwrite(&samp, 4, 1, fp); } break; } return 1; } void quisk_sample_source(ty_sample_start start, ty_sample_stop stop, ty_sample_read read) { pt_sample_start = start; pt_sample_stop = stop; pt_sample_read = read; } int quisk_read_sound(void) // Called from sound thread { // called in an infinite loop by the main program int i, nSamples, mic_count, mic_interp, retval, is_cw, mic_sample_rate; complex tx_mic_phase; static double cwEnvelope=0; static double cwCount=0; static complex tuneVector = (double)CLIP32 / CLIP16; // Convert 16-bit to 32-bit samples static struct quisk_cFilter filtInterp={NULL}; quisk_sound_state.interupts++; #if DEBUG_IO > 1 QuiskPrintTime("Start read_sound", 0); #endif if (pt_sample_read) { // read samples from SDR-IQ nSamples = (*pt_sample_read)(cSamples); } else if (quisk_using_udp) { // read samples from UDP port nSamples = quisk_read_rx_udp(cSamples); } else if (Capture.handle) { // blocking read from soundcard if (Capture.portaudio_index < 0) nSamples = quisk_read_alsa(&Capture, cSamples); else nSamples = quisk_read_portaudio(&Capture, cSamples); if (Capture.channel_Delay >= 0) // delay the I or Q channel by one sample delay_sample(&Capture, (double *)cSamples, nSamples); if (Capture.doAmplPhase) // amplitude and phase corrections correct_sample(&Capture, cSamples, nSamples); } else { nSamples = 0; } retval = nSamples; // retval remains the number of samples read #if DEBUG_IO debug_timer += nSamples; if (debug_timer >= quisk_sound_state.sample_rate) // one second debug_timer = 0; #endif #if DEBUG_IO > 2 ptimer (nSamples); #endif quisk_sound_state.latencyCapt = nSamples; // samples available #if DEBUG_IO > 1 QuiskPrintTime(" read samples", 0); #endif // Perhaps record the samples to a file if (want_record) { if (is_recording_samples) { record_samples(cSamples, nSamples); // Record samples } else if (file_name_samples[0]) { if (record_samples(NULL, -1)) // Open file is_recording_samples = 1; } } else if (is_recording_samples) { record_samples(NULL, -2); // Close file is_recording_samples = 0; } #if ! DEBUG_MIC nSamples = quisk_process_samples(cSamples, nSamples); #endif #if DEBUG_IO > 1 QuiskPrintTime(" process samples", 0); #endif if (Playback.portaudio_index < 0) quisk_play_alsa(&Playback, nSamples, cSamples, 1, quisk_audioVolume); else quisk_play_portaudio(&Playback, nSamples, cSamples, 1, quisk_audioVolume); if (rxMode == 7 || rxMode == 8 || rxMode == 9) { if (DigitalOutput.portaudio_index < 0) quisk_play_alsa(&DigitalOutput, nSamples, cSamples, 0, digital_output_level); else quisk_play_portaudio(&DigitalOutput, nSamples, cSamples, 0, digital_output_level); } // Perhaps record the speaker audio to a file if (want_record) { if (is_recording_audio) { record_audio(cSamples, nSamples); // Record samples } else if (file_name_audio[0]) { if (record_audio(NULL, -1)) // Open file is_recording_audio = 1; } } else if (is_recording_audio) { record_audio(NULL, -2); // Close file is_recording_audio = 0; } #if DEBUG_IO > 1 QuiskPrintTime(" play samples", 0); #endif // Read and process the microphone mic_count = 0; mic_sample_rate = quisk_sound_state.mic_sample_rate; if (MicCapture.handle) { if (MicCapture.portaudio_index < 0) mic_count = quisk_read_alsa(&MicCapture, cSamples); else mic_count = quisk_read_portaudio(&MicCapture, cSamples); } if (quisk_record_state == PLAYBACK) { // Discard previous samples and replace with saved sound quisk_tmp_microphone(cSamples, mic_count); } if (rxMode == 7 || rxMode == 8 || rxMode == 9) { // Discard previous samples and use digital samples if (DigitalInput.handle) { mic_sample_rate = DigitalInput.sample_rate; if (DigitalInput.portaudio_index < 0) mic_count = quisk_read_alsa(&DigitalInput, cSamples); else mic_count = quisk_read_portaudio(&DigitalInput, cSamples); } else { mic_count = 0; } } if (mic_count > 0) { #if DEBUG_IO > 1 QuiskPrintTime(" mic-read", 0); #endif // quisk_process_microphone returns samples at the sample rate MIC_OUT_RATE mic_count = quisk_process_microphone(mic_sample_rate, cSamples, mic_count); #if DEBUG_MIC == 1 if ( ! quisk_is_key_down()) for (i = 0; i < mic_count; i++) cSamples[i] = 0; for (i = 0; i < mic_count; i++) cSamples[i] *= (double)CLIP32 / CLIP16; // convert 16-bit samples to 32 bits quisk_process_samples(cSamples, mic_count); #endif #if DEBUG_IO > 1 QuiskPrintTime(" mic-proc", 0); #endif } // Mic playback without a mic is needed for CW if (MicPlayback.handle) { // Mic playback: send mic I/Q samples to a sound card if (rxMode == 0 || rxMode == 1) { // Transmit CW is_cw = 1; } else { is_cw = 0; cwCount = 0; cwEnvelope = 0.0; } tx_mic_phase = cexp(( -I * 2.0 * M_PI * quisk_tx_tune_freq) / MicPlayback.sample_rate); if (is_cw) { // Transmit CW; use capture device for timing, not microphone cwCount += (double)retval * MicPlayback.sample_rate / quisk_sound_state.sample_rate; mic_count = 0; if (quisk_is_key_down()) { while (cwCount >= 1.0) { if (cwEnvelope < 1.0) { cwEnvelope += 1. / (MicPlayback.sample_rate * 5e-3); // 5 milliseconds if (cwEnvelope > 1.0) cwEnvelope = 1.0; } cSamples[mic_count++] = (CLIP16 - 1) * cwEnvelope * tuneVector * quisk_sound_state.mic_out_volume; tuneVector *= tx_mic_phase; cwCount -= 1; } } else { // key is up while (cwCount >= 1.0) { if (cwEnvelope > 0.0) { cwEnvelope -= 1.0 / (MicPlayback.sample_rate * 5e-3); // 5 milliseconds if (cwEnvelope < 0.0) cwEnvelope = 0.0; } cSamples[mic_count++] = (CLIP16 - 1) * cwEnvelope * tuneVector * quisk_sound_state.mic_out_volume; tuneVector *= tx_mic_phase; cwCount -= 1; } } } else { // Transmit SSB if ( ! quisk_is_key_down()) { for (i = 0; i < mic_count; i++) cSamples[i] = 0.0; } } // Perhaps interpolate the mic samples back to the mic play rate mic_interp = MicPlayback.sample_rate / MIC_OUT_RATE; if ( ! is_cw && mic_interp > 1) { if (! filtInterp.dCoefs) quisk_filt_cInit(&filtInterp, quiskFilt12_19Coefs, sizeof(quiskFilt12_19Coefs)/sizeof(double)); mic_count = quisk_cInterpolate(cSamples, mic_count, &filtInterp, mic_interp); } // Tune the samples to frequency if ( ! is_cw) { for (i = 0; i < mic_count; i++) { cSamples[i] = conj(cSamples[i]) * tuneVector * quisk_sound_state.mic_out_volume; tuneVector *= tx_mic_phase; } } // delay the I or Q channel by one sample if (MicPlayback.channel_Delay >= 0) delay_sample(&MicPlayback, (double *)cSamples, mic_count); // amplitude and phase corrections if (MicPlayback.doAmplPhase) correct_sample (&MicPlayback, cSamples, mic_count); // play mic samples if (MicPlayback.portaudio_index < 0) quisk_play_alsa(&MicPlayback, mic_count, cSamples, 0, 1.0); else quisk_play_portaudio(&MicPlayback, mic_count, cSamples, 0, 1.0); #if DEBUG_MIC == 2 quisk_process_samples(cSamples, mic_count); #endif } #if DEBUG_IO > 1 QuiskPrintTime(" finished", 0); #endif // Return negative number for error return retval; } int quisk_get_overrange(void) // Called from GUI thread { // Return the overrange (ADC clip) counter, then zero it int i; i = quisk_sound_state.overrange + Capture.overrange; quisk_sound_state.overrange = 0; Capture.overrange = 0; return i; } void quisk_close_sound(void) // Called from sound thread { if (pt_sample_stop) (*pt_sample_stop)(); quisk_close_sound_portaudio(); quisk_close_sound_alsa(CaptureDevices, PlaybackDevices); strncpy (quisk_sound_state.err_msg, CLOSED_TEXT, QUISK_SC_SIZE); } static void set_num_channels(struct sound_dev * dev) { // Set num_channels to the maximum channel index plus one dev->num_channels = dev->channel_I; if (dev->num_channels < dev->channel_Q) dev->num_channels = dev->channel_Q; dev->num_channels++; } void quisk_open_sound(void) // Called from GUI thread { int i; quisk_sound_state.read_error = 0; quisk_sound_state.write_error = 0; quisk_sound_state.underrun_error = 0; quisk_sound_state.mic_read_error = 0; quisk_sound_state.interupts = 0; quisk_sound_state.rate_min = quisk_sound_state.rate_max = -99; quisk_sound_state.chan_min = quisk_sound_state.chan_max = -99; quisk_sound_state.msg1[0] = 0; quisk_sound_state.err_msg[0] = 0; strncpy(Capture.name, quisk_sound_state.dev_capt_name, QUISK_SC_SIZE); strncpy(Playback.name, quisk_sound_state.dev_play_name, QUISK_SC_SIZE); strncpy(MicCapture.name, quisk_sound_state.mic_dev_name, QUISK_SC_SIZE); strncpy(MicPlayback.name, quisk_sound_state.name_of_mic_play, QUISK_SC_SIZE); Playback.sample_rate = quisk_sound_state.playback_rate; // Radio sound play rate MicPlayback.sample_rate = quisk_sound_state.mic_playback_rate; MicCapture.sample_rate = quisk_sound_state.mic_sample_rate; MicCapture.channel_I = quisk_sound_state.mic_channel_I; // Mic audio is here MicCapture.channel_Q = quisk_sound_state.mic_channel_Q; // Capture device for digital modes strncpy(DigitalInput.name, QuiskGetConfigString ("digital_input_name", ""), QUISK_SC_SIZE); DigitalInput.sample_rate = 48000; DigitalInput.channel_I = 0; DigitalInput.channel_Q = 1; // Playback device for digital modes strncpy(DigitalOutput.name, QuiskGetConfigString ("digital_output_name", ""), QUISK_SC_SIZE); digital_output_level = QuiskGetConfigDouble("digital_output_level", 0.7); DigitalOutput.sample_rate = quisk_sound_state.playback_rate; // Radio sound play rate DigitalOutput.channel_I = 0; DigitalOutput.channel_Q = 1; set_num_channels (&Capture); set_num_channels (&Playback); set_num_channels (&MicCapture); set_num_channels (&MicPlayback); set_num_channels (&DigitalInput); set_num_channels (&DigitalOutput); #ifdef FIX_H101 Capture.channel_Delay = Capture.channel_Q; // Obsolete; do not use. #else Capture.channel_Delay = QuiskGetConfigInt ("channel_delay", -1); #endif MicPlayback.channel_Delay = QuiskGetConfigInt ("tx_channel_delay", -1); if (pt_sample_read) { // capture from SDR-IQ by Rf-Space Capture.name[0] = 0; // zero the capture soundcard name } else if (quisk_using_udp) { // samples from UDP at multiple of 48 kHz Capture.name[0] = 0; // zero the capture soundcard name } else { // sound card capture Capture.sample_rate = quisk_sound_state.sample_rate; } // set read size for sound card capture i = (int)(quisk_sound_state.data_poll_usec * 1e-6 * Capture.sample_rate + 0.5); i = i / 64 * 64; if (i > SAMP_BUFFER_SIZE / Capture.num_channels) // limit to buffer size i = SAMP_BUFFER_SIZE / Capture.num_channels; Capture.read_frames = i; MicCapture.read_frames = 0; // Use non-blocking read for microphone Playback.read_frames = 0; MicPlayback.read_frames = 0; // set sound card play latency Playback.latency_frames = Playback.sample_rate * quisk_sound_state.latency_millisecs / 1000; MicPlayback.latency_frames = MicPlayback.sample_rate * quisk_sound_state.latency_millisecs / 1000; Capture.latency_frames = 0; MicCapture.latency_frames = 0; // set capture and playback for digital modes DigitalInput.read_frames = 0; // Use non-blocking read DigitalInput.latency_frames = 0; DigitalOutput.read_frames = 0; DigitalOutput.latency_frames = DigitalOutput.sample_rate * 500 / 1000; // 500 milliseconds #if DEBUG_IO printf("Sample buffer size %d, latency msec %d\n", SAMP_BUFFER_SIZE, quisk_sound_state.latency_millisecs); #endif } void quisk_start_sound(void) // Called from sound thread { if (pt_sample_start) (*pt_sample_start)(); quisk_start_sound_portaudio(CaptureDevices, PlaybackDevices); quisk_start_sound_alsa(CaptureDevices, PlaybackDevices); if (pt_sample_read || quisk_using_udp) { quisk_sound_state.rate_min = Playback.rate_min; quisk_sound_state.rate_max = Playback.rate_max; quisk_sound_state.chan_min = Playback.chan_min; quisk_sound_state.chan_max = Playback.chan_max; } else { quisk_sound_state.rate_min = Capture.rate_min; quisk_sound_state.rate_max = Capture.rate_max; quisk_sound_state.chan_min = Capture.chan_min; quisk_sound_state.chan_max = Capture.chan_max; } } PyObject * quisk_set_ampl_phase(PyObject * self, PyObject * args) // Called from GUI thread { /* Set the sound card amplitude and phase corrections. See S.W. Ellingson, Correcting I-Q Imbalance in Direct Conversion Receivers, February 10, 2003 */ struct sound_dev * dev; double ampl, phase; int is_tx; // Is this for Tx? Otherwise Rx. if (!PyArg_ParseTuple (args, "ddi", &l, &phase, &is_tx)) return NULL; if (is_tx) dev = &MicPlayback; else dev = &Capture; if (ampl == 0.0 && phase == 0.0) { dev->doAmplPhase = 0; } else { dev->doAmplPhase = 1; ampl = ampl + 1.0; // Change factor 0.01 to 1.01 phase = (phase / 360.0) * 2.0 * M_PI; // convert to radians dev->AmPhAAAA = 1.0 / ampl; dev->AmPhCCCC = - dev->AmPhAAAA * tan(phase); dev->AmPhDDDD = 1.0 / cos(phase); } Py_INCREF (Py_None); return Py_None; } PyObject * quisk_capt_channels(PyObject * self, PyObject * args) // Called from GUI thread { if (!PyArg_ParseTuple (args, "ii", &Capture.channel_I, &Capture.channel_Q)) return NULL; Py_INCREF (Py_None); return Py_None; } PyObject * quisk_play_channels(PyObject * self, PyObject * args) // Called from GUI thread { if (!PyArg_ParseTuple (args, "ii", &Playback.channel_I, &Playback.channel_Q)) return NULL; Py_INCREF (Py_None); return Py_None; } PyObject * quisk_micplay_channels(PyObject * self, PyObject * args) // Called from GUI thread { if (!PyArg_ParseTuple (args, "ii", &MicPlayback.channel_I, &MicPlayback.channel_Q)) return NULL; Py_INCREF (Py_None); return Py_None; } static void AddCard(struct sound_dev * dev, PyObject * pylist, const char * txt) { PyObject * v; if (dev->name[0]) { v = Py_BuildValue("(ssiii)", txt, dev->name, dev->sample_rate, dev->dev_latency, dev->dev_error + dev->dev_underrun); PyList_Append(pylist, v); } } PyObject * quisk_sound_errors(PyObject * self, PyObject * args) { // return a list of strings with card names and error counts PyObject * pylist; if (!PyArg_ParseTuple (args, "")) return NULL; pylist = PyList_New(0); AddCard(&Capture, pylist, "Capture radio samples"); AddCard(&MicCapture, pylist, "Capture microphone samples"); AddCard(&DigitalInput, pylist, "Capture digital Tx samples"); AddCard(&Playback, pylist, "Play radio sound"); AddCard(&MicPlayback, pylist, "Play microphone sound"); AddCard(&DigitalOutput, pylist, "Play digital mode sound"); return pylist; } PyObject * quisk_set_file_record(PyObject * self, PyObject * args) // called from GUI { /* set the names of the recording files and the recording state */ const char * name; int which; if (!PyArg_ParseTuple (args, "is", &which, &name)) return NULL; switch (which) { case 0: // change the name of the audio file strncpy(file_name_audio, name, QUISK_PATH_SIZE); break; case 1: // change the name of the sample file strncpy(file_name_samples, name, QUISK_PATH_SIZE); break; case 2: // the record button was pressed want_record = 1; break; case 3: // the record button was un-pressed want_record = 0; break; } Py_INCREF (Py_None); return Py_None; } quisk-3.6.11/Extensions.txt0000644000175000017500000000006411632372222015216 0ustar jimjim00000000000000The information from this file is now in docs.html. quisk-3.6.11/WinQuiskVna.pyw0000666000175000017500000000032511715032273015303 0ustar jimjim00000000000000#!/usr/bin/python import quisk # May be quisk.py or package quisk if quisk.__file__.find('__init__') >= 0: # quisk is the package import quisk.quisk_vna as quisk_vna else: import quisk_vna quisk_vna.main() quisk-3.6.11/quisk_hardware_sdr8600.py0000644000175000017500000000561011641071530017067 0ustar jimjim00000000000000# Please do not change this hardware control module for Quisk. Instead copy # it to your own quisk_hardware.py and make changes there. # See quisk_hardware_model.py for documentation. # # This hardware module sends the IF output of an AOR AR8600 # to the input of an SDR-IQ by RfSpace # # Note: The AR8600 IF output in WFM mode seems to tune in 10kHz increments # no matter what the step size, even though the display reads a # different frequency. import time import _quisk as QS from sdriqpkg import sdriq import serial # From the pyserial package # Use the SDR-IQ hardware as the base class from sdriqpkg import quisk_hardware as SdriqHardware BaseHardware = SdriqHardware.Hardware class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.vfo_frequency = 0 # current vfo frequency self.tty_name = '/dev/ttyUSB0' # serial port name for AR8600 self.serial = None # the open serial port self.timer = 0.02 # time between AR8600 commands in seconds self.time0 = 0 # time of last AR8600 command self.serial_out = [] # send commands slowly def open(self): self.serial = serial.Serial(port=self.tty_name, baudrate=9600, stopbits=serial.STOPBITS_TWO, xonxoff=1, timeout=0) self.SendAR8600('MD0\r') # set WFM mode so the IF output is available # The AR8600 inverts the spectrum of the 2 meter and 70 cm bands. # Other bands may not be inverted, so we may need to test the frequency. # But this is not currently implemented. QS.invert_spectrum(1) t = BaseHardware.open(self) # save the message sdriq.freq_sdriq(10700000) return t def close(self): BaseHardware.close(self) if self.serial: self.serial.write('EX\r') time.sleep(1) # wait for output to drain, but don't block self.serial.close() self.serial = None def ChangeFrequency(self, rx_freq, vfo_freq, source='', band='', event=None): vfo_freq = (vfo_freq + 5000) / 10000 * 10000 # round frequency if vfo_freq != self.vfo_frequency and vfo_freq >= 100000: self.vfo_frequency = vfo_freq self.SendAR8600('RF%010d\r' % vfo_freq) return rx_freq, vfo_freq def ChangeBand(self, band): # Defeat base class method return def SendAR8600(self, msg): # Send commands to the AR8600, but not too fast if self.serial: if time.time() - self.time0 > self.timer: self.serial.write(msg) # send message now self.time0 = time.time() else: self.serial_out.append(msg) # send message later def HeartBeat(self): # Called at about 10 Hz by the main BaseHardware.HeartBeat(self) if self.serial: chars = self.serial.read(1024) #if chars: # print chars if self.serial_out and time.time() - self.time0 > self.timer: self.serial.write(self.serial_out[0]) self.time0 = time.time() del self.serial_out[0] quisk-3.6.11/quisk_conf_win.py0000644000175000017500000000552411632372224015716 0ustar jimjim00000000000000# This is a sample quisk_conf.py configuration file for Microsoft Windows. # For Windows, your default config file name is "My Documents/quisk_conf.py", # but you can use a different config file by using -c or --config. Quisk creates # an initial default config file if there is none. To control Quisk, edit # "My Documents/quisk_conf.py" using any text editor; for example WordPad (not Notepad). # In Windows you can see what sound devices you have, and you can set the Primary # Device for capture and playback by using Control Panel/Sounds and Audio Devices. # If you have only one sound device, it should be set as "Primary". If you have # several, find the names by using Control Panel/Sounds and Audio Devices; for # example, you may have "SoundMAX HD Audio" in the list for "Sound playback" and # "Sound recording". To specify this device for capture (recording) or playback, # enter a unique part of its name using exact upper/lower case. For example: # name_of_sound_capture = "SoundMAX" # name_of_sound_play = "SoundMAX" # There are many possible options for your config file. Copy the ones you want # from the master file quisk_conf_defaults.py (but don't change the master file). # The master config file is located in the site-packages/quisk folder for Python 2.7. # This file is Python code and the comment character is "#". To ignore a line, # start it with "#". To un-ignore a line, remove the "#". Generally you must start # lines in column one (the left edge) except for logic blocks. sample_rate = 48000 # ADC hardware sample rate in Hertz name_of_sound_capt = "Primary" # Name of soundcard capture hardware device. name_of_sound_play = "Primary" # Use the same device for play back. latency_millisecs = 150 # latency time in milliseconds # Select the default screen when Quisk starts: default_screen = 'Graph' #default_screen = 'WFall' # If you use hardware with a fixed VFO (crystal controlled SoftRock) un-comment the following: # import quisk_hardware_fixed as quisk_hardware # fixed_vfo_freq = 7056000 # If you use an SDR-IQ for capture, first install the SpectraView software # that came with the SDR-IQ. This will install the USB driver. Then set these parameters: # import quisk_hardware_sdriq as quisk_hardware # Use different hardware file # use_sdriq = 1 # Capture device is the SDR-IQ # sdriq_name = "SDR-IQ" # Name of the SDR-IQ device to open # sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal) # sdriq_decimation = 500 # Must be 360, 500, 600, or 1250 # sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this # name_of_sound_capt = "" # We do not capture from the soundcard # playback_rate = 48000 # Radio sound play rate, default 48000 # display_fraction = 0.85 # The edges of the full bandwidth are not valid quisk-3.6.11/hiqsdr/0000775000175000017500000000000012164330433013611 5ustar jimjim00000000000000quisk-3.6.11/hiqsdr/quisk_hardware.py0000666000175000017500000003311412126115217017177 0ustar jimjim00000000000000# This is a sample hardware file for UDP control. Use this file for my 2010 transceiver # described in QEX and for the improved version HiQSDR. To turn on the extended # features in HiQSDR, update your FPGA firmware to version 1.1 or later and use use_rx_udp = 2. from __future__ import print_function import struct, socket, math, traceback import _quisk as QS from quisk_hardware_model import Hardware as BaseHardware DEBUG = 0 class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.use_sidetone = 1 self.got_udp_status = '' # status from UDP receiver # want_udp_status is a 14-byte string with numbers in little-endian order: # [0:2] 'St' # [2:6] Rx tune phase # [6:10] Tx tune phase # [10] Tx output level 0 to 255 # [11] Tx control bits: # 0x01 Enable CW transmit # 0x02 Enable all other transmit # 0x04 Use the HiQSDR extended IO pins not present in the 2010 QEX ver 1.0 # 0x08 The key is down (software key) # [12] Rx control bits # Second stage decimation less one, 1-39, six bits # [13] zero or firmware version number # The above is used for firmware version 1.0. # Version 1.1 adds eight more bytes for the HiQSDR conntrol ports: # [14] X1 connector: Preselect pins 69, 68, 65, 64; Preamp pin 63, Tx LED pin 57 # [15] Attenuator pins 84, 83, 82, 81, 80 # [16] More bits: AntSwitch pin 41 is 0x01 # [17:22] The remaining five bytes are sent as zero. # Version 1.2 uses the same format as 1.1, but adds the "Qs" command (see below). # Version 1.3 adds features needed by the new quisk_vna.py program: # [17] This one byte must be zero # [18:20] This is vna_count, the number of VNA data points; or zero for normal operation # [20:22] These two bytes mmust be zero # The "Qs" command is a two-byte UDP packet sent to the control port. It returns the hardware status # as the above string, except that the string starts with "Qs" instead of "St". Do not send the "Qs" command # from Quisk, as it interferes with the "St" command. The "Qs" command is meant to be used from an # external program, such as HamLib or a logging program. # When vna_count != 0, we are in VNA mode. The start frequency is rx_phase, and for each point tx_phase is added # to advance the frequency. A zero sample is added to mark the blocks. The samples are I and Q averaged at DC. self.rx_phase = 0 self.tx_phase = 0 self.tx_level = 0 self.tx_control = 0 self.rx_control = 0 self.vna_count = 0 # VNA scan count; MUST be zero for non-VNA operation self.index = 0 self.mode = None self.band = None self.rf_gain = 0 self.HiQSDR_Connector_X1 = 0 self.HiQSDR_Attenuator = 0 self.HiQSDR_Bits = 0 if conf.use_rx_udp == 2: # Set to 2 for the HiQSDR self.rf_gain_labels = ('RF 0 dB', 'RF +10', 'RF -10', 'RF -20', 'RF -30') self.antenna_labels = ('Ant 1', 'Ant 2') self.firmware_version = None # firmware version is initially unknown self.rx_udp_socket = None self.vfo_frequency = 0 # current vfo frequency self.tx_frequency = 0 self.decimations = [] # supported decimation rates for dec in (40, 20, 10, 8, 5, 4, 2): self.decimations.append(dec * 64) if self.conf.fft_size_multiplier == 0: self.conf.fft_size_multiplier = 7 # Set size needed by VarDecim def open(self): # Create the proper broadcast address for rx_udp_ip. nm = self.conf.rx_udp_ip_netmask.split('.') ip = self.conf.rx_udp_ip.split('.') nm = map(int, nm) ip = map(int, ip) bc = '' for i in range(4): x = (ip[i] | ~ nm[i]) & 0xFF bc = bc + str(x) + '.' self.broadcast_addr = bc[:-1] # This socket is used for the Simple Network Discovery Protocol by AE4JY self.socket_sndp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket_sndp.setblocking(0) self.socket_sndp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.sndp_request = chr(56) + chr(0) + chr(0x5A) + chr(0xA5) + chr(0) * 52 self.sndp_active = self.conf.sndp_active # conf.rx_udp_port is used for returning ADC samples # conf.rx_udp_port + 1 is used for control self.rx_udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.rx_udp_socket.setblocking(0) self.rx_udp_socket.connect((self.conf.rx_udp_ip, self.conf.rx_udp_port + 1)) return QS.open_rx_udp(self.conf.rx_udp_ip, self.conf.rx_udp_port) def close(self): if self.rx_udp_socket: self.rx_udp_socket.close() self.rx_udp_socket = None def ReturnFrequency(self): # Return the current tuning and VFO frequency return None, None # frequencies have not changed def ReturnVfoFloat(self): # Return the accurate VFO as a float return float(self.rx_phase) * self.conf.rx_udp_clock / 2.0**32 def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None): if vfo_freq != self.vfo_frequency: self.vfo_frequency = vfo_freq self.rx_phase = int(float(vfo_freq) / self.conf.rx_udp_clock * 2.0**32 + 0.5) & 0xFFFFFFFF if tx_freq and tx_freq > 0: self.tx_frequency = tx_freq tx = tx_freq self.tx_phase = int(float(tx) / self.conf.rx_udp_clock * 2.0**32 + 0.5) & 0xFFFFFFFF self.NewUdpStatus() return tx_freq, vfo_freq def ChangeMode(self, mode): # mode is a string: "USB", "AM", etc. self.mode = mode self.tx_control &= ~0x03 # Erase last two bits if self.vna_count: pass elif mode in ("CWL", "CWU"): self.tx_control |= 0x01 elif mode in ("USB", "LSB", "AM", "FM"): self.tx_control |= 0x02 elif mode[0:4] == 'DGT-': self.tx_control |= 0x02 elif mode[0:3] == 'IMD': self.tx_control |= 0x02 self.SetTxLevel() def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. self.band = band self.HiQSDR_Connector_X1 &= ~0x0F # Mask in the last four bits self.HiQSDR_Connector_X1 |= self.conf.HiQSDR_BandDict.get(band, 0) & 0x0F self.SetTxLevel() def SetTxLevel(self): # As tx_level varies from 50 to 200, the output level changes from 263 to 752 mV # So 0 to 255 is 100 to 931, or 1.0 to 9.31; v = 1.0 + 0.0326 * level if not self.vna_count: try: self.tx_level = self.conf.tx_level[self.band] except KeyError: self.tx_level = self.conf.tx_level[None] # The default if self.mode[0:4] == 'DGT-': reduc = self.application.digital_tx_level else: reduc = self.application.tx_level if reduc < 100: # reduce power by a percentage level = 1.0 + self.tx_level * 0.0326 level *= math.sqrt(reduc / 100.0) # Convert from a power to an amplitude self.tx_level = int((level - 1.0) / 0.0326 + 0.5) if self.tx_level < 0: self.tx_level = 0 self.NewUdpStatus() def OnButtonRfGain(self, event): # The HiQSDR attenuator is five bits: 2, 4, 8, 10, 20 dB btn = event.GetEventObject() n = btn.index self.HiQSDR_Connector_X1 &= ~0x10 # Mask in the preamp bit if n == 0: # 0dB self.HiQSDR_Attenuator = 0 self.rf_gain = 0 elif n == 1: # +10 self.HiQSDR_Attenuator = 0 self.HiQSDR_Connector_X1 |= 0x10 self.rf_gain = 10 elif n == 2: # -10 self.HiQSDR_Attenuator = 0x08 self.rf_gain = -10 elif n == 3: # -20 self.HiQSDR_Attenuator = 0x10 self.rf_gain = -20 elif n == 4: # -30 self.HiQSDR_Attenuator = 0x18 self.rf_gain = -30 else: self.HiQSDR_Attenuator = 0 self.rf_gain = 0 print ('Unknown RfGain') self.NewUdpStatus() def OnButtonPTT(self, event): # This feature requires firmware version 1.1 or higher if self.firmware_version: btn = event.GetEventObject() if btn.GetValue(): # Turn the software key bit on or off self.tx_control |= 0x08 else: self.tx_control &= ~0x08 self.NewUdpStatus() def OnButtonAntenna(self, event): # This feature requires extended IO btn = event.GetEventObject() if btn.index: self.HiQSDR_Bits |= 0x01 else: self.HiQSDR_Bits &= ~0x01 self.NewUdpStatus() def HeartBeat(self): if self.sndp_active: # AE4JY Simple Network Discovery Protocol - attempt to set the FPGA IP address try: self.socket_sndp.sendto(self.sndp_request, (self.broadcast_addr, 48321)) data = self.socket_sndp.recv(1024) # print(repr(data)) except: # traceback.print_exc() pass else: if len(data) == 56 and data[5:14] == 'HiQSDR-v1': ip = self.conf.rx_udp_ip.split('.') t = (data[0:4] + chr(2) + data[5:37] + chr(int(ip[3])) + chr(int(ip[2])) + chr(int(ip[1])) + chr(int(ip[0])) + chr(0) * 12 + chr(self.conf.rx_udp_port & 0xFF) + chr(self.conf.rx_udp_port >> 8) + chr(0)) # print(repr(t)) self.socket_sndp.sendto(t, (self.broadcast_addr, 48321)) try: # receive the old status if any data = self.rx_udp_socket.recv(1024) if DEBUG: self.PrintStatus(' got ', data) except: pass else: if data[0:2] == 'St': self.got_udp_status = data if self.firmware_version is None: # get the firmware version if self.want_udp_status[0:13] != self.got_udp_status[0:13]: try: self.rx_udp_socket.send(self.want_udp_status) if DEBUG: self.PrintStatus('Start', self.want_udp_status) except: pass else: # We got a correct response. self.firmware_version = ord(self.got_udp_status[13]) # Firmware version is returned here if DEBUG: print ('Got version', self.firmware_version) if self.firmware_version > 0 and self.conf.use_rx_udp == 2: self.tx_control |= 0x04 # Use extra control bytes self.sndp_active = False self.NewUdpStatus() else: if self.want_udp_status != self.got_udp_status: if DEBUG: self.PrintStatus('Have ', self.got_udp_status) self.PrintStatus(' send', self.want_udp_status) try: self.rx_udp_socket.send(self.want_udp_status) except: pass elif DEBUG: self.rx_udp_socket.send('Qs') def PrintStatus(self, msg, string): print (msg, ' ', end=' ') print (string[0:2], end=' ') for c in string[2:]: print ("%2X" % ord(c), end=' ') print () def GetFirmwareVersion(self): return self.firmware_version def OnSpot(self, level): pass def OnBtnFDX(self, is_fdx): # Status of FDX button, 0 or 1 if is_fdx: self.HiQSDR_Connector_X1 |= 0x20 # Mask in the FDX bit else: self.HiQSDR_Connector_X1 &= ~0x20 self.NewUdpStatus() def VarDecimGetChoices(self): # return text labels for the control clock = self.conf.rx_udp_clock l = [] # a list of sample rates for dec in self.decimations: l.append(str(int(float(clock) / dec / 1e3 + 0.5))) return l def VarDecimGetLabel(self): # return a text label for the control return "Sample rate ksps" def VarDecimGetIndex(self): # return the current index return self.index def VarDecimSet(self, index=None): # set decimation, return sample rate if index is None: # initial call to set decimation before the call to open() rate = self.application.vardecim_set # May be None or from different hardware try: dec = int(float(self.conf.rx_udp_clock / rate + 0.5)) self.index = self.decimations.index(dec) except: try: self.index = self.decimations.index(self.conf.rx_udp_decimation) except: self.index = 0 else: self.index = index dec = self.decimations[self.index] self.rx_control = dec / 64 - 1 # Second stage decimation less one self.NewUdpStatus() return int(float(self.conf.rx_udp_clock) / dec + 0.5) def NewUdpStatus(self, do_tx=False): s = "St" s = s + struct.pack(" 0: # Add the extra bytes if self.tx_control & 0x04: # Use extra HiQSDR control bytes s = s + chr(self.HiQSDR_Connector_X1) s = s + chr(self.HiQSDR_Attenuator) s = s + chr(self.HiQSDR_Bits) s = s + chr(0) else: s = s + chr(0) * 4 s = s + struct.pack(" // used by quisk.h #include // Used by quisk.h #include "quisk.h" // This module provides methods to access the state of the key. // First call quisk_open_key(name) to choose a method and initialize. // Subsequent key access uses the method chosen. static int key_is_down = 0; // internal key state #ifdef MS_WINDOWS int quisk_open_key(const char * name) { // Open the hardware key; return 0 for success, else an error code. return 0; } void quisk_close_key(void) { } int quisk_is_key_down(void) { return key_is_down; } void quisk_set_key_down(int state) { // Set the key state internally if (state) key_is_down = 1; else key_is_down = 0; } #else // Not MS Windows: #include #include #include #include #include #include #include #include static int open_key_pport(const char * name); static int open_key_serport(const char * name); static int open_key_enet(const char * name); static void close_key_pport(void); static void close_key_serport(void); static void close_key_enet(void); static int is_key_down_pport(void); static int is_key_down_serport(void); static int is_key_down_enet(void); static enum { // The key access method None, // Return the internal state; default key is always up ParPort, // Use the parallel port SerPort, // Use the serial port Udp // Use UDP Ethernet } key_method = None; static int fd = -1; // File descriptor to read the parallel or serial port static int KEY_PORT = 0x553C; // Ethernet UDP port static int key_socket = -1; // Ethernet socket int quisk_open_key(const char * name) { // Open the hardware key; return 0 for success, else an error code. int ret; if (!name[0]){ // null string means internal key state key_method = None; ret = 0; } else if (!strncmp(name, "/dev/tty", 8)){ // serial port key_method = SerPort; ret = open_key_serport(name); } else if (name[0] == '/'){ // starting '/' means parallel port name key_method = ParPort; ret = open_key_pport(name); } else if (isdigit(name[0])){ // IP address key_method = Udp; ret = open_key_enet(name); } else { ret = 5; } return ret; } void quisk_close_key(void) { switch(key_method) { case None: break; case ParPort: close_key_pport(); break; case SerPort: close_key_serport(); break; case Udp: close_key_enet(); break; } return; } int quisk_is_key_down(void) { switch(key_method) { case None: return key_is_down; case SerPort: return is_key_down_serport(); case ParPort: return is_key_down_pport(); case Udp: return is_key_down_enet(); } return 0; } void quisk_set_key_down(int state) { // Set the key state internally if (state) key_is_down = 1; else key_is_down = 0; } // *************************************************** // Access the parallel port static int open_key_pport(const char * name) { int byte; if (fd >= 0) close(fd); fd = open(name, O_RDONLY); if (fd == -1) { printf("Open %s failed, try modprobe ppdev.\n", name); } else if (ioctl (fd, PPCLAIM)) { perror ("PPCLAIM"); close (fd); fd = -1; } else { byte = 0x0; ioctl(fd, PPWCONTROL, &byte); return 0; // Success } return -1; } static void close_key_pport(void) { int byte; if (fd >= 0) { byte = 0x0; ioctl(fd, PPWCONTROL, &byte); close(fd); } fd = -1; } // This code writes to the control register so the PC can send a signal. // Currently unused. // ioctl(fd, PPRCONTROL, &byte); // byte |= 0x02; // ioctl(fd, PPWCONTROL, &byte); static int is_key_down_pport(void) { int byte; if (fd < 0) // port not open return 0; // Key is up byte = 0; ioctl(fd, PPRSTATUS, &byte); if (byte & 0x10) return 1; // Key is down return 0; // Key is up } // *************************************************** // Access using Ethernet // Check for a UDP packet from the network to determine key status static int open_key_enet(const char * ip) { struct sockaddr_in Addr; close_key_enet(); key_socket = socket(PF_INET, SOCK_DGRAM, 0); if (key_socket < 0) return -1; memset(&Addr, 0, sizeof(Addr)); // Assign an address to our socket Addr.sin_family = AF_INET; Addr.sin_addr.s_addr = htonl(INADDR_ANY); Addr.sin_port = htons(KEY_PORT); if (bind(key_socket, (struct sockaddr *)&Addr, sizeof(Addr)) != 0) { close_key_enet(); return -1; } memset(&Addr, 0, sizeof(Addr)); // Only accept UDP from this host Addr.sin_family = AF_INET; inet_aton(ip, &Addr.sin_addr); Addr.sin_port = htons(KEY_PORT); if (connect(key_socket, (struct sockaddr *)&Addr, sizeof(Addr)) != 0) { close_key_enet(); return -1; } return 0; // Success } static void close_key_enet(void) { if (key_socket != -1) { shutdown(key_socket, SHUT_RDWR); close(key_socket); key_socket = -1; } } static int is_key_down_enet(void) { static int keyed = 0; unsigned char buf[4]; if (key_socket >= 0 && recv(key_socket, buf, 2, MSG_DONTWAIT) == 2) keyed = buf[0]; // new key state is available return keyed; // return current key state } // *************************************************** // Access the serial port. This code sets DTR high, and monitors DSR. // When DSR is high the key is down (else up). // Set the RTS signal high when the key is down; else low after a delay. static int open_key_serport(const char * name) { int bits; if (fd >= 0) close(fd); fd = open(name, O_RDWR | O_NOCTTY); if (fd == -1) { printf("Open serial port %s failed.\n", name); return -1; } ioctl(fd, TIOCMGET, &bits); // read modem bits bits |= TIOCM_DTR; // Set DTR bits &= ~TIOCM_RTS; // Clear RTS at first ioctl(fd, TIOCMSET, &bits); return 0; // Success } static void close_key_serport(void) { if (fd >= 0) close(fd); fd = -1; } // Delay clearing RTS when the key goes up (semi breakin) #define KEY_UP_DELAY_SECS 1.5 static int is_key_down_serport(void) { int bits; struct timeval tv; double time; static double time0=0; // time when the key was last down if (fd < 0) // Port not open return 0; // Key is up gettimeofday(&tv, NULL); time = tv.tv_sec + tv.tv_usec / 1.0E6; // time is in seconds ioctl(fd, TIOCMGET, &bits); // read modem bits if (bits & TIOCM_DSR) { // Key is down bits |= TIOCM_RTS; // Set RTS ioctl(fd, TIOCMSET, &bits); time0 = time; return 1; } else { // Key is up if (time - time0 > KEY_UP_DELAY_SECS) { bits &= ~TIOCM_RTS; // Clear RTS after a delay ioctl(fd, TIOCMSET, &bits); } return 0; } } #endif quisk-3.6.11/docs2.html0000644000175000017500000013605412115131430014216 0ustar jimjim00000000000000 Documentation for Quisk

Welcome to QUISK (April 2012)

This is Quisk, a Software Defined Radio (SDR). You supply an antenna, a complex (I/Q) mixer to convert radio spectrum to a low IF, and send that IF to the left and right inputs of the sound card in your computer. The Quisk software will read the sound card data, tune it, filter it, demodulate it, and send the audio to headphones or speakers.  Quisk has a microphone input and a key input so it can operate as a complete transceiver.  Quisk works with this hardware:
  • SoftRock connected to the sound card
  • Many other SDR's connected to the sound card
  • SDR-IQ connected by USB
  • N2ADR hardware connected by Ethernet/TCP/IP
  • Quisk can be used as a pan adapter, and can control some radios
Quisk is small and simple, and has been designed so that it is easy to change Quisk to suit your own hardware.   Quisk rhymes with "brisk", and is QSK plus a few letters to make it easier to pronounce. QSK is a Q signal meaning full breakin CW operation, and Quisk has been designed for low latency. Quisk includes an input keying signal that can mute the audio and substitute a sidetone.

Please read the file CHANGELOG.txt for changes.

When running Quisk for the first time, please press the "Help" button on the lower right.

Credits

Quisk was originally written by James Ahlstrom, N2ADR.

Thanks to Leigh L. Klotz, Jr. WA5ZNU for configuration improvements, factoring out my eccentric hardware control, and adding panadapter and other hardware support.

Thanks to Franco Spinelli for a fix for the H101 hardware.

Thanks to Andrew Nilsson VK6JBL for adding support for SoftRock Rx and Tx.

Thanks to Terry Fox, WB4JFI, for code to support the Charleston hardware.

Thanks to Maitland Bottoms, AA4HS, for the sub-module linkage patches.

Many others contributed to Quisk, and are mentioned in comments in the source code.

Installation


Quisk is registered on http://pypi.python.org; just search for "quisk" to see the latest version and the download URL. The download page is http://james.ahlstrom.name/quisk/index.html.  There will be a source distribution (a tar.gz file) and a binary Windows version (msi installer).  The Linux version is for 32-bit Linux.  If you get the message "wrong ELF class", you have 64-bit Linux, and you must recompile (use "make").  You do not need to compile the Windows binary, but you need Python to run it.

You must have Python installed on your computer, preferably version 2.7.  Linux almost certainly has Python installed.  For Windows, visit http://www.python.org and download the Windows installer for Python 2.7 to install it.  You must also install the latest wxPython package for your version of Python from http://www.wxpython.org.

Linux

I recommend that you just uncompress and un-tar the tar.gz file somewhere under your home directory:

gunzip quisk-3.4.4.tar.gz
tar xf quisk-3.4.4.tar
# Check directory quisk-3.4.4 before removing the tar file
rm quisk-3.4.4.tar
# Perhaps change to a shorter name unless you want multiple versions
mv quisk-3.4.4 quisk

That way all the source for Quisk is available so you can change or add to Quisk. If you need to recompile the source, use the "make" command in the quisk directory. If there are compile errors or missing *.h files, you must install some "dev" packages. See below for needed "dev" packages.

Run Quisk using a terminal with the command "python quisk.py". If there is any error output, it will appear on the terminal. After testing, you can create a panel launcher with the same command but a full path, for example "python /home/jim/quisk-3.4.4/quisk.py" or "python /home/jim/quisk/quisk.py" if you used the shorter name . Then just click the button to run Quisk.

Another way to install Quisk is to change to the superuser (root) and run "easy_install quisk" or "python setup.py install". If you don't have easy_install, install the python-setuptools package (for Debian/Ubuntu). This method installs Quisk as a package. But you need to be root, and the source is not in a convenient place; it is in /usr/lib/python2.7/site-packages. And there is no uninstall feature.

Quisk needs a few additional packages to run. All should be available as packages or RPM's so you don't have to compile the source. Generally you would get the most recent versions rather than the versions I show below. Needed packages are:

  • python2.7, the Python programming language. See http://www.python.org. This almost certainly is already installed on your Linux. Use the version you have, or get the most recent version.
  • python-wxgtk2.8, the wxPython package used for the GUI. Get the most recent version available for your Python version.
  • fftw3, the Fastest Fourier Transform in the West. See fftw.org. This is a great FFT package and is also used by GNU radio.
  • python2.7-dev, fftw3-dev, libasound2-dev, portaudio19-dev These are development packages that you need so you can change and recompile the Quisk C-language files. Get the version that corresponds to the software you have. If you get compiler errors, check for missing "-dev" packages.

If you want to attach a key status line to your computer, you need to change is_key_down.c and run "make". I currently use Ethernet to send key up/down status.  I previously sent a 5 volt CMOS signal to my parallel port, but new computers often lack a parallel port, and Ethernet is much easier.

If you decide to use the parallel port, you need the ppdev Linux driver. To load it on boot, add it to /etc/modules (on Debian). The permissions on the port (on Debian) are 660, group "lp". So add yourself to the "lp" group. Otherwise you will have to run "modprobe ppdev", and run "chmod 666 /dev/parport0" as root to access the parallel port.

Quisk does not use the serial port, but some of the special hardware files do. If you need Python serial port support, install pyserial from package python-serial. Note that many programs use USB, but are based on a USB to serial converter, and pyserial works with these too.

Windows Installer

To install Quisk, first install Python and wxPython (see above).  Next download the quisk.msi installer, right click it, and select "install".  This is best for those who plan to run Quisk, but not work with the source code.  To uninstall Quisk, use the Control Panel item Add/Remove Programs.  Quisk is installed in the site-packages folder under the Python 2.7 libraries.  This enables Quisk to be imported as a package by other software.

Windows Source

If you want to see and change the source code, or recompile the Windows version from source, download the source tarball (the tar.gz file), uncompress it and extract it into a directory somewhere.  This is the same as the Linux install proceedure.  I use the directory C:/pub/quisk because I synchronize this directory using SpiderOak on multiple computers.  You should probably choose a directory under C:/Users/my_name with Windows 7, or perhaps a directory under the Documents folder.  You can then run Quisk with the command "C:\python27\pythonw.exe quisk.py" from the Quisk directory, the directory where quisk.py is located.  You can create a shortcut on the desktop with this command.  There is no need to recompile unless you change the C language source, as the needed DLLs are included.  You can change any of the Python *.py files, and there is no need to recompile.

To recompile the DLL, install the MinGw compiler and the same dependencies as the Linux version, and enter "make win".  If you get errors, look for missing *.h files from missing dependencies.

Quisk Files


These are the Quisk files in the distribution:

  • quisk.py is the main program and is written in the Python language. Python is a powerful but easy to learn language, and I hope you have fun changing Quisk to make it do what you want. Python is also useful for general electronics calculations such as complex arithmetic. See www.python.org. Quisk.py uses the wxPython Python package to make the screen interface.
  • help.html is the help file for quisk. Press the "Help" button.
  • _quisk.so is the _quisk extension module for Linux, and _quisk.pyd is the extension module DLL used by Windows.
  • sdriq.so is the extension module needed for the SDR-IQ. It needs _quisk.so to be available when it starts.
  • makefile is the makefile, and you must run "make" to create a new _quisk.so unless you use a Python installer that creates _quisk.so itself.
  • setup.py is used by makefile and the Python installers.
  • quisk_conf_defaults.py is the basic configuration file imported into all other configuration files. Read it (but don't change it) to see what you can change in your own quisk_conf.py.
  • quisk_conf_*.py are various Quisk configuration files. Copy one of them to your own .quisk_conf.py and edit that file. I may publish new model files in the future, and you don't want your changes to be overwritten.
  • quisk_hardware_*.py are various quisk hardware control programs. If you have custom hardware, import one of these files into your quisk_conf.py. Or copy one of them to your own quisk_hardware.py, edit that file, and import it in .quisk_conf.py.
  • quisk.c, quisk.h are the files for the _quisk extension module used by quisk.py. The other C-language files are linked with these to make _quisk.so and _quisk.pyd.
  • sound.c is the general purpose sound code for all sources.
  • sound_portaudio.c is the sound card access code for PortAudio.
  • sound_alsa.c is the sound card access code for the ALSA drivers.
  • sound_directx.c is the sound card access code for DirectX.
  • is_key_down.c is the hardware key checker for the PC. I use Ethernet to send the key status, but there is code for the parallel port and dummy code too.
  • sdriq.c, sdriq.h are the files that make sdriq.so and support the SDR-IQ.
  • microphone.c reads the microphone audio and sends it to your hardware using Ethernet. Change it for other sound access.
  • doc.html is Quisk documentation.  It uses doc1.html and doc2.html.
  • portaudio.py is a utility program. Run it to list your PortAudio devices. It is not used by the Quisk program.

Configuration

Quisk does not have a menu to control its operating parameters.  Instead, you must create and edit your own configuration file.  For Linux, the default configuration file name is ".quisk_conf.py" in your home directory; that is, "~/.quisk_conf.py".  For Windows, the default configuration file name is quisk_conf.py in your My Documents folder.
  • Linux config file:         ~/.quisk_conf.py
  • Windows config file:    My Documents/quisk_conf.py
 To help you get started, there are several configuration files included, such as  quisk_conf_model.py for sound card, quisk_conf_sdriq.py for SDR-IQ, and quisk_conf_fixed.py for fixed VFO such as SoftRock.  Do not change any of the quisk_conf_*.py files. Instead copy one of these files (but NOT quisk_conf_defaults.py) to your own config file.  Newer versions of Quisk will not overwrite your personal config file.

The file quisk_conf_defaults.py contains all Quisk's parameters.  It is read in first; then your config file is read in and overwrites some parameters.  Do not copy quisk_conf_defaults.py to your config file. It is too long and is subject to change with each new version. Instead, read it to see what you can change, and then just put the lines that need changing into your config file.

If you are controlling custom hardware, you will need to specify a hardware file in quisk_conf.py. The default is quisk_hardware_model.py. Look at the other quisk_hardware_*.py files. For example, quisk_hardware_fixed.py is for crystal controlled SoftRock. To use that hardware file, change your quisk_conf.py to include:

import quisk_hardware_fixed as quisk_hardware

There are comments in quisk_conf_model.py showing this change. If none of the hardware files do exactly what you want, copy one of them to your own quisk_hardware.py, edit that file, and include this line in quisk_conf.py:

import quisk_hardware

Newer versions of Quisk will not overwrite your quisk_hardware.py.  Your hardware file enables you to customize Quisk without changing the Quisk program files.

Alternatively, you can define a class named "Hardware" in your config file, and that class will be used instead of a hardware file. This is recommended only for simple hardware needs. The class should start like this:

        from quisk_hardware_model import Hardware as BaseHardware
        class Hardware(BaseHardware):
            def __init__(self, app, conf):
                BaseHardware.__init__(self, app, conf) # Start your hardware control here.
                # For ideas, see one of the other hardware modules.

Both the config file and your hardware file are written in the Python language.  Python is an easy to learn but powerful computer language.  Quisk can be adapted to different hardware because of the power of Python.

Sound Cards

If you use a sound card for input, the quality of your sound card is critical; but you can start with the sound card you have. Check the Graph screen with no input to see the noise floor. It should be as flat and as low as possible, with no bump near zero Hertz. The 0dB line at the top of the Graph screen is the maximum level, so if your noise floor is at -90 dB, you have that much dynamic range. The IF (sound) input to the sound card should raise the noise floor only slightly to avoid losing dynamic range.

The sample rate determines how much of the band you can see on the screen. My 96 kHz card shows a little over 80 kHz of bandwidth, from -40 kHz to + 40 kHz centered at the VFO frequency.  Generally you would choose the highest rate available to get the most visible bandwidth. Be aware that a card claiming to work at (say) 192 kHz may in fact play at that rate, but only capture (record) audio at a lower rate. It is the capture rate that matters. Enter only the sample rate you know your raw hardware supports for capture.

If you use the SDR-IQ or other hardware for input, you still need a sound card for sound output.  The quality of this card is not so important, so try the one you have.  Be aware that most sound cards require the capture and playback rate to be the same when used for both.  Here are some sample configurations:
  • SoftRock Rx/Tx: Receive to card 1, Transmit to card 1 at the same rate, radio sound to card 2 at 48 kHz, microphone input from card 2 or 3 at 48 kHz.
  • SoftRock Rx: Receive to card 1, radio sound to card1 at the same rate; OR radio sound to card 2 at 48 kHz.
  • Other: Receive from SDR-IQ or other hardware, radio sound to card 1 at 48 kHz.  Add a microphone to card1 at 48 kHz, or to card2 at 48 kHz.
  • Panadapter: There is no radio sound.  Enter a null name "" for the play device.
If you buy a new sound card, make sure you know the capture (recording) sample rates and the noise level.  Sound cards are usually specified over the audio range up to 24 kHz or so. But we need low noise and distortion over the whole range.

Linux Names

Quisk can use PortAudio or ALSA to access your sound card.  Either name can be a fragment of text from the device description.  It is better to use this text search rather than an index number, because the index number can change if you plug and unplug USB sound cards.

The ALSA drivers use different names for the same sound card to provide different access. The names "hw:0" and "hw:1" refer to the raw hardware devices of the first and second sound card. You should use the raw hardware if possible. If the raw devices don't work, use the "plughw" name.  The ALSA name can also be a string name.  Here are some ALSA names:
"hw:0"		# First sound card
"hw:1" # Second sound card, etc.
"plughw" # plug device
"default" # alsa default device
"alsa:NVidia" # Search for the name in the alsa device description
Alsa names starting with "alsa:" are an extension to the normal alsa names.  They search for the text after the colon in the alsa device name.  The alsa device names are shown on the config screen.  Or you can start a terminal window and enter "aplay -l" for a list of play devices, or "arecord -l" for a list of capture devices.  See alsa_names for more information.

The PortAudio interface is newer, may be easier to get working, and may be used to connect Quisk to other programs (I have not tried this).  But for CW, ALSA has lower latency.  Run "python portaudio.py" in a terminal window to see a list of available names, or use a different PortAudio tool.  Here are some PortAudio names:
"portaudio:(hw:0,0)"    First sound card.
"portaudio:(hw:1,0)" Second sound card, etc.
"portaudio:NVidia" Search for the name in the portaudio device description.
"portaudio#1" Directly specified index.
"portaudiodefault" May give poor performance on capture.

Linux Sound Servers

Newer Linux systems are now shipping with PulseAudio enabled.  PulseAudio is a sound server, a program that takes control of your sound cards, and controls usage by applications.  The idea is that your applications talk to PulseAudio, and PulseAudio talks to the sound cards.  Another example of a sound server is JACK.  There are advantages to sound servers, but they can be confusing.  For example, suppose you set up Quisk to use ALSA device hw:0, and everything works fine.  Then you run a different application (maybe a CD player) that uses PulseAudio.  PulseAudio now claims hw:0 for its use and sends application (CD) audio to it.  Then you run Quisk again, but it fails because it can not access hw:0.  The problem is that PulseAudio still "owns" hw:0.  Eventually it will time out and Quisk will work again.

You can set up Quisk to use PulseAudio too, so that PulseAudio can do its job of routing audio.  To do this use "pulse" as the sound card device name in Quisk.  This "pulse" name is an ALSA plugin that sends/receives audio from PulseAudio.  You can control the sound routing with the pavucontrol program.  Remarkably, this is not included with PulseAudio, and you will need to install the pavucontrol package first.  PulseAudio will add latency and you must be careful that it does not try to re-sample the data to change the sample rate of the hardware.  If you have SoftRock hardware and a high quality sound card to sample data, it would be good to avoid using this with PulseAudio, and to reserve it for Quisk.  PulseAudio could still be used to play radio sound on a second card.

Linux Problems

If Quisk appears to run but you get no sound input or output, you may be having trouble with your settings. Start Quisk and look at the graph. You should get a moving line display. Look at the Config screen. Interrupts should be increasing and latencies should fluctuate. If all this looks normal, but you get no sound output, or you get only white noise output, then you may need to change your settings with a mixer program.

If you capture data with the sound card (no SDR-IQ) then you need to set the "capture device" to the line-in jack, and set the volume of the line-in to 100%. To play sound, you need to increase the volume of the playback device. Since a typical sound card has ten or twenty controls for all its analog and digital inputs and outputs, it is a guessing game to figure out which control to adjust.

Basically you start the alsamixer program (use "man alsamixer" first) and adjust the volume controls and capture device until Quisk works. It is wise to reduce or mute unwanted inputs to avoid adding extra noise.   Quisk does not do this for you. But once you have the controls set, they will stay the same and Quisk should keep working until you run another audio program that changes them.

To make Quisk adjust the mixer controls when it starts, you need to know the control id number. Run the command "amixer -c 0 contents" (for card zero) and look at the control ids, names and values of all your controls. Figure out the control you need to adjust. For a setable option (on/off) the control value is one or zero. For a volume it is a number from 0.0 to 1.0. Make a list of (device_name, numid, value) and add it to mixer_settings in your .quisk_conf.py file (see quisk_conf_defaults.py). I don't need to do this on my computer except for the microphone input on my second sound card.

If you really get stuck, try one of these commands (see the "man" page):
  • alsamixer   An ALSA mixer program with a curses interface.
  • amixer   A character ALSA mixer.
  • aplay   Play sound.
  • arecord   Capture sound.
  • speaker-test   Play sound to test your speakers.
And try to play an audio CD or run some other Linux audio program just to see that you have a working sound system. If you can't get ALSA to work, you could try the PortAudio interface by just changing the sound card names.

For more information try these articles:
http://linuxplanet.com/linuxplanet/tutorials/6465/1/
http://linuxplanet.com/linuxplanet/tutorials/6466/1/

Windows Names

To see what sound cards you have, use the Control Panel item Sound Devices.  There is a separate list for capture (recording) and playback devices, and a specified default device for each.  The name of the default device is "Primary".  To specify your sound card name, use either "Primary" or a substring of the device name.  The search is case sensitive.

SDR-IQ as Input


Quisk can use an SDR-IQ from RfSpace instead of a sound card for input. Edit your config file to select the SDR-IQ. Read quisk_conf_defaults.py to see what changes you need to make. For Linux, install the ft245 Linux USB driver. See http://james.ahlstrom.name/ft245 for installation instructions. You still need a sound card for output. The output is 48 kHz stereo and a high quality card is not required. Files that support the SDR-IQ are now in subdirectory sdriqpkg.

Timing


There are several configuration parameters devoted to tuning; read the file quisk_conf_defaults.py for documentation. For most users, Quisk should run fine with the default settings. But if you use Quisk as part of a QSK CW transmitter, you should reduce latency_millisecs to as low a value as possible. This will reduce latency, but increase the likelihood of clicks and pops due to sound buffer underruns.

USB Control

Many radio devices are now controlled through a USB interface.  In many cases, the interface is actually a serial port, and an external or internal USB to serial converter is used.  In other cases, the USB is native, but requires a custom device driver.  In still other cases, the USB device announces itself as a standard device such as a sound device or human interface device, and uses a standard operating system built-in driver.

Linux

Default USB permissions do not allow a non-root user to write to the bus.  You may find that Quisk will complain about lack of permission to access the USB.  You could test this by running Quisk as root and seeing if that works; but this is not acceptable except for testing.  To change USB permissions, add a rule to /etc/udev/rules.d/local.rules (for SoftRock on Debian and Ubuntu) like this:

  SUBSYSTEM=="usb", ATTR{idVendor}=="16c0" , ATTR{idProduct}=="05dc", MODE="0666", GROUP="dialout"

This changes the USB device permissions to read/write for all users, and changes the group to the "dialout" group.  Default group permissions are read/write, so if you are in the "dialout" group, you don't need "MODE"; modify as appropriate.  To load the new rule, you can either reboot or on Ubuntu use

       sudo udevadm control --reload-rules

Custom Hardware

Quisk receives RF using your sound card or your SDR-IQ out of the box.  But if you have custom  hardware such as  a VFO or a transmitter, you need to describe your hardware to Quisk.

First, Quisk has a transmit (Tx) frequency and a receive (Rx) frequency.  The transmit frequency is the one shown in the frequency display, and shown by the tuning line on the graph and the waterfall.  The Rx frequency is always equal to the Tx frequency except when the RIT (receiver incremental tuning) button is down or the Split feature is in use.  The primary frequency in Quisk is the Tx frequency, even when you are receiving.

Quisk has a "VFO" frequency.  This is the RF frequency corresponding to zero Hertz audio frequency, and is the frequency shown at the center of the graph display.  For a SoftRock or a direct conversion receiver (Tayloe detector, SDR1000-type hardware, etc.) this really is the VFO frequency.  But consider an AOR AR8600 receiver with a 10.7 MHz IF output to a pan adapter.  For that case, the VFO is always 10.7 MHz since that is the center point of the display, and signals at exactly 10.7 MHz are at zero Hertz audio.  But to display the correct frequency within Quisk, the VFO would be the tuning frequency of the AR8600.

When Quisk starts, it uses the hardware description in quisk_hardware_model.py, but this file doesn't do much.  It is mostly useful as a model or starting point.  To use a different hardware file, first create a custom file such as my_hardware.py.  Look at the various quisk_hardware_*.py for ideas.  Then import your file in your config file:

    import my_hardware as quisk_hardware.

Suppose you have a crystal controlled SoftRock.  A good model hardware file is quisk_hardware_fixed.py.  Copy quisk_hardware_fixed.py to my_hardware.py, make any changes to my_hardware.py, and import it in your config file.

At my shack, I control an AT-200PC antenna tuner, my SDR-IQ, my filter boxes and my SSB exciter (using Ethernet) all with Quisk.  Take a look at quisk_hardware_n2adr.py.

The quisk_hardware_model.py file shows the basics of hardware control. There is an open() and close() function called once on startup and shutdown. The ChangeMode() and ChangeBand() functions are called when the user changes the mode or band with the corresponding buttons.  The HeartBeat() function is called at about 10 Hz by Quisk.  You can put code there to poll a serial port or to perform other housekeeping functions (try to be efficient).  The two remaining functions deserve more documentation.

ChangeFrequency(self, tune, vfo, source='', band='', event=None)

Quisk calls the ChangeFrequency() function when the user changes the Tx frequency with a mouse click on the graph or waterfall, with the entry box, with the band Up/Down buttons, etc.  The "source" is a string giving the reason for the change:

BtnBand A band button was pressed (the string band is in the band argument)
BtnUpDown The band Up/Down buttons were pressed
FreqEntry The user entered a frequency in the box
MouseBtn1 Left mouse button was pressed (for the mouse, "event" is the handler event)
MouseBtn3 Right mouse button was pressed
MouseMotion The user is dragging with the left button
MouseWheel The mouse wheel up/down was used

Most of the time you will not care about the "source".  You just need to react to the user's action, perhaps by changing the hardware VFO frequency.  It is not necessary to actually make the change requested.  Just adjust your hardware as required, and return the actual (tune, vfo) that you want.  Quisk will ignore its requested values and use your actual values instead.

For example, suppose you have a crystal controlled SoftRock.  The VFO frequency is fixed at (say) 7.025 MHz.  Then when ChangeFrequency() is called, return (tune, 7025000).  This will fix your VFO frequency to the only one available.

Suppose Quisk calls ChangeFrequency() with vfo=7050000 and tune=7100000, so the tune is 50 kHz above the VFO.  Suppose that is unacceptable because of (say) bandwidth limitations, so you want the VFO closer to the tune.  Set your hardware VFO to 7090000 instead, and return (tune, 7090000).

Suppose Quisk is just controlling a receiver and the audio is demodulated by the receiver and not by Quisk.  Then the center frequency is always the tuning frequency, and you would set the receiver frequency to tune, and return (tune, tune).

ReturnFrequency(self)

When Quisk starts, it calls ReturnFrequency() to get the initial tune and VFO.  To display an initial frequency, return (tune, vfo) on the first call.

Thereafter, Quisk calls ReturnFrequency() at a 10 Hz rate to poll for frequency changes.  You should almost always return (None, None) to indicate that the frequencies have not changed since the last time ReturnFrequency() or ChangeFrequency() was called.  Returning (None, None) is slightly more efficient than returning the actual frequencies, and thus forcing Quisk to see if its frequencies are out of date.

The only reason to return something other than (None, None) is if your hardware can change frequency by itself; that is, other than in response to ChangeFrequency().  For example, if your hardware is a receiver with a tuning knob, and the user turns the knob, you must return the new frequencies from ReturnFrequency() or else Quisk will be unaware of the change.

Extension Packages

Quisk comes with two extension packages.  The sdriqpkg package supports the SDR-IQ hardware by RfSpace.  The n2adr package supports the hardware in my shack.  There are other extension packages available from third parties.

All extension packages are directories (folders) in the Quisk root; that is, in the directory where quisk.py is located.  This enables Quisk to find extension modules, and extension modules to find each other.  You can install in a different place, but you will need to know what you are doing.

Starting with Quisk 3.6 C-language extension modules are not linked with _quisk.so.  Certain symbols from _quisk.so are exported using the Python CObject or Capsule interface.  That simplifies linkage and eliminates problems with module search paths.  See the documentation in import_quisk_api.c.  This change was suggested by Maitland Bottoms, AA4HS, and he also provided patches.

Most Quisk users will not need to write packages to support their hardware.  They will need a config file in their home directory (or other name with the "-c" or "--config" command line option).  And they may need a custom hardware file that can be written directly in the config file (for simple cases) or imported from the file quisk_hardware.py.  If you need to import Python files, they must be on your PYTHONPATH.  You could just put them in the Quisk root (not really recommended).  Or you could put them in a directory somewhere on PYTHONPATH (import sys; print sys.path).  Or you could put them in a directory somewhere and add that directory to PYTHONPATH in your config file:

  import sys
  sys.path.append('/home/jim/my_python_stuff')

Shared Libraries

The main Python extension module for Quisk is _quisk.so or _quisk.pyd. It is a shared library. To import it, it must be on the Python path. There are other Python extension modules (shared libraries) for other hardware, for example, sdriq.so. Quisk works fine when all these modules are in package subdirectories.  If you want to put them somewhere else, be sure that the Python import mechanism can find them.

If you link your sub-packages against _quisk so you can use _quisk functions, be aware that your sub-package must be able to find _quisk.so at both compile and run time. You need to follow the Linux rules for searching for shared libraries. Try using the "ldd sdriq.so" command to see your library dependencies. Also try readelf -d sdriq.so.

For Quisk version 3.6 and newer, you should use the Python CObject or Capsule mechanism instead of using the C linker to access _quisk functions and data.  Quisk will prepare an array of function and data pointers and transfer them to your sub-module without using the C linker.  Only minimal changes to your sub-module are required.  The SDR-IQ module sdriq.so uses this method, and you can use it as a model.  See the file import_quisk_api.c for documentation.

New Packages

If you have more complex needs or want to distribute your code more widely, you need to create a new Quisk package.  That is easily done by modeling your code after the existing packages.  To create a new package you need a subdirectory of the Quisk root to hold it, perhaps "mypak".  Then create these files in mypak:

  • __init__.py     This file just consists of the character "#".  Its existence identifies mypak as a Python package.
  • makefile        Only needed if you have C-language extensions.  Copy this file from sdriqpkg/makefile.
  • MANIFEST.in     A list of files you want to distribute in your package.  This file often consists of just one line: include  *.c  *.h  *.py  *.txt  *.html  *.so  makefile
  • README.txt      This file is expected to be present.

To these files, you add all your Python files, C-language files and any other files you need.  If you have a hardware or widget file, they should be named quisk_hardware.py and quisk_widgets.py.  Longer names are not needed because you are within a package.  You should include a sample quisk_conf.py too.

To compile C-language extensions (if you have any) enter "make".  To import your hardware and widgets files from other modules, use:

  from mypak import quisk_hardware
  from mypak import quisk_widgets
  from mypak import myext as EXT

The setup.py file describes how to build your package.  But it is also used to distribute it.  To create a mypak-1.0.tar.gz file in the "dist" subdirectory, use:

  python setup.py sdist

You can then put the file on your web page (for example).  To make your package available on PyPi.Python.org, first register with PyPi and then use:

  python setup.py register sdist upload

Python supports quite complicated packages; see the distutils documentation.

Installing Packages

Your package mypak will run on your machine as is.  But when another use gets mypak-1.0.tar.gz they need to install it.  Basically, they just put it in the Quisk root with the same name as on your machine.  Here is an INSTALL.txt:

Unzip and untar this archive at the root of the Quisk directory; that is, where the file quisk.py is located.  In this example, the archive is named "mypak" and the path to quisk.py is /home/jim/quisk/quisk.py.

  mv mypak-1.0.tar.gz  /home/jim/quisk
  cd /home/jim/quisk
  gunzip mypak-1.0.tar.gz
  tar xf mypak-1.0.tar
  # Make sure that directory mypak-1.0 exists before removing the archive.
  rm mypak-1.0.tar        # tar file is no longer needed
  mv mypak-1.0 mypak    # change to the correct name

Digital Modes

Quisk has a number of modes "DGT-" to receive and transmit digital signals.  The modes "DGT-U" and "DGT-L" decode the signal as upper or lower sideband, and send the monophonic audio to the digital sound device.  The mode "DGT-IQ" does not decode the audio; the I/Q samples are sent directly to the (stereo) digital sound device.  The bandwidth of the digital sideband signals is set with the filter buttons as usual, and the maximum bandwidth is 20 kilohertz.

Digital modes require an external program such as Fldigi to decode the received audio and to generate transmit audio.  There are two aspects, rig control and audio transfer.  Rig control is needed to synchronize the transmit frequency between Quisk and Fldigi (or other program) and to operate the PTT (push to talk).  You can control Quisk using either XML-RPC or Hamlib.  For Fldigi, start Quisk and select a digital mode.  Then start Fldigi and set Fldigi rig control to "Use XMML-RPC".  Now changing the frequency on one program will change the other.  Keying Quisk to key down (however you do that with your hardware) will set Fldigi to Transmit.  Pressing the PTT control in Fldigi will also press the PTT button in Quisk.

Using Hamlib is similar.  Set your digital program to Hamlib control, rig 2, device localhost:4575.  This establishes a TCP connection to Quisk.  If your program does not offer rig 2, please update your Hamlib files for that program.  If your program can not set the TCP port to localhost:4575, then change the port Quisk uses by adding "hamlib_port = 4532" to your config file. This is the default port for rig 2.  Hamlib control can be used by other programs such as logging programs.  See http://james.ahlstrom.name/hamlib.html for more information.

Please read the file quisk_conf_defaults.py (as usual) to discover the various settings available for digital modes.

Quisk has an additional audio input and output for digital programs.  They are named digital_input_name and digital_output_name.  You need to set these names to a sound device, and then set the Fldigi (or other program) sound card to the same device.  The sound device is not a real sound card; it is some sort of loopback device, and is only needed because there is no standard way of sending sound samples between two programs (yet).  The method to use for Quisk is the same as for other programs, and is on the web.  It works for any digital program, not just Fldigi.

If you use Windows, you need to purchase Virtual Audio Cable (VAC).  Connect Quisk to one side, and your digital program to the other.  I haven't tried this, so I don't know the device names to use.

If you use Linux, you can use the ALSA loopback device, or use PortAudio or Jack to route your audio.  The ALSA  loopback device is simple, and works the same as the Windows VAC.  First create the loopback device with the command "modprobe snd-aloop" (you will need to be root).  You can create the loopback device automatically, but the way to do that depends on your version of Linux.  I just put the modprobe command in /etc/rc.local for my Ubuntu system.  Now you can enter "cat /proc/asound/cards" to print out your sound cards, and you should see a "Loopback" card listed.  The cards are also shown on the Quisk config screen.  The Loopback card has one side that connects to Quisk and another side that connects to your digital program.  For the Quisk side use:

digital_input_name = "hw:Loopback,0"
digital_output_name = digital_input_name

Note that the Loopback card is full duplex, and handles both input and output.  For the digital program side, set the input and output to "Loopback,1".  For Fldigi this is in the Audio / Devices / PortAudio menu.  Your audio is now connected and you should be able to receive digital signals.  Be sure to test your transmit signal off the air.  You may need to reduce power to improve linearity.  I am open to adding support for other digital programs, especially if you provide information on how to do it.

The sample rate for digital_input_name (transmit audio) is fixed at 48000 sps.  The sample rate for digital_output_name (received audio) is the same as the rate sent to your speakers.  The Loopback device adopts the rate of the first program to use it.  So starting Quisk first and your digital program next should work.  Or you may need to set the appropriate rates.  It is probably best to set all sample rates to 48000 sps because the digital signals are so narrow, and this make them easier to see.

Vector Network Analyzer

If you have my transceiver hardware from 2010 QEX, or the newer HiQSDR hardware, you can use it as a vector network analyzer by using a special program.  You must be using FPGA firmware version 1.3 or newer.  Run the VNA program with "python quisk_vna.py" or use a shortcut.  The VNA program will not work with SoftRock or other hardware.  The "Help" button explains how to use it, and should get you started.  This VNA program enables you to analyze your antennas without additional expense.

When running in VNA mode the two control bytes [18:20] are the 16-bit non-zero VNA count "vna_count", the number of data points to send.   This locks the transmit and receive frequency to the same value.  The phases are also equal except for a fixed time delay, which causes a linear change of phase with frequency.  The starting frequency is the receive frequency (actually phase) rx_phase.  Subsequent points have the transmit phase tx_phase added to create a frequency scan.  Specifically, after each data point, the tx_phase is added to create the RF output at the next frequency; then there is a pause of 65 microseconds to allow the external device under test to stabilize; then 4096 data points are added together to create the sample; then the sample is added to the block of data to send by UDP.  A sample of zero is sent after the last data point, and the process repeats.  The receiving software must look for the zero sample that marks the start of a new scan.  The total number of points in the scan is vna_count, and blocks received with a different length should be rejected.

Since the transmit and receive frequency is the same, the data points are I/Q values at DC; that is, a complex number representing a voltage and phase.

A calibration run must be taken before any data can be obtained.  The calibrations request a scan of data points every 15 killohertz from zero to 60 megahertz, or a little over 4000 points.  These data are saved so that the scan frequencies can be changed without a new calibration.  For any start and end scan frequency the user chooses, these saved calibrations are used with linear interpolation.

If vna_count is zero, the firmware is operating normally, and not in VNA mode.
quisk-3.6.11/sound_directx.c0000666000175000017500000004417212122366303015346 0ustar jimjim00000000000000#include #include #include #include "quisk.h" #include "dsound.h" //#include #include //#include //#include // This module provides sound card access using Direct Sound HRESULT errFound, errOpen; static GUID IEEE = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static GUID PCMM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static BOOL CALLBACK DSEnumNames(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID pyseq) { PyList_Append((PyObject *)pyseq, PyString_FromString(lpszDesc)); return( TRUE ); } static BOOL CALLBACK DsEnumPlay(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID dev) { // Open the play device if the name is found in the description LPDIRECTSOUND8 DsDev; if (strstr (lpszDesc, ((struct sound_dev *)dev)->name)) { errFound = DS_OK; errOpen = DirectSoundCreate8(lpGUID, &DsDev, NULL); if (errOpen == DS_OK) { ((struct sound_dev *)dev)->handle = DsDev; } return FALSE; // Stop iteration } else { return TRUE; } } static BOOL CALLBACK DsEnumCapture(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID dev) { // Open the capture device if the name is found in the description LPDIRECTSOUNDCAPTURE8 DsDev; if (strstr (lpszDesc, ((struct sound_dev *)dev)->name)) { errFound = DS_OK; errOpen = DirectSoundCaptureCreate8(lpGUID, &DsDev, NULL); if (errOpen == DS_OK) ((struct sound_dev *)dev)->handle = DsDev; return FALSE; // Stop iteration } else { return TRUE; } } static void MakeWFext(int use_new, int use_float, struct sound_dev * dev, WAVEFORMATEXTENSIBLE * pwfex) { // fill in a WAVEFORMATEXTENSIBLE structure if (use_float) dev->sample_bytes = 4; if (use_new) { pwfex->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; pwfex->Format.cbSize = 22; pwfex->Samples.wValidBitsPerSample = dev->sample_bytes * 8; if (dev->num_channels == 1) pwfex->dwChannelMask = SPEAKER_FRONT_LEFT; else pwfex->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; if (use_float) { pwfex->SubFormat = IEEE; dev->use_float = 1; } else { pwfex->SubFormat = PCMM; dev->use_float = 0; } } else { pwfex->Format.cbSize = 0; if (use_float) { pwfex->Format.wFormatTag = 0x03; //WAVE_FORMAT_IEEE; dev->use_float = 1; } else { pwfex->Format.wFormatTag = WAVE_FORMAT_PCM; dev->use_float = 0; } } pwfex->Format.nChannels = dev->num_channels; pwfex->Format.nSamplesPerSec = dev->sample_rate; pwfex->Format.nAvgBytesPerSec = dev->num_channels * dev->sample_rate * dev->sample_bytes; dev->play_buf_size = pwfex->Format.nAvgBytesPerSec; pwfex->Format.nBlockAlign = dev->num_channels * dev->sample_bytes; pwfex->Format.wBitsPerSample = dev->sample_bytes * 8; } static int quisk_open_capture(struct sound_dev * dev) { // Open the soundcard for capture. Return non-zero for error. LPDIRECTSOUNDCAPTUREBUFFER ptBuf; DSCBUFFERDESC dscbd; HRESULT hr; WAVEFORMATEXTENSIBLE wfex; dev->handle = NULL; dev->buffer = NULL; dev->started = 0; dev->dataPos = 0; dev->portaudio_index = -1; if ( ! dev->name[0]) // Check for null play name; not an error return 0; errFound = ~DS_OK; DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)DsEnumCapture, dev); if (errFound != DS_OK) { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound capture device name %s not found", dev->name); return 1; } if (errOpen != DS_OK) { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound capture device %s open failed", dev->name); return 1; } dev->sample_bytes = 4; MakeWFext (1, 0, dev, &wfex); // fill in wfex memset(&dscbd, 0, sizeof(DSCBUFFERDESC)); dscbd.dwSize = sizeof(DSCBUFFERDESC); dscbd.dwFlags = 0; dscbd.dwBufferBytes = dev->play_buf_size; // one second buffer dscbd.lpwfxFormat = (WAVEFORMATEX *)&wfex; hr = IDirectSoundCapture_CreateCaptureBuffer( (LPDIRECTSOUNDCAPTURE8)dev->handle, &dscbd, &ptBuf, NULL); if (hr == DS_OK) { dev->buffer = ptBuf; #if DEBUG_IO printf("Created capture buffer size %d bytes for %s\n", dev->play_buf_size, dev->name); #endif } else { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound capture device %s buffer create failed (0x%lX)", dev->name, hr); return 1; } ptBuf = (LPDIRECTSOUNDCAPTUREBUFFER)dev->buffer; hr = IDirectSoundCaptureBuffer8_Start(ptBuf, DSCBSTART_LOOPING); if (hr != DS_OK) { #if DEBUG_IO printf("Capture start error 0x%lX", hr); #endif snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound capture device %s capture start failed", dev->name); return 1; } return 0; } static int quisk_open_playback(struct sound_dev * dev) { // Open the soundcard for playback. Return non-zero for error. LPDIRECTSOUNDBUFFER ptBuf; WAVEFORMATEXTENSIBLE wfex; DSBUFFERDESC dsbdesc; HRESULT hr; dev->handle = NULL; dev->buffer = NULL; dev->started = 0; dev->oldPlayPos = 0; dev->play_delay = 0; dev->dataPos = 0; dev->portaudio_index = -1; dev->sample_bytes = 2; if ( ! dev->name[0]) // Check for null play name; not an error return 0; errFound = ~DS_OK; DirectSoundEnumerate((LPDSENUMCALLBACK)DsEnumPlay, dev); if (errFound != DS_OK) { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound play device name %s not found", dev->name); return 1; } if (errOpen != DS_OK) { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound play device %s open failed", dev->name); return 1; } hr = IDirectSound_SetCooperativeLevel ((LPDIRECTSOUND8)dev->handle, (HWND)quisk_mainwin_handle, DSSCL_PRIORITY); if (hr != DS_OK) { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound play device %s cooperative level failed", dev->name); return 1; } dev->sample_bytes = 4; MakeWFext (1, 0, dev, &wfex); // fill in wfex memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS; dsbdesc.dwBufferBytes = dev->play_buf_size; // one second buffer dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&wfex; hr = IDirectSound_CreateSoundBuffer( (LPDIRECTSOUND8)dev->handle, &dsbdesc, &ptBuf, NULL); if (hr == DS_OK) { dev->buffer = ptBuf; } else { snprintf (quisk_sound_state.err_msg, SC_SIZE, "DirectSound play device %s buffer create failed (0x%X)", dev->name, hr); return 1; } return 0; } PyObject * quisk_sound_devices(PyObject * self, PyObject * args) { // Return a list of DirectSound device names PyObject * pylist, * pycapt, * pyplay; if (!PyArg_ParseTuple (args, "")) return NULL; // Each pycapt and pyplay is a device name pylist = PyList_New(0); // list [pycapt, pyplay] pycapt = PyList_New(0); // list of capture devices pyplay = PyList_New(0); // list of play devices PyList_Append(pylist, pycapt); PyList_Append(pylist, pyplay); DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)DSEnumNames, pycapt); DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumNames, pyplay); return pylist; } void quisk_start_sound_alsa (struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { struct sound_dev * pDev; if (quisk_sound_state.err_msg[0]) return; // prior error // DirectX must open the playback device before the (same) capture device while (1) { pDev = *pPlayback++; if ( ! pDev) break; if (quisk_open_playback(pDev)) return; // error } while (1) { pDev = *pCapture++; if ( ! pDev) break; if (quisk_open_capture(pDev)) return; // error } } void quisk_close_sound_alsa(struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { struct sound_dev * pDev; while (*pCapture) { pDev = *pCapture; if (pDev->buffer) IDirectSoundCaptureBuffer_Stop((LPDIRECTSOUNDCAPTUREBUFFER)pDev->buffer); pDev->handle = NULL; pCapture++; } while (*pPlayback) { pDev = *pPlayback; if (pDev->buffer) IDirectSoundBuffer8_Stop((LPDIRECTSOUNDBUFFER)pDev->buffer); pDev->handle = NULL; pPlayback++; } } int quisk_read_alsa(struct sound_dev * dev, complex * cSamples) { LPDIRECTSOUNDCAPTUREBUFFER ptBuf = (LPDIRECTSOUNDCAPTUREBUFFER)dev->buffer; HRESULT hr; DWORD readPos, captPos; LPVOID pt1, pt2; DWORD i, n1, n2; short si, sq, * pts; float fi, fq, * ptf; int li, lq, * ptl; // int must be 32 bits complex c; int ii, qq, nSamples; int bytes, frames, poll_size, millisecs, bytes_per_frame, pass; if ( ! dev->handle || ! dev->buffer) return 0; bytes_per_frame = dev->num_channels * dev->sample_bytes; hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(ptBuf, &captPos, &readPos); if (hr != DS_OK) { #if DEBUG_IO printf ("Get CurrentPosition error 0x%lX\n", hr); #endif dev->dev_error++; return 0; } // printf("dataPos %d\n", dev->dataPos); if ( ! dev->started) { dev->started = 1; dev->dataPos = readPos; } if (readPos >= dev->dataPos) bytes = readPos - dev->dataPos; else bytes = readPos - dev->dataPos + dev->play_buf_size; frames = bytes / bytes_per_frame; // frames available to read poll_size = dev->read_frames; millisecs = (poll_size - frames) * 1000 / dev->sample_rate; // time to read remaining poll size if (millisecs > 0) { // wait for additional frames #if DEBUG_IO > 2 printf ("Wait %d millisecs for more samples\n", millisecs); #endif Sleep(millisecs); hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(ptBuf, &captPos, &readPos); if (hr != DS_OK) { #if DEBUG_IO printf ("Get CurrentPosition two error 0x%lX\n", hr); #endif dev->dev_error++; return 0; } if (readPos >= dev->dataPos) bytes = readPos - dev->dataPos; else bytes = readPos - dev->dataPos + dev->play_buf_size; } frames = bytes / bytes_per_frame; // frames available to read dev->dev_latency = frames; bytes = frames * bytes_per_frame; // round to frames if ( ! bytes) { return 0; } i = poll_size * bytes_per_frame * 4; // Limit size of read if (i > 0 && bytes > i) { // zero poll_size is allowed bytes = i; frames = bytes / bytes_per_frame; } if (IDirectSoundCaptureBuffer8_Lock(ptBuf, dev->dataPos, bytes, &pt1, &n1, &pt2, &n2, 0) != DS_OK) { dev->dev_error++; #if DEBUG_IO printf ("DirecctX capture lock error bytes %d\n", bytes); #endif return 0; } //printf ("%d %d %d %d\n", dev->channel_I, dev->channel_Q, bytes_per_frame, dev->num_channels); #if DEBUG_IO > 3 printf("%s read %4d bytes %4d frames from %9d to (%9lu %9lu) diff %9lu\n", dev->name, bytes, frames, dev->dataPos, readPos, captPos, captPos - readPos); #endif #if DEBUG_IO if (bytes != n1 + n2) printf ("Lock not equal to bytes\n"); #endif dev->dataPos += bytes; dev->dataPos = dev->dataPos % dev->play_buf_size; nSamples = 0; pass = 0; switch (dev->sample_bytes + dev->use_float) { case 2: pts = (short *)pt1; frames = (n1 + n2) / bytes_per_frame; bytes = 0; while (frames) { si = pts[dev->channel_I]; sq = pts[dev->channel_Q]; pts += dev->num_channels; if (si >= CLIP16 || si <= -CLIP16) dev->overrange++; // assume overrange returns max int if (sq >= CLIP16 || sq <= -CLIP16) dev->overrange++; ii = si << 16; qq = sq << 16; cSamples[nSamples++] = ii + I * qq; bytes += bytes_per_frame; frames--; if (bytes == n1) pts = (short *)pt2; } break; case 4: ptl = (int *)pt1; frames = (n1 + n2) / bytes_per_frame; bytes = 0; while (frames) { li = ptl[dev->channel_I]; lq = ptl[dev->channel_Q]; ptl += dev->num_channels; if (li >= CLIP32 || li <= -CLIP32) dev->overrange++; // assume overrange returns max int if (lq >= CLIP32 || lq <= -CLIP32) dev->overrange++; cSamples[nSamples++] = li + I * lq; bytes += bytes_per_frame; frames--; if (bytes == n1) ptl = (int *)pt2; } break; case 5: // use IEEE float ptf = (float *)pt1; frames = (n1 + n2) / bytes_per_frame; bytes = 0; while (frames) { fi = ptf[dev->channel_I]; fq = ptf[dev->channel_Q]; ptf += dev->num_channels; if (fabsf(fi) >= 1.0 || fabsf(fq) >= 1.0) dev->overrange++; // assume overrange returns maximum cSamples[nSamples++] = (fi + I * fq) * 16777215; bytes += bytes_per_frame; frames--; if (bytes == n1) { ptf = (float *)pt2; } } break; } IDirectSoundCaptureBuffer8_Unlock(ptBuf, pt1, n1, pt2, n2); for (i = 0; i < nSamples; i++) { // DC removal; R.G. Lyons page 553 c = cSamples[i] + dev->dc_remove * 0.95; cSamples[i] = c - dev->dc_remove; dev->dc_remove = c; } return nSamples; } void quisk_play_alsa(struct sound_dev * dev, int nSamples, complex * cSamples, int report_latency, double volume) { LPDIRECTSOUNDBUFFER ptBuf = (LPDIRECTSOUNDBUFFER)dev->buffer; DWORD playPos, writePos; // hardware index into buffer LPVOID pt1, pt2; DWORD n1, n2; short * pts; float * ptf; int * ptl; // int must be 32 bits int n, unavail, count, frames, bytes, pass, bytes_per_frame; if ( ! dev->handle || ! dev->buffer) return; bytes_per_frame = dev->num_channels * dev->sample_bytes; // Note: writePos moves ahead with playPos; it is not associated with write activity if (IDirectSoundBuffer8_GetCurrentPosition(ptBuf, &playPos, &writePos) != DS_OK) { #if DEBUG_IO printf ("Bad GetCurrentPosition\n"); #endif quisk_sound_state.write_error++; dev->dev_error++; playPos = writePos = 0; } unavail = (int)writePos - (int)playPos; // Must not write to this region if (unavail < 0) unavail += dev->play_buf_size; count = (int)playPos - dev->oldPlayPos; // number of bytes played if (count < 0) count += dev->play_buf_size; // assume no wrap-around beyond play_buf_size dev->oldPlayPos = playPos; dev->play_delay -= count; // bytes in buffer available to play dev->dev_latency = dev->play_delay / bytes_per_frame; if (report_latency) // Report latency for main playback device quisk_sound_state.latencyPlay = dev->dev_latency; #if DEBUG_IO if (nSamples || count) printf ("DirectX playPos %6d writePos %6d no-write %6d dev->dev_latency %6d data_pos %6d samples %6d\n", (int)playPos, (int)writePos, unavail, dev->dev_latency, dev->dataPos, nSamples); #endif switch(dev->started) { case 0: // Starting state; wait for buffer to fill before starting play if (dev->dev_latency + nSamples >= dev->latency_frames) { IDirectSoundBuffer8_Play (ptBuf, 0, 0, DSBPLAY_LOOPING); dev->started = 1; #if DEBUG_IO printf ("Start DirectX play at dev->latency_frames %d\n", dev->latency_frames); #endif } break; case 1: // Normal run state // Measure the space available to write samples frames = (dev->play_buf_size - dev->play_delay - unavail) / bytes_per_frame; // Check for underrun n = unavail / bytes_per_frame + dev->latency_frames * 2 / 10 - nSamples; // minimum frames if (dev->dev_latency < n) { quisk_sound_state.underrun_error++; dev->dev_underrun++; n += dev->latency_frames * 2 / 10; while (n-- > 0) cSamples[nSamples++] = 0; // add zero samples #if DEBUG_IO printf ("Underrun error, frames %d\n", dev->dev_latency); #endif } // Check if play buffer is too full else if (dev->dev_latency > dev->latency_frames * 18 / 10 || nSamples >= frames) { quisk_sound_state.write_error++; dev->dev_error++; nSamples = 0; dev->started = 2; #if DEBUG_IO printf("Discard %d samples\n", nSamples); #endif } break; case 2: // Buffer is too full; wait for it to drain nSamples = 0; if (dev->dev_latency <= dev->latency_frames) { dev->started = 1; #if DEBUG_IO printf("Resume adding samples\n"); #endif } break; } bytes = nSamples * bytes_per_frame; if (bytes <= 0) return; // write our data bytes at our data position dataPos if (IDirectSoundBuffer8_Lock(ptBuf, dev->dataPos, bytes, &pt1, &n1, &pt2, &n2, 0) != DS_OK) { #if DEBUG_IO printf ("DirectX play lock error\n"); #endif quisk_sound_state.write_error++; dev->dev_error++; return; } dev->dataPos += bytes; // update data write position dev->dataPos = dev->dataPos % dev->play_buf_size; dev->play_delay += bytes; // bytes available to play pass = 0; n = 0; switch (dev->sample_bytes + dev->use_float) { case 2: pts = (short *)pt1; // Start writing at pt1 frames = n1 / bytes_per_frame; for (n = 0; n < nSamples && pass < 2; n++) { pts[dev->channel_I] = (short)(volume * creal(cSamples[n]) / 65536); pts[dev->channel_Q] = (short)(volume * cimag(cSamples[n]) / 65536); pts += dev->num_channels; if (--frames <= 0) { pass++; // change to pt2 pts = (short *)pt2; frames = n2 / bytes_per_frame; } } break; case 4: ptl = (int *)pt1; // Start writing at pt1 frames = n1 / bytes_per_frame; for (n = 0; n < nSamples && pass < 2; n++) { ptl[dev->channel_I] = (int)(volume * creal(cSamples[n])); ptl[dev->channel_Q] = (int)(volume * cimag(cSamples[n])); ptl += dev->num_channels; if (--frames <= 0) { pass++; // change to pt2 ptl = (int *)pt2; frames = n2 / bytes_per_frame; } } break; case 5: // use IEEE float ptf = (float *)pt1; // Start writing at pt1 frames = n1 / bytes_per_frame; for (n = 0; n < nSamples && pass < 2; n++) { ptf[dev->channel_I] = (volume * creal(cSamples[n]) / CLIP32); ptf[dev->channel_Q] = (volume * cimag(cSamples[n]) / CLIP32); ptf += dev->num_channels; if (--frames <= 0) { pass++; // change to pt2 ptf = (float *)pt2; frames = n2 / bytes_per_frame; } } break; } IDirectSoundBuffer8_Unlock(ptBuf, pt1, n1, pt2, n2); } void quisk_play_portaudio(struct sound_dev * dev, int j, complex * samp, int i, double volume) { } void quisk_start_sound_portaudio(struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { } void quisk_close_sound_portaudio(void) { } int quisk_read_portaudio(struct sound_dev * dev, complex * samp) { return 0; } void quisk_mixer_set(char * card_name, int numid, double value, char * err_msg, int err_size) { err_msg[0] = 0; } quisk-3.6.11/libusb.txt0000644000175000017500000000253111632372222014340 0ustar jimjim00000000000000Notes on libusb and pyusb ========================= Libusb provides access to the USB bus from user space. It uses the files in /dev/bus/usb/*/*. The following commands are useful on Linux: List devices on the USB bus: lsusb Add -d 16c0:05dc for a specific device, -v for more information. List file permissions for bus 001 device 005: ls -l /dev/bus/usb/001/005 These permissions default to 660 group root. List udev information for bus 001 device 005: udevadm info --query=all --name=/dev/bus/usb/001/005 --attribute-walk These items can be used in udev rules. Default USB permissions do not allow a non-root user to write to the bus. To change permissions, add a rule to /etc/udev/rules.d/local.rules like this: SUBSYSTEM=="usb", ATTR{idVendor}=="16c0" , ATTR{idProduct}=="05dc", MODE="0666", GROUP="dialout" Then notify udev with "udevadm control --reload_rules", or /etc/init.d/udev/restart. But on my system, I need to plug in the SoftRock and reboot. To install Libusb on Windows, follow the instructions in http://sourceforge.net/apps/trac/libusb-win32/wiki. Run the program libusb-win32*/bin/inf-wizard.exe. On Windows, when libusb-win32 is properly installed, Device Manager reports a top-level device "libusb-win32 devices" and a sub-device "DG8SAQ-I2C". Otherwise it reports "Unknown Device" under "Universal Serial Bus controllers". quisk-3.6.11/quisk_conf_kx3.py0000664000175000017500000000244212031361244015616 0ustar jimjim00000000000000# Please do not change this configuration file for Quisk. Copy it to # your own config file and make changes there. # # This config file is for hamlib control of a KX3 through hamlib, with Quisk # acting as a panadapter. The daemon rigctld must be running. The open() method # below tries to start it, or you can start it by hand. import sys, os if sys.platform == "win32": name_of_sound_capt = 'Primary' name_of_sound_play = 'Primary' latency_millisecs = 150 data_poll_usec = 20000 else: name_of_sound_capt = 'hw:0' name_of_sound_play = 'hw:0' latency_millisecs = 150 data_poll_usec = 5000 # Use the hamlib hardware module to talk to the KX3 from quisk_hardware_hamlib import Hardware as BaseHardware class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) # Change the port and timing parameters here: # self.hamlib_rigctld_port = 4532 # Standard rigctld control port # self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes def open(self): ret = BaseHardware.open(self) if not self.hamlib_connected: # rigctld is not started. Try to start it. os.system("rigctld -m 229 -r /dev/ttyUSB0 -s 4800 & ") # Check the baud rate menu setting # If this fails, start rigctld by hand. return ret quisk-3.6.11/utility.c0000666000175000017500000000732311724230304014172 0ustar jimjim00000000000000#include #ifdef MS_WINDOWS #include #else #include #include #endif #include #include "quisk.h" // Access to config file attributes. // NOTE: These must be called only from the main (GUI) thread, // not from the sound thread. int QuiskGetConfigInt(const char * name, int deflt) { // return deflt for failure. Accept int or float. int res; PyObject * attr; if (!quisk_pyConfig || PyErr_Occurred()) { return deflt; } attr = PyObject_GetAttrString(quisk_pyConfig, name); if (attr) { res = (int)PyInt_AsUnsignedLongMask(attr); // This works for floats too! Py_DECREF(attr); return res; // success } else { PyErr_Clear(); } return deflt; // failure } double QuiskGetConfigDouble(const char * name, double deflt) { // return deflt for failure. Accept int or float. double res; PyObject * attr; if (!quisk_pyConfig || PyErr_Occurred()) return deflt; attr = PyObject_GetAttrString(quisk_pyConfig, name); if (attr) { res = PyFloat_AsDouble(attr); Py_DECREF(attr); return res; // success } else { PyErr_Clear(); } return deflt; // failure } char * QuiskGetConfigString(const char * name, char * deflt) { // return deflt for failure. char * res; PyObject * attr; if (!quisk_pyConfig || PyErr_Occurred()) return deflt; attr = PyObject_GetAttrString(quisk_pyConfig, name); if (attr) { res = PyString_AsString(attr); Py_DECREF(attr); if (res) return res; // success else PyErr_Clear(); } else { PyErr_Clear(); } return deflt; // failure } double QuiskTimeSec(void) { // return time in seconds as a double #ifdef MS_WINDOWS FILETIME ft; ULARGE_INTEGER ll; GetSystemTimeAsFileTime(&ft); ll.LowPart = ft.dwLowDateTime; ll.HighPart = ft.dwHighDateTime; return (double)ll.QuadPart * 1.e-7; #else struct timeval tv; gettimeofday(&tv, NULL); return (double)tv.tv_sec + tv.tv_usec * 1e-6; #endif } void QuiskPrintTime(const char * str, int index) { // print the time and a message and the delta time for index 0 to 9 double tm; int i; static double time0 = 0; static double start_time[10]; #ifdef MS_WINDOWS static long long timer_rate = 0; LARGE_INTEGER L; if ( ! timer_rate) { if (QueryPerformanceFrequency(&L)) timer_rate = L.QuadPart; else timer_rate = 1; } if (QueryPerformanceCounter(&L)) tm = (double)L.QuadPart / timer_rate; else tm = 0; #else struct timeval tv; gettimeofday(&tv, NULL); tm = (double)tv.tv_sec + tv.tv_usec * 1e-6; #endif if (index < -9 || index > 9) // error return; if (index < 0) { start_time[ - index] = tm; return; } if ( ! str) { // initialize time0 = tm; for (i = 0; i < 10; i++) start_time[i] = tm; return; } // print the time since startup, and the time since the last call if (index > 0) { if (str[0]) // print message and a newline printf ("%12.6lf %9.3lf %9.3lf %s\n", tm - time0, (tm - start_time[0])*1e3, (tm - start_time[index])*1e3, str); else // no message; omit newline printf ("%12.6lf %9.3lf %9.3lf ", tm - time0, (tm - start_time[0])*1e3, (tm - start_time[index])*1e3); } else { if (str[0]) // print message and a newline printf ("%12.6lf %9.3lf %s\n", tm - time0, (tm - start_time[0])*1e3, str); else // no message; omit newline printf ("%12.6lf %9.3lf ", tm - time0, (tm - start_time[0])*1e3); } start_time[0] = tm; } void QuiskSleepMicrosec(int usec) { #ifdef MS_WINDOWS int msec = (usec + 500) / 1000; // convert to milliseconds if (msec < 1) msec = 1; Sleep(msec); #else struct timespec tspec; tspec.tv_sec = usec / 1000000; tspec.tv_nsec = (usec - tspec.tv_sec * 1000000) * 1000; nanosleep(&tspec, NULL); #endif } quisk-3.6.11/usb/0000775000175000017500000000000012164330433013110 5ustar jimjim00000000000000quisk-3.6.11/usb/util.pyc0000644000175000017500000001463612146140537014616 0ustar jimjim00000000000000 iNc@sdZdZddlZddljZdZdZdZdZdZ d Z d Z d Z dZ dZdZd ZdZdZdZd ZdZdZdZd Zd Zd Zd ZdZd Zd Zd ZdZ dZ!dZ"e#ddZ%dZ&dZ'dZ(dS(susb.util - Utility functions.sWander Lairson CostaiNiiiiiiiicCs|t@S(sReturn the endpoint absolute address. The address parameter is the bEndpointAddress field of the endpoint descriptor. (t_ENDPOINT_ADDR_MASK(taddress((s ./usb/util.pytendpoint_addressJscCs|t@S(sReturn the endpoint direction. The address parameter is the bEndpointAddress field of the endpoint descriptor. The possible return values are ENDPOINT_OUT or ENDPOINT_IN. (t_ENDPOINT_DIR_MASK(R((s ./usb/util.pytendpoint_directionRscCs|t@S(sReturn the transfer type of the endpoint. The bmAttributes parameter is the bmAttributes field of the endpoint descriptor. The possible return values are: ENDPOINT_TYPE_CTRL, ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR. (t_ENDPOINT_TRANSFER_TYPE_MASK(t bmAttributes((s ./usb/util.pyt endpoint_type[scCs|t@S(sReturn the direction of a control request. The bmRequestType parameter is the value of the bmRequestType field of a control transfer. The possible return values are CTRL_OUT or CTRL_IN. (t_CTRL_DIR_MASK(t bmRequestType((s ./usb/util.pytctrl_directionescCs||d>B|BS(sBuild a bmRequestType field for control requests. These is a conventional function to build a bmRequestType for a control request. The direction parameter can be CTRL_OUT or CTRL_IN. The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS, CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values. The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE, CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER. Return the bmRequestType value. i((t directionttypet recipient((s ./usb/util.pytbuild_request_typensc sfd}|j|j}}|rQg|||D] }|^qASytj|||SWntk rdSXdS(sFind an inner descriptor. find_descriptor works in the same way the core.find() function does, but it acts on general descriptor objects. For example, suppose you have a Device object called dev and want a Configuration of this object with its bConfigurationValue equals to 1, the code would be like so: >>> cfg = util.find_descriptor(dev, bConfigurationValue=1) You can use any field of the Descriptor as a match criteria, and you can supply a customized match just like core.find() does. The find_descriptor function also accepts the find_all parameter to get a list of descriptor instead of just one. c 3snxgD]_dks%rtjdttj|tfd|trVqqWdS(NcSs |o |S(N((tatb((s ./usb/util.pytscs t|S(N(tgetattr(ti(td(s ./usb/util.pyRs(tNonet_interopt_reducetmaptoperatorteqtTrue(tktv(t custom_matchtdesc(Rs ./usb/util.pyt desc_iters  N(tkeystvaluesRt_nextt StopIterationR(Rtfind_allRtargsR RRR((RRs ./usb/util.pytfind_descriptor~s  cCs|jj||dS(sExplicitly claim an interface. PyUSB users normally do not have to worry about interface claiming, as the library takes care of it automatically. But there are situations where you need deterministic interface claiming. For these uncommon cases, you can use claim_interface. If the interface is already claimed, either through a previously call to claim_interface or internally by the device object, nothing happens. N(t_ctxtmanaged_claim_interface(tdevicet interface((s ./usb/util.pytclaim_interfaces cCs|jj||dS(s;Explicitly release an interface. This function is used to release an interface previously claimed, either through a call to claim_interface or internally by the device object. Normally, you do not need to worry about claiming policies, as the device object takes care of it automatically. N(R(tmanaged_release_interface(R*R+((s ./usb/util.pytrelease_interfaces cCs|jj|dS(s"Release internal resources allocated by the object. Sometimes you need to provide deterministic resources freeing, for example to allow another application to talk to the device. As Python does not provide deterministic destruction, this function releases all internal resources allocated by the device, like device handle and interface policy. After calling this function, you can continue using the device object normally. If the resources will be necessary again, it will allocate them automatically. N(R(tdispose(R*((s ./usb/util.pytdispose_resourcess()t__doc__t __author__Rt usb._interopRtDESC_TYPE_DEVICEtDESC_TYPE_CONFIGtDESC_TYPE_STRINGtDESC_TYPE_INTERFACEtDESC_TYPE_ENDPOINTt ENDPOINT_INt ENDPOINT_OUTtENDPOINT_TYPE_CTRLtENDPOINT_TYPE_ISOtENDPOINT_TYPE_BULKtENDPOINT_TYPE_INTRtCTRL_TYPE_STANDARDtCTRL_TYPE_CLASStCTRL_TYPE_VENDORtCTRL_TYPE_RESERVEDtCTRL_RECIPIENT_DEVICEtCTRL_RECIPIENT_INTERFACEtCTRL_RECIPIENT_ENDPOINTtCTRL_RECIPIENT_OTHERtCTRL_OUTtCTRL_INRRRRRRRR RtFalseRR'R,R.R0(((s ./usb/util.pytsJ   ( quisk-3.6.11/usb/core.py0000644000175000017500000007576011632372224014432 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. r"""usb.core - Core USB features. This module exports: Device - a class representing a USB device. Configuration - a class representing a configuration descriptor. Interface - a class representing an interface descriptor. Endpoint - a class representing an endpoint descriptor. find() - a function to find USB devices. """ __author__ = 'Wander Lairson Costa' __all__ = ['Device', 'Configuration', 'Interface', 'Endpoint', 'find'] import array import usb.util as util import copy import sys import operator import usb._interop as _interop import logging _logger = logging.getLogger('usb.core') _DEFAULT_TIMEOUT = 1000 def _set_attr(input, output, fields): for f in fields: setattr(output, f, int(getattr(input, f))) class _ResourceManager(object): def __init__(self, parent, dev, backend): self.backend = backend self._active_cfg_index = None self.dev = dev self.handle = None self._claimed_intf = _interop._set() self._alt_set = {} self._ep_type_map = {} def managed_open(self): if self.handle is None: self.handle = self.backend.open_device(self.dev) return self.handle def managed_close(self): if self.handle is not None: self.backend.close_device(self.handle) self.handle = None def managed_set_configuration(self, device, config): if config is None: cfg = device[0] elif isinstance(config, Configuration): cfg = config else: cfg = util.find_descriptor(device, bConfigurationValue=config) self.managed_open() self.backend.set_configuration(self.handle, cfg.bConfigurationValue) # cache the index instead of the object to avoid cyclic references # of the device and Configuration (Device tracks the _ResourceManager, # which tracks the Configuration, which tracks the Device) self._active_cfg_index = cfg.index # after changing configuration, our alternate setting and endpoint type caches # are not valid anymore self._ep_type_map.clear() self._alt_set.clear() def managed_claim_interface(self, device, intf): self.managed_open() if intf is None: cfg = self.get_active_configuration() i = cfg[(0,0)].bInterfaceNumber elif isinstance(intf, Interface): i = intf.bInterfaceNumber else: i = intf if i not in self._claimed_intf: self.backend.claim_interface(self.handle, i) self._claimed_intf.add(i) def managed_release_interface(self, device, intf): if intf is None: cfg = self.get_active_configuration(device) i = cfg[(0,0)].bInterfaceNumber elif isinstance(intf, Interface): i = intf.bInterfaceNumber else: i = intf if i in self._claimed_intf: self.backend.release_interface(self.handle, i) self._claimed_intf.remove(i) def managed_set_interface(self, device, intf, alt): if intf is None: i = self.get_interface(device, intf) elif isinstance(intf, Interface): i = intf else: cfg = self.get_active_configuration(device) if alt is not None: i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt) else: i = util.find_descriptor(cfg, bInterfaceNumber=intf) self.managed_claim_interface(device, i) if alt is None: alt = i.bAlternateSetting self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt) self._alt_set[i.bInterfaceNumber] = alt def get_interface(self, device, intf): # TODO: check the viability of issuing a GET_INTERFACE # request when we don't have a alternate setting cached if intf is None: cfg = self.get_active_configuration(device) return cfg[(0,0)] elif isinstance(intf, Interface): return intf else: cfg = self.get_active_configuration(device) if intf in self._alt_set: return util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=self._alt_set[intf]) else: return util.find_descriptor(cfg, bInterfaceNumber=intf) def get_active_configuration(self, device): # TODO: when we haven't called managed_set_configuration, # issue a get_configuration request to discover the current configuration # See patch #283765. # Meanwhile, we just return the first configuration found if self._active_cfg_index is None: cfg = device[0] self._active_cfg_index = cfg.index return cfg return device[self._active_cfg_index] def get_endpoint_type(self, device, address, intf): intf = self.get_interface(device, intf) key = (address, intf.bInterfaceNumber, intf.bAlternateSetting) try: return self._ep_type_map[key] except KeyError: e = util.find_descriptor(intf, bEndpointAddress=address) type = util.endpoint_type(e.bmAttributes) self._ep_type_map[key] = type return type def release_all_interfaces(self, device): claimed = copy.copy(self._claimed_intf) for i in claimed: self.managed_release_interface(device, i) def dispose(self, device, close_handle = True): self.release_all_interfaces(device) if close_handle: self.managed_close() self._ep_type_map.clear() self._alt_set.clear() self._active_cfg_index = None class USBError(IOError): r"""Exception class for USB errors. Backends must raise this exception when USB related errors occur. """ pass class Endpoint(object): r"""Represent an endpoint object. This class contains all fields of the Endpoint Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bEndpointAddress of the endpoint descriptor: >>> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> for i in cfg: >>> for e in i: >>> print e.bEndpointAddress """ def __init__(self, device, endpoint, interface = 0, alternate_setting = 0, configuration = 0): r"""Initialize the Endpoint object. The device parameter is the device object returned by the find() function. endpoint is the endpoint logical index (not the endpoint address). The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). The interface parameter is the interface logical index (not the bInterfaceNumber field) and alternate_setting is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alternate_setting parameter should be zero. By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. """ self.device = device intf = Interface(device, interface, alternate_setting, configuration) self.interface = intf.bInterfaceNumber self.index = endpoint backend = device._ctx.backend desc = backend.get_endpoint_descriptor( device._ctx.dev, endpoint, interface, alternate_setting, configuration ) _set_attr( desc, self, ( 'bLength', 'bDescriptorType', 'bEndpointAddress', 'bmAttributes', 'wMaxPacketSize', 'bInterval', 'bRefresh', 'bSynchAddress' ) ) def write(self, data, timeout = None): r"""Write data to the endpoint. The parameter data contains the data to be sent to the endpoint and timeout is the time limit of the operation. The transfer type and endpoint address are automatically inferred. The method returns the number of bytes written. For details, see the Device.write() method. """ return self.device.write(self.bEndpointAddress, data, self.interface, timeout) def read(self, size, timeout = None): r"""Read data from the endpoint. The parameter size is the number of bytes to read and timeout is the time limit of the operation.The transfer type and endpoint address are automatically inferred. The method returns an array.array object with the data read. For details, see the Device.read() method. """ return self.device.read(self.bEndpointAddress, size, self.interface, timeout) class Interface(object): r"""Represent an interface object. This class contains all fields of the Interface Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bInterfaceNumber of the interface descriptor: >>> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> for i in cfg: >>> print i.bInterfaceNumber """ def __init__(self, device, interface = 0, alternate_setting = 0, configuration = 0): r"""Initialize the interface object. The device parameter is the device object returned by the find() function. The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). The interface parameter is the interface logical index (not the bInterfaceNumber field) and alternate_setting is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alternate_setting parameter should be zero. By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. """ self.device = device self.alternate_index = alternate_setting self.index = interface self.configuration = configuration backend = device._ctx.backend desc = backend.get_interface_descriptor( self.device._ctx.dev, interface, alternate_setting, configuration ) _set_attr( desc, self, ( 'bLength', 'bDescriptorType', 'bInterfaceNumber', 'bAlternateSetting', 'bNumEndpoints', 'bInterfaceClass', 'bInterfaceSubClass', 'bInterfaceProtocol', 'iInterface' ) ) def set_altsetting(self): r"""Set the interface alternate setting.""" self.device.set_interface_altsetting( self.bInterfaceNumber, self.bAlternateSetting ) def __iter__(self): r"""Iterate over all endpoints of the interface.""" for i in range(self.bNumEndpoints): yield Endpoint( self.device, i, self.index, self.alternate_index, self.configuration ) def __getitem__(self, index): r"""Return the Endpoint object in the given position.""" return Endpoint( self.device, index, self.index, self.alternate_index, self.configuration ) class Configuration(object): r"""Represent a configuration object. This class contains all fields of the Configuration Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bConfigurationValue of the configuration descriptor: >>> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> print cfg.bConfigurationValue """ def __init__(self, device, configuration = 0): r"""Initialize the configuration object. The device parameter is the device object returned by the find() function. The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. """ self.device = device self.index = configuration backend = device._ctx.backend desc = backend.get_configuration_descriptor( self.device._ctx.dev, configuration ) _set_attr( desc, self, ( 'bLength', 'bDescriptorType', 'wTotalLength', 'bNumInterfaces', 'bConfigurationValue', 'iConfiguration', 'bmAttributes', 'bMaxPower' ) ) def set(self): r"""Set this configuration as the active one.""" self.device.set_configuration(self.bConfigurationValue) def __iter__(self): r"""Iterate over all interfaces of the configuration.""" for i in range(self.bNumInterfaces): alt = 0 try: while True: yield Interface(self.device, i, alt, self.index) alt += 1 except (USBError, IndexError): pass def __getitem__(self, index): r"""Return the Interface object in the given position. index is a tuple of two values with interface index and alternate setting index, respectivally. Example: >>> interface = config[(0, 0)] """ return Interface(self.device, index[0], index[1], self.index) class Device(object): r"""Device object. This class contains all fields of the Device Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bDescriptorType of the device descriptor: >>> import usb.core >>> dev = usb.core.find() >>> dev.bDescriptorType Additionally, the class provides methods to communicate with the hardware. Typically, an application will first call the set_configuration() method to put the device in a known configured state, optionally call the set_interface_altsetting() to select the alternate setting (if there is more than one) of the interface used, and call the write() and read() method to send and receive data. When working in a new hardware, one first try would be like this: >>> import usb.core >>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId) >>> dev.set_configuration() >>> dev.write(1, 'teste') This sample finds the device of interest (myVendorId and myProductId should be replaced by the corresponding values of your device), then configures the device (by default, the configuration value is 1, which is a typical value for most devices) and then writes some data to the endpoint 0x01. Timeout values for the write, read and ctrl_transfer methods are specified in miliseconds. If the parameter is omitted, Device.default_timeout value will be used instead. This property can be set by the user at anytime. """ def __init__(self, dev, backend): r"""Initialize the Device object. Library users should normally get a Device instance through the find function. The dev parameter is the identification of a device to the backend and its meaning is opaque outside of it. The backend parameter is a instance of a backend object. """ self._ctx = _ResourceManager(self, dev, backend) self.__default_timeout = _DEFAULT_TIMEOUT desc = backend.get_device_descriptor(dev) _set_attr( desc, self, ( 'bLength', 'bDescriptorType', 'bcdUSB', 'bDeviceClass', 'bDeviceSubClass', 'bDeviceProtocol', 'bMaxPacketSize0', 'idVendor', 'idProduct', 'bcdDevice', 'iManufacturer', 'iProduct', 'iSerialNumber', 'bNumConfigurations' ) ) def set_configuration(self, configuration = None): r"""Set the active configuration. The configuration parameter is the bConfigurationValue field of the configuration you want to set as active. If you call this method without parameter, it will use the first configuration found. As a device hardly ever has more than one configuration, calling the method without parameter is enough to get the device ready. """ self._ctx.managed_set_configuration(self, configuration) def get_active_configuration(self): r"""Return a Configuration object representing the current configuration set.""" return self._ctx.get_active_configuration(self) def set_interface_altsetting(self, interface = None, alternate_setting = None): r"""Set the alternate setting for an interface. When you want to use an interface and it has more than one alternate setting, you should call this method to select the alternate setting you would like to use. If you call the method without one or the two parameters, it will be selected the first one found in the Device in the same way of set_configuration method. Commonly, an interface has only one alternate setting and this call is not necessary. For most of the devices, either it has more than one alternate setting or not, it is not harmful to make a call to this method with no arguments, as devices will silently ignore the request when there is only one alternate setting, though the USB Spec allows devices with no additional alternate setting return an error to the Host in response to a SET_INTERFACE request. If you are in doubt, you may want to call it with no arguments wrapped by a try/except clause: >>> try: >>> dev.set_interface_altsetting() >>> except usb.core.USBError: >>> pass """ self._ctx.managed_set_interface(self, interface, alternate_setting) def get_interface_altsetting(self, interface = None): r"""Get the active alternate setting of the given interface.""" return self._ctx.get_interface(self, interface) def reset(self): r"""Reset the device.""" self._ctx.dispose(self, False) self._ctx.backend.reset_device(self._ctx.handle) def write(self, endpoint, data, interface = None, timeout = None): r"""Write data to the endpoint. This method is used to send data to the device. The endpoint parameter corresponds to the bEndpointAddress member whose endpoint you want to communicate with. The interface parameter is the bInterfaceNumber field of the interface descriptor which contains the endpoint. If you do not provide one, the first one found will be used, as explained in the set_interface_altsetting() method. The data parameter should be a sequence like type convertible to array type (see array module). The timeout is specified in miliseconds. The method returns the number of bytes written. """ backend = self._ctx.backend fn_map = { util.ENDPOINT_TYPE_BULK:backend.bulk_write, util.ENDPOINT_TYPE_INTR:backend.intr_write, util.ENDPOINT_TYPE_ISO:backend.iso_write } intf = self._ctx.get_interface(self, interface) fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)] self._ctx.managed_claim_interface(self, intf) return fn( self._ctx.handle, endpoint, intf.bInterfaceNumber, array.array('B', data), self.__get_timeout(timeout) ) def read(self, endpoint, size, interface = None, timeout = None): r"""Read data from the endpoint. This method is used to receive data from the device. The endpoint parameter corresponds to the bEndpointAddress member whose endpoint you want to communicate with. The interface parameter is the bInterfaceNumber field of the interface descriptor which contains the endpoint. If you do not provide one, the first one found will be used, as explained in the set_interface_altsetting() method. The size parameters tells how many bytes you want to read. The timeout is specified in miliseconds. The method returns an array object with the data read. """ backend = self._ctx.backend fn_map = { util.ENDPOINT_TYPE_BULK:backend.bulk_read, util.ENDPOINT_TYPE_INTR:backend.intr_read, util.ENDPOINT_TYPE_ISO:backend.iso_read } intf = self._ctx.get_interface(self, interface) fn = fn_map[self._ctx.get_endpoint_type(self, endpoint, intf)] self._ctx.managed_claim_interface(self, intf) return fn( self._ctx.handle, endpoint, intf.bInterfaceNumber, size, self.__get_timeout(timeout) ) def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0, data_or_wLength = None, timeout = None): r"""Do a control transfer on the endpoint 0. This method is used to issue a control transfer over the endpoint 0(endpoint 0 is required to always be a control endpoint). The parameters bmRequestType, bRequest, wValue and wIndex are the same of the USB Standard Control Request format. Control requests may or may not have a data payload to write/read. In cases which it has, the direction bit of the bmRequestType field is used to infere the desired request direction. For host to device requests (OUT), data_or_wLength parameter is the data payload to send, and it must be a sequence type convertible to an array object. In this case, the return value is the number of data payload written. For device to host requests (IN), data_or_wLength is the wLength parameter of the control request specifying the number of bytes to read in data payload. In this case, the return value is the data payload read, as an array object. """ if util.ctrl_direction(bmRequestType) == util.CTRL_OUT: if data_or_wLength is None: a = array.array('B') else: a = array.array('B', data_or_wLength) elif data_or_wLength is None: a = 0 else: a = data_or_wLength self._ctx.managed_open() return self._ctx.backend.ctrl_transfer( self._ctx.handle, bmRequestType, bRequest, wValue, wIndex, a, self.__get_timeout(timeout) ) def is_kernel_driver_active(self, interface): r"""Determine if there is kernel driver associated with the interface. If a kernel driver is active, and the object will be unable to perform I/O. """ self._ctx.managed_open() return self._ctx.backend.is_kernel_driver_active(self._ctx.handle, interface) def detach_kernel_driver(self, interface): r"""Detach a kernel driver. If successful, you will then be able to perform I/O. """ self._ctx.managed_open() self._ctx.backend.detach_kernel_driver(self._ctx.handle, interface) def attach_kernel_driver(self, interface): r"""Re-attach an interface's kernel driver, which was previously detached using detach_kernel_driver().""" self._ctx.managed_open() self._ctx.backend.attach_kernel_driver(self._ctx.handle, interface) def __iter__(self): r"""Iterate over all configurations of the device.""" for i in range(self.bNumConfigurations): yield Configuration(self, i) def __getitem__(self, index): r"""Return the Configuration object in the given position.""" return Configuration(self, index) def __del__(self): self._ctx.dispose(self) def __get_timeout(self, timeout): if timeout is not None: return timeout return self.__default_timeout def __set_def_tmo(self, tmo): if tmo < 0: raise ValueError('Timeout cannot be a negative value') self.__default_timeout = tmo def __get_def_tmo(self): return self.__default_timeout default_timeout = property( __get_def_tmo, __set_def_tmo, doc = 'Default timeout for transfer I/O functions' ) def find(find_all=False, backend = None, custom_match = None, **args): r"""Find an USB device and return it. find() is the function used to discover USB devices. You can pass as arguments any combination of the USB Device Descriptor fields to match a device. For example: find(idVendor=0x3f4, idProduct=0x2009) will return the Device object for the device with idVendor Device descriptor field equals to 0x3f4 and idProduct equals to 0x2009. If there is more than one device which matchs the criteria, the first one found will be returned. If a matching device cannot be found the function returns None. If you want to get all devices, you can set the parameter find_all to True, then find will return an list with all matched devices. If no matching device is found, it will return an empty list. Example: printers = find(find_all=True, bDeviceClass=7) This call will get all the USB printers connected to the system. (actually may be not, because some devices put their class information in the Interface Descriptor). You can also use a customized match criteria: dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009) A more accurate printer finder using a customized match would be like so: def is_printer(dev): import usb.util if dev.bDeviceClass == 7: return True for cfg in dev: if util.find_descriptor(cfg, bInterfaceClass=7) is not None: return True printers = find(find_all=True, custom_match = is_printer) Now even if the device class code is in the interface descriptor the printer will be found. You can combine a customized match with device descriptor fields. In this case, the fields must match and the custom_match must return True. In the our previous example, if we would like to get all printers belonging to the manufacturer 0x3f4, the code would be like so: printers = find(find_all=True, idVendor=0x3f4, custom_match=is_printer) If you want to use find as a 'list all devices' function, just call it with find_all = True: devices = find(find_all=True) Finally, you may pass a custom backend to the find function: find(backend = MyBackend()) PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB. If you do not supply a backend explicitly, find() function will select one of the predefineds backends according to system availability. Backends are explained in the usb.backend module. """ def device_iter(k, v): for dev in backend.enumerate_devices(): d = Device(dev, backend) if (custom_match is None or custom_match(d)) and \ _interop._reduce( lambda a, b: a and b, map( operator.eq, v, map(lambda i: getattr(d, i), k) ), True ): yield d if backend is None: import usb.backend.libusb10 as libusb10 import usb.backend.libusb01 as libusb01 import usb.backend.openusb as openusb for m in (libusb10, openusb, libusb01): backend = m.get_backend() if backend is not None: _logger.info('find(): using backend "%s"', m.__name__) break else: raise ValueError('No backend available') k, v = args.keys(), args.values() if find_all: return [d for d in device_iter(k, v)] else: try: return _interop._next(device_iter(k, v)) except StopIteration: return None quisk-3.6.11/usb/backend/0000775000175000017500000000000012164330433014477 5ustar jimjim00000000000000quisk-3.6.11/usb/backend/libusb10.pyc0000644000175000017500000003660412146140542016644 0ustar jimjim00000000000000 iNc@sbddlTddlZddlZddlZddlZddlZddlmZdZ dgZ ej dZ dZ dZdZd Zd Zd Zd Zd ZdZdZdZdZdZdZide 6de6de6de6de6de6de6de6de6de6de6de6d e6d!e6Zd"efd#YZd$efd%YZd&efd'YZd(efd)YZ d*efd+YZ!da#da$e%Z&d,Z'd-Z(d.Z)d/e*fd0YZ+d1e*fd2YZ,d3e*fd4YZ-d5e*fd6YZ.d7e*fd8YZ/d9ej0j1fd:YZ2d;Z3dS(<i(t*N(t methodtracesWander Lairson Costat get_backendsusb.backend.libusb10iiiiiiiiiiiiisSuccess (no error)sInput/output errorsInvalid parameters(Access denied (insufficient permissions)s.No such device (it may have been disconnected)sEntity not founds Resource busysOperation timed outtOverflows Pipe errors/System call interrupted (perhaps due to signal)sInsufficient memorys9Operation not supported or unimplemented on this platforms Unknown errort_libusb_endpoint_descriptorc BsneZdefdefdefdefdefdefdefdefdeefd efg ZRS( tbLengthtbDescriptorTypetbEndpointAddresst bmAttributestwMaxPacketSizet bIntervaltbRefresht bSynchAddresstextrat extra_length(t__name__t __module__tc_uint8tc_uint16tPOINTERtc_ubytetc_intt_fields_(((s./usb/backend/libusb10.pyRRs        t_libusb_interface_descriptorc BseZdefdefdefdefdefdefdefdefdefd eefd eefd efg ZRS( RRtbInterfaceNumbertbAlternateSettingt bNumEndpointstbInterfaceClasstbInterfaceSubClasstbInterfaceProtocolt iInterfacetendpointR R(RRRRRRRR(((s./usb/backend/libusb10.pyR^s         t_libusb_interfacecBs&eZdeefdefgZRS(t altsettingtnum_altsetting(RRRRRR(((s./usb/backend/libusb10.pyR lst_libusb_config_descriptorc Bs}eZdefdefdefdefdefdefdefdefdeefd eefd efg ZRS( RRt wTotalLengthtbNumInterfacestbConfigurationValuetiConfigurationRt bMaxPowert interfaceR R( RRRRRR RRR(((s./usb/backend/libusb10.pyR#ps        t_libusb_device_descriptorcBseZdefdefdefdefdefdefdefdefdefd efd efd efd efd efgZRS(RRtbcdUSBt bDeviceClasstbDeviceSubClasstbDeviceProtocoltbMaxPacketSize0tidVendort idProductt bcdDevicet iManufacturertiProductt iSerialNumbertbNumConfigurations(RRRRR(((s./usb/backend/libusb10.pyR*}s             cCsd }x|D](}tjj|}|dk r Pq q WtjdkrytdSWqtk r|tj ddt qXnt dtjd krt |}n t|}t |d st dn|S( Nsusb-1.0s libusb-1.0tusbtcygwinscygusb-1.0-0.dlls(Libusb 1.0 could not be loaded in cygwintexc_infosUSB library could not be foundtwin32t libusb_init(susb-1.0s libusb-1.0susb(tctypestutilt find_librarytNonetsystplatformtCDLLt Exceptiont_loggerterrortTruetOSErrortWinDLLthasattr(t candidatest candidatetlibnametl((s./usb/backend/libusb10.pyt _load_librarys"     cCs;ttg|j_ttg|j_tg|j_ttttg|j_tttg|j_tg|j _t|j _ tg|j _ttt g|j _t g|j_t tg|j_t tg|j_t tg|j_t ttg|j_t g|j_t tg|j_t tg|j_t tg|j_tttg|j_tttttg|j_ttg|j_t ttttg|j_t tttttttt g|j!_t ttttttt g|j"_t ttttttt g|j#_dS(N($tc_void_pRtlibusb_set_debugtargtypesRR;t libusb_exittlibusb_get_device_listtlibusb_free_device_listtlibusb_ref_devicetrestypetlibusb_unref_devicet_libusb_device_handlet libusb_opent libusb_closetlibusb_set_configurationtlibusb_claim_interfacetlibusb_release_interfacet libusb_set_interface_alt_settingtlibusb_reset_devicetlibusb_kernel_driver_activetlibusb_detach_kernel_drivertlibusb_attach_kernel_driverR*tlibusb_get_device_descriptorRR#tlibusb_get_config_descriptortlibusb_free_config_descriptorRt"libusb_get_string_descriptor_asciiRtc_uinttlibusb_control_transfertlibusb_bulk_transfertlibusb_interrupt_transfer(tlib((s./usb/backend/libusb10.pyt_setup_prototypessn            cCsit|trt|}nt|tre|jdkreddlm}|t|jqen|S(Nii(tUSBError(t isinstancetintRtvaluetusb.coreRmt _str_error(tretvalRm((s./usb/backend/libusb10.pyt_check[st_DevicecBseZdZdZRS(cCstj||_dS(N(t_libRUtdevid(tselfRw((s./usb/backend/libusb10.pyt__init__fscCstj|jdS(N(RvRWRw(Rx((s./usb/backend/libusb10.pyt__del__hs(RRRyRz(((s./usb/backend/libusb10.pyRues t_WrapDescriptorcBseZddZdZRS(cCs||_||_dS(N(tobjtdesc(RxR}R|((s./usb/backend/libusb10.pyRyns cCst|j|S(N(tgetattrR}(Rxtname((s./usb/backend/libusb10.pyt __getattr__qsN(RRR?RyR(((s./usb/backend/libusb10.pyR{ms t_ConfigDescriptorcBs#eZdZdZdZRS(cCs ||_dS(N(R}(RxR}((s./usb/backend/libusb10.pyRyvscCstj|jdS(N(RvReR}(Rx((s./usb/backend/libusb10.pyRzxscCst|jj|S(N(R~R}tcontents(RxR((s./usb/backend/libusb10.pyRzs(RRRyRzR(((s./usb/backend/libusb10.pyRus  t _InitializercBseZdZdZRS(cCsttjddS(N(RtRvR;R?(Rx((s./usb/backend/libusb10.pyRyscCstjddS(N(RvRRR?(Rx((s./usb/backend/libusb10.pyRzs(RRRyRz(((s./usb/backend/libusb10.pyR~s t _DevIteratorcBs#eZdZdZdZRS(cCs=tt|_ttjdt|jj|_ dS(N( RROtdev_listRtRvRSR?tbyrefRptnum_devs(Rx((s./usb/backend/libusb10.pyRys ccs0x)t|jD]}t|j|VqWdS(N(trangeRRuR(Rxti((s./usb/backend/libusb10.pyt__iter__scCstj|jddS(Ni(RvRTR(Rx((s./usb/backend/libusb10.pyRzs(RRRyRRz(((s./usb/backend/libusb10.pyRs  t_LibUSBcBseZeedZeedZeedZeedZeedZeedZ eedZ eedZ eedZ eed Z eed Zeed Zeed Zeed ZeedZeedZeedZeedZeedZeedZdZdZRS(cCstS(N(R(Rx((s./usb/backend/libusb10.pytenumerate_devicesscCs,t}ttj|jt||S(N(R*RtRvRcRwR(Rxtdevtdev_desc((s./usb/backend/libusb10.pytget_device_descriptors cCs;tt}ttj|j|t|t|S(N(RR#RtRvRdRwRR(RxRtconfigtcfg((s./usb/backend/libusb10.pytget_configuration_descriptorscCs|j||}||jkr:tdt|n|j|}||jkrotdt|nt|j||S(NsInvalid interface index s Invalid alternate setting index (RR%t IndexErrortstrR)R"R{R!(RxRtintftaltRRR((s./usb/backend/libusb10.pytget_interface_descriptors cCsT|j||||}||jkr@tdt|nt|j||S(NsInvalid endpoint index (RRRRR{R(RxRtepRRRR((s./usb/backend/libusb10.pytget_endpoint_descriptorscCs,t}ttj|jt||S(N(RXRtRvRYRwR(RxRthandle((s./usb/backend/libusb10.pyt open_devices cCstj|dS(N(RvRZ(Rxt dev_handle((s./usb/backend/libusb10.pyt close_devicescCsttj||dS(N(RtRvR[(RxRt config_value((s./usb/backend/libusb10.pytset_configurationscCsttj|||dS(N(RtRvR^(RxRRR!((s./usb/backend/libusb10.pytset_interface_altsettings cCsttj||dS(N(RtRvR\(RxRR((s./usb/backend/libusb10.pytclaim_interfacescCsttj||dS(N(RtRvR](RxRR((s./usb/backend/libusb10.pytrelease_interfacescCs|jtj|||||S(N(t_LibUSB__writeRvRi(RxRRRtdatattimeout((s./usb/backend/libusb10.pyt bulk_writes  cCs|jtj|||||S(N(t _LibUSB__readRvRi(RxRRRtsizeR((s./usb/backend/libusb10.pyt bulk_reads  cCs|jtj|||||S(N(RRvRj(RxRRRRR((s./usb/backend/libusb10.pyt intr_writes  cCs|jtj|||||S(N(RRvRj(RxRRRRR((s./usb/backend/libusb10.pyt intr_reads  c Cstjj|tjjkr'|}ntjd|d}|j\} } | |j9} ttj |||||t | t t | |} tjj|tjjkr| j S|| j SdS(NtBt(R7R=tctrl_directiontCTRL_OUTtarrayt buffer_infotitemsizeRtRvRhtcastRRRp( RxRt bmRequestTypetbRequesttwValuetwIndextdata_or_wLengthRtbufftaddrtlengthtret((s./usb/backend/libusb10.pyt ctrl_transfers"      cCsttj|dS(N(RtRvR_(RxR((s./usb/backend/libusb10.pyt reset_device!scCstttj||S(N(tboolRtRvR`(RxRR((s./usb/backend/libusb10.pytis_kernel_driver_active%scCsttj||dS(N(RtRvRa(RxRR((s./usb/backend/libusb10.pytdetach_kernel_driver)scCsttj||dS(N(RtRvRb(RxRR((s./usb/backend/libusb10.pytattach_kernel_driver-sc CsV|j\}}t} t|||t|tt|t| || jS(N(RRRtRRRRRp( RxtfnRRRRRtaddressRt transferred((s./usb/backend/libusb10.pyt__write1s    c Csptjdd|}|j\}} t} t|||t|tt| t| ||| j S(NRR( RRRRtRRRRRp( RxRRRRRRtbufferRRR((s./usb/backend/libusb10.pyt__read<s    (RRRRDRRRRRRRRRRRRRRRRRRRRRR(((s./usb/backend/libusb10.pyRs,      cCsby6tdkr.tatttantSWn%tk r]tj ddt dSXdS(Ns Error loading libusb 1.0 backendR9( RvR?RNRlRt_initRRCRDRERF(((s./usb/backend/libusb10.pyRHs      (4R<t ctypes.utiltusb.utilR7RR@tloggingt usb._debugRt __author__t__all__t getLoggerRDt_LIBUSB_SUCCESSt_LIBUSB_ERROR_IOt_LIBUSB_ERROR_INVALID_PARAMt_LIBUSB_ERROR_ACCESSt_LIBUSB_ERROR_NO_DEVICEt_LIBUSB_ERROR_NOT_FOUNDt_LIBUSB_ERROR_BUSYt_LIBUSB_ERROR_TIMEOUTt_LIBUSB_ERROR_OVERFLOWt_LIBUSB_ERROR_PIPEt_LIBUSB_ERROR_INTERRUPTEDt_LIBUSB_ERROR_NO_MEMt_LIBUSB_ERROR_NOT_SUPPORTEDt_LIBUSB_ERROR_OTHERRrt StructureRRR R#R*R?RvRRORXRNRlRttobjectRuR{RRRtbackendtIBackendRR(((s./usb/backend/libusb10.pytsp             quisk-3.6.11/usb/backend/libusb01.py0000644000175000017500000004467111632372224016507 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. from ctypes import * import ctypes.util import os import usb.backend import usb.util import array import sys from usb.core import USBError from usb._debug import methodtrace import logging __author__ = 'Wander Lairson Costa' __all__ = ['get_backend'] _logger = logging.getLogger('usb.backend.libusb01') # usb.h _PC_PATH_MAX = 4 if sys.platform != 'win32': _PATH_MAX = os.pathconf('.', _PC_PATH_MAX) else: _PATH_MAX = 511 # libusb-win32 makes all structures packed, while # default libusb only does for some structures # _PackPolicy defines the structure packing according # to the platform. class _PackPolicy(object): pass if sys.platform == 'win32': _PackPolicy._pack_ = 1 # Data structures class _usb_descriptor_header(Structure): _pack_ = 1 _fields_ = [('blength', c_uint8), ('bDescriptorType', c_uint8)] class _usb_string_descriptor(Structure): _pack_ = 1 _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('wData', c_uint16)] class _usb_endpoint_descriptor(Structure, _PackPolicy): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bEndpointAddress', c_uint8), ('bmAttributes', c_uint8), ('wMaxPacketSize', c_uint16), ('bInterval', c_uint8), ('bRefresh', c_uint8), ('bSynchAddress', c_uint8), ('extra', POINTER(c_uint8)), ('extralen', c_int)] class _usb_interface_descriptor(Structure, _PackPolicy): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bInterfaceNumber', c_uint8), ('bAlternateSetting', c_uint8), ('bNumEndpoints', c_uint8), ('bInterfaceClass', c_uint8), ('bInterfaceSubClass', c_uint8), ('bInterfaceProtocol', c_uint8), ('iInterface', c_uint8), ('endpoint', POINTER(_usb_endpoint_descriptor)), ('extra', POINTER(c_uint8)), ('extralen', c_int)] class _usb_interface(Structure, _PackPolicy): _fields_ = [('altsetting', POINTER(_usb_interface_descriptor)), ('num_altsetting', c_int)] class _usb_config_descriptor(Structure, _PackPolicy): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('wTotalLength', c_uint16), ('bNumInterfaces', c_uint8), ('bConfigurationValue', c_uint8), ('iConfiguration', c_uint8), ('bmAttributes', c_uint8), ('bMaxPower', c_uint8), ('interface', POINTER(_usb_interface)), ('extra', POINTER(c_uint8)), ('extralen', c_int)] class _usb_device_descriptor(Structure, _PackPolicy): _pack_ = 1 _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bcdUSB', c_uint16), ('bDeviceClass', c_uint8), ('bDeviceSubClass', c_uint8), ('bDeviceProtocol', c_uint8), ('bMaxPacketSize0', c_uint8), ('idVendor', c_uint16), ('idProduct', c_uint16), ('bcdDevice', c_uint16), ('iManufacturer', c_uint8), ('iProduct', c_uint8), ('iSerialNumber', c_uint8), ('bNumConfigurations', c_uint8)] class _usb_device(Structure, _PackPolicy): pass class _usb_bus(Structure, _PackPolicy): pass _usb_device._fields_ = [('next', POINTER(_usb_device)), ('prev', POINTER(_usb_device)), ('filename', c_int8 * (_PATH_MAX + 1)), ('bus', POINTER(_usb_bus)), ('descriptor', _usb_device_descriptor), ('config', POINTER(_usb_config_descriptor)), ('dev', c_void_p), ('devnum', c_uint8), ('num_children', c_ubyte), ('children', POINTER(POINTER(_usb_device)))] _usb_bus._fields_ = [('next', POINTER(_usb_bus)), ('prev', POINTER(_usb_bus)), ('dirname', c_char * (_PATH_MAX + 1)), ('devices', POINTER(_usb_device)), ('location', c_uint32), ('root_dev', POINTER(_usb_device))] _usb_dev_handle = c_void_p _lib = None def _load_library(): candidates = ('usb', 'libusb0') for candidate in candidates: libname = ctypes.util.find_library(candidate) if libname is not None: break else: # corner cases # cygwin predefines library names with 'cyg' instead of 'lib' if sys.platform == 'cygwin': try: return CDLL('cygusb0.dll') except: _logger.error('Libusb 0 could not be loaded in cygwin', exc_info=True) raise OSError('USB library could not be found') return CDLL(libname) def _setup_prototypes(lib): # usb_dev_handle *usb_open(struct usb_device *dev); lib.usb_open.argtypes = [POINTER(_usb_device)] lib.usb_open.restype = _usb_dev_handle # int usb_close(usb_dev_handle *dev); lib.usb_close.argtypes = [_usb_dev_handle] # int usb_get_string(usb_dev_handle *dev, # int index, # int langid, # char *buf, # size_t buflen); lib.usb_get_string.argtypes = [ _usb_dev_handle, c_int, c_int, c_char_p, c_size_t ] # int usb_get_string_simple(usb_dev_handle *dev, # int index, # char *buf, # size_t buflen); lib.usb_get_string_simple.argtypes = [ _usb_dev_handle, c_int, c_char_p, c_size_t ] # int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, # int ep, # unsigned char type, # unsigned char index, # void *buf, # int size); lib.usb_get_descriptor_by_endpoint.argtypes = [ _usb_dev_handle, c_int, c_ubyte, c_ubyte, c_void_p, c_int ] # int usb_get_descriptor(usb_dev_handle *udev, # unsigned char type, # unsigned char index, # void *buf, # int size); lib.usb_get_descriptor.argtypes = [ _usb_dev_handle, c_ubyte, c_ubyte, c_void_p, c_int ] # int usb_bulk_write(usb_dev_handle *dev, # int ep, # const char *bytes, # int size, # int timeout); lib.usb_bulk_write.argtypes = [ _usb_dev_handle, c_int, c_char_p, c_int, c_int ] # int usb_bulk_read(usb_dev_handle *dev, # int ep, # char *bytes, # int size, # int timeout); lib.usb_bulk_read.argtypes = [ _usb_dev_handle, c_int, c_char_p, c_int, c_int ] # int usb_interrupt_write(usb_dev_handle *dev, # int ep, # const char *bytes, # int size, # int timeout); lib.usb_interrupt_write.argtypes = [ _usb_dev_handle, c_int, c_char_p, c_int, c_int ] # int usb_interrupt_read(usb_dev_handle *dev, # int ep, # char *bytes, # int size, # int timeout); lib.usb_interrupt_read.argtypes = [ _usb_dev_handle, c_int, c_char_p, c_int, c_int ] # int usb_control_msg(usb_dev_handle *dev, # int requesttype, # int request, # int value, # int index, # char *bytes, # int size, # int timeout); lib.usb_control_msg.argtypes = [ _usb_dev_handle, c_int, c_int, c_int, c_int, c_char_p, c_int, c_int ] # int usb_set_configuration(usb_dev_handle *dev, int configuration); lib.usb_set_configuration.argtypes = [_usb_dev_handle, c_int] # int usb_claim_interface(usb_dev_handle *dev, int interface); lib.usb_claim_interface.argtypes = [_usb_dev_handle, c_int] # int usb_release_interface(usb_dev_handle *dev, int interface); lib.usb_release_interface.argtypes = [_usb_dev_handle, c_int] # int usb_set_altinterface(usb_dev_handle *dev, int alternate); lib.usb_set_altinterface.argtypes = [_usb_dev_handle, c_int] # int usb_resetep(usb_dev_handle *dev, unsigned int ep); lib.usb_resetep.argtypes = [_usb_dev_handle, c_int] # int usb_clear_halt(usb_dev_handle *dev, unsigned int ep); lib.usb_clear_halt.argtypes = [_usb_dev_handle, c_int] # int usb_reset(usb_dev_handle *dev); lib.usb_reset.argtypes = [_usb_dev_handle] # char *usb_strerror(void); lib.usb_strerror.argtypes = [] lib.usb_strerror.restype = c_char_p # void usb_set_debug(int level); lib.usb_set_debug.argtypes = [c_int] # struct usb_device *usb_device(usb_dev_handle *dev); lib.usb_device.argtypes = [_usb_dev_handle] lib.usb_device.restype = POINTER(_usb_device) # struct usb_bus *usb_get_busses(void); lib.usb_get_busses.restype = POINTER(_usb_bus) def _check(retval): if retval is None: errmsg = _lib.usb_strerror() else: ret = int(retval) if ret < 0: errmsg = _lib.usb_strerror() # No error means that we need to get the error # message from the return code # Thanks to Nicholas Wheeler to point out the problem... # Also see issue #2860940 if errmsg.lower() == 'no error': errmsg = os.strerror(-ret) else: return ret raise USBError(errmsg) # implementation of libusb 0.1.x backend class _LibUSB(usb.backend.IBackend): @methodtrace(_logger) def enumerate_devices(self): _check(_lib.usb_find_busses()) _check(_lib.usb_find_devices()) bus = _lib.usb_get_busses() while bool(bus): dev = bus[0].devices while bool(dev): yield dev[0] dev = dev[0].next bus = bus[0].next @methodtrace(_logger) def get_device_descriptor(self, dev): return dev.descriptor @methodtrace(_logger) def get_configuration_descriptor(self, dev, config): if config >= dev.descriptor.bNumConfigurations: raise IndexError('Invalid configuration index ' + str(config)) return dev.config[config] @methodtrace(_logger) def get_interface_descriptor(self, dev, intf, alt, config): cfgdesc = self.get_configuration_descriptor(dev, config) if intf >= cfgdesc.bNumInterfaces: raise IndexError('Invalid interface index ' + str(interface)) interface = cfgdesc.interface[intf] if alt >= interface.num_altsetting: raise IndexError('Invalid alternate setting index ' + str(alt)) return interface.altsetting[alt] @methodtrace(_logger) def get_endpoint_descriptor(self, dev, ep, intf, alt, config): interface = self.get_interface_descriptor(dev, intf, alt, config) if ep >= interface.bNumEndpoints: raise IndexError('Invalid endpoint index ' + str(ep)) return interface.endpoint[ep] @methodtrace(_logger) def open_device(self, dev): return _check(_lib.usb_open(dev)) @methodtrace(_logger) def close_device(self, dev_handle): _check(_lib.usb_close(dev_handle)) @methodtrace(_logger) def set_configuration(self, dev_handle, config_value): _check(_lib.usb_set_configuration(dev_handle, config_value)) @methodtrace(_logger) def set_interface_altsetting(self, dev_handle, intf, altsetting): _check(_lib.usb_set_altinterface(dev_handle, altsetting)) @methodtrace(_logger) def claim_interface(self, dev_handle, intf): _check(_lib.usb_claim_interface(dev_handle, intf)) @methodtrace(_logger) def release_interface(self, dev_handle, intf): _check(_lib.usb_release_interface(dev_handle, intf)) @methodtrace(_logger) def bulk_write(self, dev_handle, ep, intf, data, timeout): return self.__write(_lib.usb_bulk_write, dev_handle, ep, intf, data, timeout) @methodtrace(_logger) def bulk_read(self, dev_handle, ep, intf, size, timeout): return self.__read(_lib.usb_bulk_read, dev_handle, ep, intf, size, timeout) @methodtrace(_logger) def intr_write(self, dev_handle, ep, intf, data, timeout): return self.__write(_lib.usb_interrupt_write, dev_handle, ep, intf, data, timeout) @methodtrace(_logger) def intr_read(self, dev_handle, ep, intf, size, timeout): return self.__read(_lib.usb_interrupt_read, dev_handle, ep, intf, size, timeout) @methodtrace(_logger) def ctrl_transfer(self, dev_handle, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout): if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: address, length = data_or_wLength.buffer_info() length *= data_or_wLength.itemsize return _check(_lib.usb_control_msg( dev_handle, bmRequestType, bRequest, wValue, wIndex, cast(address, c_char_p), length, timeout )) else: buffer = array.array('B', '\x00' * data_or_wLength) read = int(_check(_lib.usb_control_msg( dev_handle, bmRequestType, bRequest, wValue, wIndex, cast(buffer.buffer_info()[0], c_char_p), data_or_wLength, timeout ))) return buffer[:read] @methodtrace(_logger) def reset_device(self, dev_handle): _check(_lib.usb_reset(dev_handle)) @methodtrace(_logger) def detach_kernel_driver(self, dev_handle, intf): _check(_lib.usb_detach_kernel_driver_np(dev_handle, intf)) def __write(self, fn, dev_handle, ep, intf, data, timeout): address, length = data.buffer_info() return int(_check(fn( dev_handle, ep, cast(address, c_char_p), length, timeout ))) def __read(self, fn, dev_handle, ep, intf, size, timeout): buffer = array.array('B', '\x00' * size) address, length = buffer.buffer_info() ret = int(_check(fn( dev_handle, ep, cast(address, c_char_p), length, timeout ))) return buffer[:ret] def get_backend(): global _lib try: if _lib is None: _lib = _load_library() _setup_prototypes(_lib) _lib.usb_init() return _LibUSB() except Exception: _logger.error('Error loading libusb 0.1 backend', exc_info=True) return None quisk-3.6.11/usb/backend/__init__.pyc0000644000175000017500000003601412146140542016755 0ustar jimjim00000000000000 iNc@sAdZdZddddgZdZdefdYZdS( s?usb.backend - Backend interface. This module exports: IBackend - backend interface. Backends are Python objects which implement the IBackend interface. The easiest way to do so is inherinting from IBackend. PyUSB already provides backends for libusb versions 0.1 and 1.0, and OpenUSB library. Backends modules included with PyUSB are required to export the get_backend() function, which returns an instance of a backend object. You can provide your own customized backend if you want to. Bellow you find a skeleton of a backend implementation module: import usb.backend class MyBackend(usb.backend.IBackend): pass def get_backend(): return MyBackend() You can use your customized backend by passing it as the backend parameter of the usb.core.find() function. For example: import custom_backend import usb.core myidVendor = 0xfffe myidProduct = 0x0001 mybackend = custom_backend.get_backend() dev = usb.core.find(backend = mybackend, idProduct=myidProduct, idVendor=myidVendor) For custom backends, you are not required to supply the get_backend() function, since the application code will instantiate the backend. If you do not provide a backend to the find() function, it will use one of the defaults backend according to its internal rules. For details, consult the find() function documentation. sWander Lairson CostatIBackendtlibusb01tlibusb10topenusbcCst|jdS(N(tNotImplementedErrort__name__(tfunc((s./usb/backend/__init__.pyt_not_implementedNscBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZRS(sBackend interface. IBackend is the basic interface for backend implementations. By default, the methods of the interface raise a NotImplementedError exception. A backend implementation should replace the methods to provide the funcionality necessary. As Python is a dynamic typed language, you are not obligated to inherit from IBackend: everything that bahaves like an IBackend is an IBackend. But you are strongly recommended to do so, inheriting from IBackend provides consistent default behavior. cCst|jdS(sThis function is required to return an iterable object which yields an implementation defined device identification for each USB device found in the system. The device identification object is used as argument to other methods of the interface. N(Rtenumerate_devices(tself((s./usb/backend/__init__.pyR^scCst|jdS(skReturn the device descriptor of the given device. The object returned is required to have all the Device Descriptor fields accessible as member variables. They must be convertible (but not required to be equal) to the int type. dev is an object yielded by the iterator returned by the enumerate_devices() method. N(Rtget_device_descriptor(R tdev((s./usb/backend/__init__.pyR hs cCst|jdS(sWReturn a configuration descriptor of the given device. The object returned is required to have all the Configuration Descriptor fields acessible as member variables. They must be convertible (but not required to be equal) to the int type. The dev parameter is the already described device identification object. config is the logical index of the configuration (not the bConfigurationValue field). By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. N(Rtget_configuration_descriptor(R R tconfig((s./usb/backend/__init__.pyR ts cCst|jdS(sReturn an interface descriptor of the given device. The object returned is required to have all the Interface Descriptor fields accessible as member variables. They must be convertible (but not required to be equal) to the int type. The dev parameter is the already described device identification object. The intf parameter is the interface logical index (not the bInterfaceNumber field) and alt is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alt parameter should be zero. config is the configuration logical index (not the bConfigurationValue field). N(Rtget_interface_descriptor(R R tintftaltR ((s./usb/backend/__init__.pyRscCst|jdS(sReturn an endpoint descriptor of the given device. The object returned is required to have all the Endpoint Descriptor fields acessible as member variables. They must be convertible (but not required to be equal) to the int type. The ep parameter is the endpoint logical index (not the bEndpointAddress field) of the endpoint descriptor desired. intf, alt and config are the same values already described in the get_interface_descriptor() method. N(Rtget_endpoint_descriptor(R R tepRRR ((s./usb/backend/__init__.pyRs cCst|jdS(sOpen the device for data exchange. This method opens the device identified by the dev parameter for communication. This method must be called before calling any communication related method, such as transfer methods. It returns a handle identifying the communication instance. This handle must be passed to the communication methods. N(Rt open_device(R R ((s./usb/backend/__init__.pyRs cCst|jdS(sClose the device handle. This method closes the device communication channel and releases any system resources related to it. N(Rt close_device(R t dev_handle((s./usb/backend/__init__.pyRscCst|jdS(sNSet the active device configuration. This method should be called to set the active configuration of the device. The dev_handle parameter is the value returned by the open_device() method and the config_value parameter is the bConfigurationValue field of the related configuration descriptor. N(Rtset_configuration(R Rt config_value((s./usb/backend/__init__.pyRscCst|jdS(s]Set the interface alternate setting. This method should only be called when the interface has more than one alternate setting. The dev_handle is the value returned by the open_device() method. intf and altsetting are respectivelly the bInterfaceNumber and bAlternateSetting fields of the related interface. N(Rtset_interface_altsetting(R RRt altsetting((s./usb/backend/__init__.pyRscCst|jdS(sClaim the given interface. Interface claiming is not related to USB spec itself, but it is generally an necessary call of the USB libraries. It requests exclusive access to the interface on the system. This method must be called before using one of the transfer methods. dev_handle is the value returned by the open_device() method and intf is the bInterfaceNumber field of the desired interface. N(Rtclaim_interface(R RR((s./usb/backend/__init__.pyRs cCst|jdS(sRelease the claimed interface. dev_handle and intf are the same parameters of the claim_interface method. N(Rtrelease_interface(R RR((s./usb/backend/__init__.pyRscCst|jdS(sPerform a bulk write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent. It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. N(Rt bulk_write(R RRRtdatattimeout((s./usb/backend/__init__.pyRs cCst|jdS(sPerform a bulk read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. N(Rt bulk_read(R RRRtsizeR((s./usb/backend/__init__.pyRs cCst|jdS(s#Perform an interrupt write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent. It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. N(Rt intr_write(R RRRRR((s./usb/backend/__init__.pyR!s cCst|jdS(s Perform an interrut read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. N(Rt intr_read(R RRRR R((s./usb/backend/__init__.pyR"s cCst|jdS(s$Perform an isochronous write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent.It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. N(Rt iso_write(R RRRRR((s./usb/backend/__init__.pyR#s cCst|jdS(sPerform an isochronous read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. N(Rtiso_read(R RRRR R((s./usb/backend/__init__.pyR$%s cCst|jdS(sIPerform a control transfer on the endpoint 0. The direction of the transfer is inferred from the bmRequestType field of the setup packet. dev_handle is the value returned by the open_device() method. bmRequestType, bRequest, wValue and wIndex are the same fields of the setup packet. data_or_wLength is either the payload to be sent to the device, if any, as an array.array object (None there is no payload) for OUT requests in the data stage or the wLength field specifying the number of bytes to read for IN requests in the data stage. The timeout parameter specifies a time limit to the operation in miliseconds. Return the number of bytes written (for OUT transfers) or the data read (for IN transfers), as an array.array object. N(Rt ctrl_transfer(R Rt bmRequestTypetbRequesttwValuetwIndextdata_or_wLengthR((s./usb/backend/__init__.pyR%3scCst|jdS(sReset the device.N(Rt reset_device(R R((s./usb/backend/__init__.pyR+NscCst|jdS(sDetermine if a kernel driver is active on an interface. If a kernel driver is active, you cannot claim the interface, and the backend will be unable to perform I/O. N(Rtis_kernel_driver_active(R RR((s./usb/backend/__init__.pyR,RscCst|jdS(sDetach a kernel driver from an interface. If successful, you will then be able to claim the interface and perform I/O. N(Rtdetach_kernel_driver(R RR((s./usb/backend/__init__.pyR-ZscCst|jdS(skRe-attach an interface's kernel driver, which was previously detached using detach_kernel_driver().N(Rtattach_kernel_driver(R RR((s./usb/backend/__init__.pyR.bs(Rt __module__t__doc__RR R RRRRRRRRRRR!R"R#R$R%R+R,R-R.(((s./usb/backend/__init__.pyRQs.               N(R0t __author__t__all__RtobjectR(((s./usb/backend/__init__.pytHs quisk-3.6.11/usb/backend/openusb.pyc0000644000175000017500000003523712146140542016677 0ustar jimjim00000000000000 iNc@sddlTddlZddlZddlZddlmZddlZdZdgZ ej dZ de fdYZ d e fd YZd e fd YZd e fdYZde fdYZde fdYZde fdYZde fdYZde fdYZde fdYZeZeZeZeZdadadZdZ dZ!de"fdYZ#d e"fd!YZ$d"e"fd#YZ%d$ej&j'fd%YZ(d&Z)dS('i(t*N(t methodtracesWander Lairson Costat get_backendsusb.backend.openusbt_usb_endpoint_descc BsVeZdefdefdefdefdefdefdefdefgZRS(tbLengthtbDescriptorTypetbEndpointAddresst bmAttributestwMaxPacketSizet bIntervaltbRefresht bSynchAddress(t__name__t __module__tc_uint8tc_uint16t_fields_(((s./usb/backend/openusb.pyR*s       t_usb_interface_descc Bs_eZdefdefdefdefdefdefdefdefdefg ZRS( RRtbInterfaceNumbertbAlternateSettingt bNumEndpointstbInterfaceClasstbInterfaceSubClasstbInterfaceProtocolt iInterface(R R RR(((s./usb/backend/openusb.pyR4s        t_usb_config_descc BsVeZdefdefdefdefdefdefdefdefgZRS(RRt wTotalLengthtbNumInterfacestbConfigurationValuetiConfigurationRt bMaxPower(R R RRR(((s./usb/backend/openusb.pyR?s       t_usb_device_desccBseZdefdefdefdefdefdefdefdefdefd efd efd efd efd efgZRS(RRtbcdUSBt bDeviceClasstbDeviceSubClasstbDeviceProtocoltbMaxPacketSize0tidVendort idProductt bcdDevicet iManufacturertiProductt iSerialNumbertbNumConfigurations(R R RRR(((s./usb/backend/openusb.pyRIs             t_openusb_request_resultcBs eZdefdefgZRS(tstatusttransfered_bytes(R R tc_int32tc_uint32R(((s./usb/backend/openusb.pyR,Ys t_openusb_ctrl_requestcBs`eZdefdYZdeefdefdefdefdefdefgZ RS(t_openusb_ctrl_setupcBs2eZdefdefdefdefgZRS(t bmRequestTypetbRequesttwValuetwIndex(R R RRR(((s./usb/backend/openusb.pyR2^s   tpayloadtlengthttimeouttflagstresulttnext( R R t StructureR2tPOINTERRR0R,tc_void_pR(((s./usb/backend/openusb.pyR1]s    t_openusb_intr_requestcBsSeZdefdeefdefdefdefdefdefgZRS(tintervalR7R8R9R:R;R<( R R RR>RR0R,R?R(((s./usb/backend/openusb.pyR@js     t_openusb_bulk_requestcBsJeZdeefdefdefdefdefdefgZRS(R7R8R9R:R;R<(R R R>RR0R,R?R(((s./usb/backend/openusb.pyRBss     t_openusb_isoc_pktscBs<eZdefdYZdefdeefgZRS(t_openusb_isoc_packetcBs&eZdeefdefgZRS(R7R8(R R R>RR0R(((s./usb/backend/openusb.pyRD|st num_packetstpackets(R R R=RDR0R>R(((s./usb/backend/openusb.pyRC{s t_openusb_isoc_requestcBsJeZdefdefdefdeefdefdefgZRS(t start_frameR:tpktst isoc_resultst isoc_statusR<( R R R0RCR>R,R/R?R(((s./usb/backend/openusb.pyRGs     cCs7tjjd}|dkr-tdnt|S(NtopenusbsUSB library could not be found(tctypestutilt find_librarytNonetOSErrortCDLL(tlibname((s./usb/backend/openusb.pyt _load_librarys c CsCtttg|j_t|j_tg|j_tttt ttg|j _tt g|j _tt ttt ttg|j _t|j _tt g|j_tt tttg|j_t|j_tg|j_t|j_ttg|j_t|j_tttg|j_t|j_ttg|j_t|j_tttg|j_t|j_tg|j_t|j_tt tttttg|j_t|j_tt ttttttg|j_t|j_tt ttttttttg|j_t|j_tt ttttttttt g |j!_t|j_tg|j"_t#|j"_ttttt$g|j%_t|j%_ttttt&g|j'_t|j(_ttttt)g|j(_t|j(_ttttt*g|j+_t|j+_dS(N(,R0R>t_openusb_handlet openusb_inittargtypesR/RLtrestypet openusb_finit_openusb_busidtopenusb_get_busid_listtopenusb_free_busid_listt_openusb_devidtopenusb_get_devids_by_bustopenusb_free_devid_listt_openusb_dev_handletopenusb_open_devicetopenusb_close_deviceRtopenusb_set_configurationtc_inttopenusb_claim_interfacetopenusb_release_interfacetopenusb_set_altsettingt openusb_resetRRtopenusb_parse_device_descRtopenusb_parse_config_descRtopenusb_parse_interface_descRtopenusb_parse_endpoint_desctopenusb_strerrortc_char_pR1topenusb_ctrl_xferR@topenusb_intr_xfertopenusb_bulk_xferRBRGtopenusb_isoc_xfer(tlib((s./usb/backend/openusb.pyt_setup_prototypess                     cCs>|jdkr:ddlm}|tj|jn|S(Nii(tUSBError(tvaluetusb.coreRut_libRm(tretvalRu((s./usb/backend/openusb.pyt_checkwst_ContextcBseZdZdZRS(cCs/t|_ttjdt|jdS(Ni(RUthandleRzRxRVtbyref(tself((s./usb/backend/openusb.pyt__init__~s cCstj|jdS(N(RxRYR|(R~((s./usb/backend/openusb.pyt__del__s(R R RR(((s./usb/backend/openusb.pyR{}s t _BusIteratorcBs#eZdZdZdZRS(cCsVtt|_t}ttjtjt |jt ||j |_ dS(N( R>t openusb_busidtbuslistR0RzRxR[t_ctxR|R}Rvt num_busids(R~R((s./usb/backend/openusb.pyRs   ccs*x#t|jD]}|j|VqWdS(N(trangeRR(R~ti((s./usb/backend/openusb.pyt__iter__scCstj|jdS(N(RxR\R(R~((s./usb/backend/openusb.pyRs(R R RRR(((s./usb/backend/openusb.pyRs  t _DevIteratorcBs#eZdZdZdZRS(cCsYtt|_t}ttjtj|t |jt ||j |_ dS(N( R>R]tdevlistR0RzRxR^RR|R}Rvt num_devids(R~tbusidR((s./usb/backend/openusb.pyRs  ccs*x#t|jD]}|j|VqWdS(N(RRR(R~R((s./usb/backend/openusb.pyRscCstj|jdS(N(RxR_R(R~((s./usb/backend/openusb.pyRs(R R RRR(((s./usb/backend/openusb.pyRs  t_OpenUSBcBsmeZeedZeedZeedZeedZeedZeedZ eedZ eedZ eedZ eed Z eed Zeed Zeed Zeed ZeedZeedZeedZRS(ccs4x-tD]"}xt|D] }|VqWq WdS(N(RR(R~tbustdevid((s./usb/backend/openusb.pytenumerate_devicesscCs5t}ttjtj|ddt||S(Ni(RRzRxRiRR|RPR}(R~tdevtdesc((s./usb/backend/openusb.pytget_device_descriptors c Cs8t}ttjtj|dd|t||S(Ni(RRzRxRjRR|RPR}(R~RtconfigR((s./usb/backend/openusb.pytget_configuration_descriptors c Cs>t}ttjtj|dd|||t||S(Ni(RRzRxRkRR|RPR}(R~RtintftaltRR((s./usb/backend/openusb.pytget_interface_descriptors c CsAt}ttjtj|dd||||t| |S(Ni(RRzRxRlRR|RPR}(R~RtepRRRR((s./usb/backend/openusb.pytget_endpoint_descriptors cCs2t}ttjtj|dt||S(Ni(R`RzRxRaRR|R}(R~RR|((s./usb/backend/openusb.pyt open_devices %cCstj|dS(N(RxRb(R~t dev_handle((s./usb/backend/openusb.pyt close_devicescCsttj||dS(N(RzRxRc(R~Rt config_value((s./usb/backend/openusb.pytset_configurationscCsttj|||dS(N(RzRxtset_altsetting(R~RRt altsetting((s./usb/backend/openusb.pytset_interface_altsettingscCsttj||ddS(Ni(RzRxRe(R~RR((s./usb/backend/openusb.pytclaim_interfacescCstj||dS(N(RxRf(R~RR((s./usb/backend/openusb.pytrelease_interfacescCsrt}tt|dt||j\|_|_||_tt j |||t||j j S(Ni( RBtmemsetR}tsizeoft buffer_infoR7R8R9RzRxRqR.Rv(R~RRRtdataR9trequest((s./usb/backend/openusb.pyt bulk_writes   "cCst}tjdd|}tt|dt||j\|_|_||_t t j |||t|||j j S(NtBti(RBtarrayRR}RRR7R8R9RzRxRqR.Rv(R~RRRtsizeR9Rtbuffer((s./usb/backend/openusb.pyt bulk_reads  "cCst}tt|dt||j\}|_t|tt|_ ||_ t t j |||t||jjS(Ni(R@RR}RRR8tcastR>RR7R9RzRxRpR.Rv(R~RRRRR9RR7((s./usb/backend/openusb.pyt intr_writes  "c Cst}tjdd|}tt|dt||j\}|_t|tt |_ ||_ t t j|||t|||jj S(NRRi(R@RRR}RRR8RR>RR7R9RzRxRpR.Rv( R~RRRRR9RRR7((s./usb/backend/openusb.pyt intr_reads  "c Cst}||j_||j_|jj|jj||_tjj |} | t kre|} nt j dd|} | j \} |_ t| tt|_ttj|ddt|} | t kr| n| | dS(NRRi(R1tsetupR3R4R5R6R9tusbRNtctrl_directiont ENDPOINT_OUTRRR8RR>RR7RzRxRoR}( R~RR3R4R5R6tdata_or_wLengthR9Rt directionRR7tret((s./usb/backend/openusb.pyt ctrl_transfer#s        $ cCsttj|dS(N(RzRxRh(R~R((s./usb/backend/openusb.pyt reset_deviceDs(R R Rt_loggerRRRRRRRRRRRRRRRRR(((s./usb/backend/openusb.pyRs"      !cCsby6tdkr.tatttantSWn%tk r]tj ddt dSXdS(NsError loading OpenUSB backendtexc_info( RxRPRTRtR{RRt ExceptionRterrortTrue(((s./usb/backend/openusb.pyRHs      (*RMt ctypes.utiltusb.utilRtsyst usb._debugRtloggingt __author__t__all__t getLoggerRR=RRRRR,R1R@RBRCRGtc_uint64R]RZRUR`RPRxRRTRtRztobjectR{RRtbackendtIBackendRR(((s./usb/backend/openusb.pyts@             quisk-3.6.11/usb/backend/libusb10.py0000644000175000017500000005145111632372224016501 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. from ctypes import * import ctypes.util import usb.util import array import sys import logging from usb._debug import methodtrace __author__ = 'Wander Lairson Costa' __all__ = ['get_backend'] _logger = logging.getLogger('usb.backend.libusb10') # libusb.h # return codes _LIBUSB_SUCCESS = 0 _LIBUSB_ERROR_IO = -1 _LIBUSB_ERROR_INVALID_PARAM = -2 _LIBUSB_ERROR_ACCESS = -3 _LIBUSB_ERROR_NO_DEVICE = -4 _LIBUSB_ERROR_NOT_FOUND = -5 _LIBUSB_ERROR_BUSY = -6 _LIBUSB_ERROR_TIMEOUT = -7 _LIBUSB_ERROR_OVERFLOW = -8 _LIBUSB_ERROR_PIPE = -9 _LIBUSB_ERROR_INTERRUPTED = -10 _LIBUSB_ERROR_NO_MEM = -11 _LIBUSB_ERROR_NOT_SUPPORTED = -12 _LIBUSB_ERROR_OTHER = -99 # map return codes to strings _str_error = { _LIBUSB_SUCCESS:'Success (no error)', _LIBUSB_ERROR_IO:'Input/output error', _LIBUSB_ERROR_INVALID_PARAM:'Invalid parameter', _LIBUSB_ERROR_ACCESS:'Access denied (insufficient permissions)', _LIBUSB_ERROR_NO_DEVICE:'No such device (it may have been disconnected)', _LIBUSB_ERROR_NOT_FOUND:'Entity not found', _LIBUSB_ERROR_BUSY:'Resource busy', _LIBUSB_ERROR_TIMEOUT:'Operation timed out', _LIBUSB_ERROR_OVERFLOW:'Overflow', _LIBUSB_ERROR_PIPE:'Pipe error', _LIBUSB_ERROR_INTERRUPTED:'System call interrupted (perhaps due to signal)', _LIBUSB_ERROR_NO_MEM:'Insufficient memory', _LIBUSB_ERROR_NOT_SUPPORTED:'Operation not supported or unimplemented on this platform', _LIBUSB_ERROR_OTHER:'Unknown error' } # Data structures class _libusb_endpoint_descriptor(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bEndpointAddress', c_uint8), ('bmAttributes', c_uint8), ('wMaxPacketSize', c_uint16), ('bInterval', c_uint8), ('bRefresh', c_uint8), ('bSynchAddress', c_uint8), ('extra', POINTER(c_ubyte)), ('extra_length', c_int)] class _libusb_interface_descriptor(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bInterfaceNumber', c_uint8), ('bAlternateSetting', c_uint8), ('bNumEndpoints', c_uint8), ('bInterfaceClass', c_uint8), ('bInterfaceSubClass', c_uint8), ('bInterfaceProtocol', c_uint8), ('iInterface', c_uint8), ('endpoint', POINTER(_libusb_endpoint_descriptor)), ('extra', POINTER(c_ubyte)), ('extra_length', c_int)] class _libusb_interface(Structure): _fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)), ('num_altsetting', c_int)] class _libusb_config_descriptor(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('wTotalLength', c_uint16), ('bNumInterfaces', c_uint8), ('bConfigurationValue', c_uint8), ('iConfiguration', c_uint8), ('bmAttributes', c_uint8), ('bMaxPower', c_uint8), ('interface', POINTER(_libusb_interface)), ('extra', POINTER(c_ubyte)), ('extra_length', c_int)] class _libusb_device_descriptor(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bcdUSB', c_uint16), ('bDeviceClass', c_uint8), ('bDeviceSubClass', c_uint8), ('bDeviceProtocol', c_uint8), ('bMaxPacketSize0', c_uint8), ('idVendor', c_uint16), ('idProduct', c_uint16), ('bcdDevice', c_uint16), ('iManufacturer', c_uint8), ('iProduct', c_uint8), ('iSerialNumber', c_uint8), ('bNumConfigurations', c_uint8)] _lib = None _init = None _libusb_device_handle = c_void_p def _load_library(): candidates = ('usb-1.0', 'libusb-1.0', 'usb') for candidate in candidates: libname = ctypes.util.find_library(candidate) if libname is not None: break else: # corner cases # cygwin predefines library names with 'cyg' instead of 'lib' if sys.platform == 'cygwin': try: return CDLL('cygusb-1.0-0.dll') except Exception: _logger.error('Libusb 1.0 could not be loaded in cygwin', exc_info=True) raise OSError('USB library could not be found') # Windows backend uses stdcall calling convention if sys.platform == 'win32': l = WinDLL(libname) else: l = CDLL(libname) # On FreeBSD 8/9, libusb 1.0 and libusb 0.1 are in the same shared # object libusb.so, so if we found libusb library name, we must assure # it is 1.0 version. We just try to get some symbol from 1.0 version if not hasattr(l, 'libusb_init'): raise OSError('USB library could not be found') return l def _setup_prototypes(lib): # void libusb_set_debug (libusb_context *ctx, int level) lib.libusb_set_debug.argtypes = [c_void_p, c_int] # int libusb_init (libusb_context **context) lib.libusb_init.argtypes = [POINTER(c_void_p)] # void libusb_exit (struct libusb_context *ctx) lib.libusb_exit.argtypes = [c_void_p] # ssize_t libusb_get_device_list (libusb_context *ctx, # libusb_device ***list) lib.libusb_get_device_list.argtypes = [ c_void_p, POINTER(POINTER(c_void_p)) ] # void libusb_free_device_list (libusb_device **list, # int unref_devices) lib.libusb_free_device_list.argtypes = [ POINTER(c_void_p), c_int ] # libusb_device *libusb_ref_device (libusb_device *dev) lib.libusb_ref_device.argtypes = [c_void_p] lib.libusb_ref_device.restype = c_void_p # void libusb_unref_device(libusb_device *dev) lib.libusb_unref_device.argtypes = [c_void_p] # int libusb_open(libusb_device *dev, libusb_device_handle **handle) lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)] # void libusb_close(libusb_device_handle *dev_handle) lib.libusb_close.argtypes = [_libusb_device_handle] # int libusb_set_configuration(libusb_device_handle *dev, # int configuration) lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int] # int libusb_claim_interface(libusb_device_handle *dev, # int interface_number) lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int] # int libusb_release_interface(libusb_device_handle *dev, # int interface_number) lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int] # int libusb_set_interface_alt_setting(libusb_device_handle *dev, # int interface_number, # int alternate_setting) lib.libusb_set_interface_alt_setting.argtypes = [ _libusb_device_handle, c_int, c_int ] # int libusb_reset_device (libusb_device_handle *dev) lib.libusb_reset_device.argtypes = [_libusb_device_handle] # int libusb_kernel_driver_active(libusb_device_handle *dev, # int interface) lib.libusb_kernel_driver_active.argtypes = [ _libusb_device_handle, c_int ] # int libusb_detach_kernel_driver(libusb_device_handle *dev, # int interface) lib.libusb_detach_kernel_driver.argtypes = [ _libusb_device_handle, c_int ] # int libusb_attach_kernel_driver(libusb_device_handle *dev, # int interface) lib.libusb_attach_kernel_driver.argtypes = [ _libusb_device_handle, c_int ] # int libusb_get_device_descriptor( # libusb_device *dev, # struct libusb_device_descriptor *desc # ) lib.libusb_get_device_descriptor.argtypes = [ c_void_p, POINTER(_libusb_device_descriptor) ] # int libusb_get_config_descriptor( # libusb_device *dev, # uint8_t config_index, # struct libusb_config_descriptor **config # ) lib.libusb_get_config_descriptor.argtypes = [ c_void_p, c_uint8, POINTER(POINTER(_libusb_config_descriptor)) ] # void libusb_free_config_descriptor( # struct libusb_config_descriptor *config # ) lib.libusb_free_config_descriptor.argtypes = [ POINTER(_libusb_config_descriptor) ] # int libusb_get_string_descriptor_ascii(libusb_device_handle *dev, # uint8_t desc_index, # unsigned char *data, # int length) lib.libusb_get_string_descriptor_ascii.argtypes = [ _libusb_device_handle, c_uint8, POINTER(c_ubyte), c_int ] # int libusb_control_transfer(libusb_device_handle *dev_handle, # uint8_t bmRequestType, # uint8_t bRequest, # uint16_t wValue, # uint16_t wIndex, # unsigned char *data, # uint16_t wLength, # unsigned int timeout) lib.libusb_control_transfer.argtypes = [ _libusb_device_handle, c_uint8, c_uint8, c_uint16, c_uint16, POINTER(c_ubyte), c_uint16, c_uint ] #int libusb_bulk_transfer( # struct libusb_device_handle *dev_handle, # unsigned char endpoint, # unsigned char *data, # int length, # int *transferred, # unsigned int timeout # ) lib.libusb_bulk_transfer.argtypes = [ _libusb_device_handle, c_ubyte, POINTER(c_ubyte), c_int, POINTER(c_int), c_uint ] # int libusb_interrupt_transfer( # libusb_device_handle *dev_handle, # unsigned char endpoint, # unsigned char *data, # int length, # int *actual_length, # unsigned int timeout # ); lib.libusb_interrupt_transfer.argtypes = [ _libusb_device_handle, c_ubyte, POINTER(c_ubyte), c_int, POINTER(c_int), c_uint ] # check a libusb function call def _check(retval): if isinstance(retval, int): retval = c_int(retval) if isinstance(retval, c_int): if retval.value < 0: from usb.core import USBError raise USBError(_str_error[retval.value]) return retval # wrap a device class _Device(object): def __init__(self, devid): self.devid = _lib.libusb_ref_device(devid) def __del__(self): _lib.libusb_unref_device(self.devid) # wrap a descriptor and keep a reference to another object # Thanks to Thomas Reitmayr. class _WrapDescriptor(object): def __init__(self, desc, obj = None): self.obj = obj self.desc = desc def __getattr__(self, name): return getattr(self.desc, name) # wrap a configuration descriptor class _ConfigDescriptor(object): def __init__(self, desc): self.desc = desc def __del__(self): _lib.libusb_free_config_descriptor(self.desc) def __getattr__(self, name): return getattr(self.desc.contents, name) # initialize and finalize the library class _Initializer(object): def __init__(self): _check(_lib.libusb_init(None)) def __del__(self): _lib.libusb_exit(None) # iterator for libusb devices class _DevIterator(object): def __init__(self): self.dev_list = POINTER(c_void_p)() self.num_devs = _check(_lib.libusb_get_device_list( None, byref(self.dev_list)) ).value def __iter__(self): for i in range(self.num_devs): yield _Device(self.dev_list[i]) def __del__(self): _lib.libusb_free_device_list(self.dev_list, 1) # implementation of libusb 1.0 backend class _LibUSB(usb.backend.IBackend): @methodtrace(_logger) def enumerate_devices(self): return _DevIterator() @methodtrace(_logger) def get_device_descriptor(self, dev): dev_desc = _libusb_device_descriptor() _check(_lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc))) return dev_desc @methodtrace(_logger) def get_configuration_descriptor(self, dev, config): cfg = POINTER(_libusb_config_descriptor)() _check(_lib.libusb_get_config_descriptor(dev.devid, config, byref(cfg))) return _ConfigDescriptor(cfg) @methodtrace(_logger) def get_interface_descriptor(self, dev, intf, alt, config): cfg = self.get_configuration_descriptor(dev, config) if intf >= cfg.bNumInterfaces: raise IndexError('Invalid interface index ' + str(intf)) i = cfg.interface[intf] if alt >= i.num_altsetting: raise IndexError('Invalid alternate setting index ' + str(alt)) return _WrapDescriptor(i.altsetting[alt], cfg) @methodtrace(_logger) def get_endpoint_descriptor(self, dev, ep, intf, alt, config): i = self.get_interface_descriptor(dev, intf, alt, config) if ep > i.bNumEndpoints: raise IndexError('Invalid endpoint index ' + str(ep)) return _WrapDescriptor(i.endpoint[ep], i) @methodtrace(_logger) def open_device(self, dev): handle = _libusb_device_handle() _check(_lib.libusb_open(dev.devid, byref(handle))) return handle @methodtrace(_logger) def close_device(self, dev_handle): _lib.libusb_close(dev_handle) @methodtrace(_logger) def set_configuration(self, dev_handle, config_value): _check(_lib.libusb_set_configuration(dev_handle, config_value)) @methodtrace(_logger) def set_interface_altsetting(self, dev_handle, intf, altsetting): _check(_lib.libusb_set_interface_alt_setting(dev_handle, intf, altsetting)) @methodtrace(_logger) def claim_interface(self, dev_handle, intf): _check(_lib.libusb_claim_interface(dev_handle, intf)) @methodtrace(_logger) def release_interface(self, dev_handle, intf): _check(_lib.libusb_release_interface(dev_handle, intf)) @methodtrace(_logger) def bulk_write(self, dev_handle, ep, intf, data, timeout): return self.__write(_lib.libusb_bulk_transfer, dev_handle, ep, intf, data, timeout) @methodtrace(_logger) def bulk_read(self, dev_handle, ep, intf, size, timeout): return self.__read(_lib.libusb_bulk_transfer, dev_handle, ep, intf, size, timeout) @methodtrace(_logger) def intr_write(self, dev_handle, ep, intf, data, timeout): return self.__write(_lib.libusb_interrupt_transfer, dev_handle, ep, intf, data, timeout) @methodtrace(_logger) def intr_read(self, dev_handle, ep, intf, size, timeout): return self.__read(_lib.libusb_interrupt_transfer, dev_handle, ep, intf, size, timeout) # TODO: implement isochronous # @methodtrace(_logger) # def iso_write(self, dev_handle, ep, intf, data, timeout): # pass # @methodtrace(_logger) # def iso_read(self, dev_handle, ep, intf, size, timeout): # pass @methodtrace(_logger) def ctrl_transfer(self, dev_handle, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout): if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: buff = data_or_wLength else: buff = array.array('B', data_or_wLength * '\x00') addr, length = buff.buffer_info() length *= buff.itemsize ret = _check(_lib.libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, cast(addr, POINTER(c_ubyte)), length, timeout)) if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: return ret.value else: return buff[:ret.value] @methodtrace(_logger) def reset_device(self, dev_handle): _check(_lib.libusb_reset_device(dev_handle)) @methodtrace(_logger) def is_kernel_driver_active(self, dev_handle, intf): return bool(_check(_lib.libusb_kernel_driver_active(dev_handle, intf))) @methodtrace(_logger) def detach_kernel_driver(self, dev_handle, intf): _check(_lib.libusb_detach_kernel_driver(dev_handle, intf)) @methodtrace(_logger) def attach_kernel_driver(self, dev_handle, intf): _check(_lib.libusb_attach_kernel_driver(dev_handle, intf)) def __write(self, fn, dev_handle, ep, intf, data, timeout): address, length = data.buffer_info() transferred = c_int() _check(fn(dev_handle, ep, cast(address, POINTER(c_ubyte)), length, byref(transferred), timeout)) return transferred.value def __read(self, fn, dev_handle, ep, intf, size, timeout): buffer = array.array('B', '\x00' * size) address, length = buffer.buffer_info() transferred = c_int() _check(fn(dev_handle, ep, cast(address, POINTER(c_ubyte)), length, byref(transferred), timeout)) return buffer[:transferred.value] def get_backend(): global _lib, _init try: if _lib is None: _lib = _load_library() _setup_prototypes(_lib) _init = _Initializer() return _LibUSB() except Exception: _logger.error('Error loading libusb 1.0 backend', exc_info=True) return None quisk-3.6.11/usb/backend/libusb01.pyc0000644000175000017500000003073612146140542016644 0ustar jimjim00000000000000 iNc @sddlTddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl Z dZ dgZe jdZdZejd krejd eZnd Zd efd YZejd krde_ndefdYZdefdYZdeefdYZdeefdYZdeefdYZdeefdYZdeefdYZdeefdYZ deefd YZ!d!e"e fd"e"e fd#e#edfd$e"e!fd%efd&e"efd'e$fd(e%fd)e&fd*e"e"e fg e _'d!e"e!fd"e"e!fd+e(edfd,e"e fd-e)fd.e"e fge!_'e$Z*da,d/Z-d0Z.d1Z/d2ej0j1fd3YZ2d4Z3dS(5i(t*N(tUSBError(t methodtracesWander Lairson Costat get_backendsusb.backend.libusb01itwin32t.it _PackPolicycBseZRS((t__name__t __module__(((s./usb/backend/libusb01.pyR;sit_usb_descriptor_headercBs&eZdZdefdefgZRS(itblengthtbDescriptorType(RRt_pack_tc_uint8t_fields_(((s./usb/backend/libusb01.pyR Cs t_usb_string_descriptorcBs/eZdZdefdefdefgZRS(itbLengthR twData(RRR R tc_uint16R(((s./usb/backend/libusb01.pyRHs  t_usb_endpoint_descriptorc BsneZdefdefdefdefdefdefdefdefdeefd efg ZRS( RR tbEndpointAddresst bmAttributestwMaxPacketSizet bIntervaltbRefresht bSynchAddresstextratextralen(RRR RtPOINTERtc_intR(((s./usb/backend/libusb01.pyRNs        t_usb_interface_descriptorc BseZdefdefdefdefdefdefdefdefdefd eefd eefd efg ZRS( RR tbInterfaceNumbertbAlternateSettingt bNumEndpointstbInterfaceClasstbInterfaceSubClasstbInterfaceProtocolt iInterfacetendpointRR(RRR RRRR(((s./usb/backend/libusb01.pyRZs         t_usb_interfacecBs&eZdeefdefgZRS(t altsettingtnum_altsetting(RRRRRR(((s./usb/backend/libusb01.pyR'hst_usb_config_descriptorc Bs}eZdefdefdefdefdefdefdefdefdeefd eefd efg ZRS( RR t wTotalLengthtbNumInterfacestbConfigurationValuetiConfigurationRt bMaxPowert interfaceRR(RRR RRR'RR(((s./usb/backend/libusb01.pyR*ls        t_usb_device_descriptorcBseZdZdefdefdefdefdefdefdefdefd efd efd efd efd efdefgZRS(iRR tbcdUSBt bDeviceClasstbDeviceSubClasstbDeviceProtocoltbMaxPacketSize0tidVendort idProductt bcdDevicet iManufacturertiProductt iSerialNumbertbNumConfigurations(RRR R RR(((s./usb/backend/libusb01.pyR1ys             t _usb_devicecBseZRS((RR(((s./usb/backend/libusb01.pyR>st_usb_buscBseZRS((RR(((s./usb/backend/libusb01.pyR?stnexttprevtfilenametbust descriptortconfigtdevtdevnumt num_childrentchildrentdirnametdevicestlocationtroot_devcCsd}xy|D](}tjj|}|dk r Pq q WtjdkrvytdSWqvtjddt qvXnt dt|S( Ntusbtlibusb0tcygwins cygusb0.dlls&Libusb 0 could not be loaded in cygwintexc_infosUSB library could not be found(susbRO( tctypestutilt find_librarytNonetsystplatformtCDLLt_loggerterrortTruetOSError(t candidatest candidatetlibname((s./usb/backend/libusb01.pyt _load_librarys   cCsttg|j_t|j_tg|j_ttttt g|j _tttt g|j _ttt t t tg|j_tt t t tg|j_tttttg|j_tttttg|j_tttttg|j_tttttg|j_ttttttttg|j_ttg|j_ttg|j_ttg|j_ttg|j_ttg|j_ttg|j_tg|j_g|j_t|j_tg|j_tg|j_tt|j_tt|j _dS(N(!RR>tusb_opentargtypest_usb_dev_handletrestypet usb_closeRtc_char_ptc_size_ttusb_get_stringtusb_get_string_simpletc_ubytetc_void_ptusb_get_descriptor_by_endpointtusb_get_descriptortusb_bulk_writet usb_bulk_readtusb_interrupt_writetusb_interrupt_readtusb_control_msgtusb_set_configurationtusb_claim_interfacetusb_release_interfacetusb_set_altinterfacet usb_reseteptusb_clear_haltt usb_resett usb_strerrort usb_set_debugt usb_deviceR?tusb_get_busses(tlib((s./usb/backend/libusb01.pyt_setup_prototypess          cCs{|dkrtj}nPt|}|dkrgtj}|jdkrktj| }qkn|St|dS(Nisno error(RUt_libRztinttlowertoststrerrorR(tretvalterrmsgtret((s./usb/backend/libusb01.pyt_check]s    t_LibUSBcBseZeedZeedZeedZeedZeedZeedZ eedZ eedZ eedZ eed Z eed Zeed Zeed Zeed ZeedZeedZeedZeedZdZdZRS(ccsttjttjtj}xSt|r|dj}x&t|rp|dV|dj}qKW|dj}q/WdS(Ni(RRtusb_find_bussestusb_find_devicesR}tboolRKR@(tselfRCRF((s./usb/backend/libusb01.pytenumerate_devicesps   cCs|jS(N(RD(RRF((s./usb/backend/libusb01.pytget_device_descriptor~scCs6||jjkr+tdt|n|j|S(NsInvalid configuration index (RDR=t IndexErrortstrRE(RRFRE((s./usb/backend/libusb01.pytget_configuration_descriptorscCsz|j||}||jkr:tdt|n|j|}||jkrotdt|n|j|S(NsInvalid interface index s Invalid alternate setting index (RR,RRR0R)R((RRFtintftaltREtcfgdescR0((s./usb/backend/libusb01.pytget_interface_descriptors cCsK|j||||}||jkr@tdt|n|j|S(NsInvalid endpoint index (RR!RRR&(RRFtepRRRER0((s./usb/backend/libusb01.pytget_endpoint_descriptorscCsttj|S(N(RRRa(RRF((s./usb/backend/libusb01.pyt open_devicescCsttj|dS(N(RRRe(Rt dev_handle((s./usb/backend/libusb01.pyt close_devicescCsttj||dS(N(RRRs(RRt config_value((s./usb/backend/libusb01.pytset_configurationscCsttj||dS(N(RRRv(RRRR(((s./usb/backend/libusb01.pytset_interface_altsettingscCsttj||dS(N(RRRt(RRR((s./usb/backend/libusb01.pytclaim_interfacescCsttj||dS(N(RRRu(RRR((s./usb/backend/libusb01.pytrelease_interfacescCs|jtj|||||S(N(t_LibUSB__writeRRn(RRRRtdatattimeout((s./usb/backend/libusb01.pyt bulk_writes  cCs|jtj|||||S(N(t _LibUSB__readRRo(RRRRtsizeR((s./usb/backend/libusb01.pyt bulk_reads  cCs|jtj|||||S(N(RRRp(RRRRRR((s./usb/backend/libusb01.pyt intr_writes  cCs|jtj|||||S(N(RRRq(RRRRRR((s./usb/backend/libusb01.pyt intr_reads  c Cstjj|tjjkrn|j\}} | |j9} ttj|||||t |t | |St j dd|} t ttj|||||t | jdt ||} | | SdS(NtBti( RNRStctrl_directiontCTRL_OUTt buffer_infotitemsizeRRRrtcastRftarrayR( RRt bmRequestTypetbRequesttwValuetwIndextdata_or_wLengthRtaddresstlengthtbuffertread((s./usb/backend/libusb01.pyt ctrl_transfers0      cCsttj|dS(N(RRRy(RR((s./usb/backend/libusb01.pyt reset_devicescCsttj||dS(N(RRtusb_detach_kernel_driver_np(RRR((s./usb/backend/libusb01.pytdetach_kernel_driversc Cs=|j\}}tt|||t|t||S(N(RRRRRf( RtfnRRRRRRR((s./usb/backend/libusb01.pyt__writes  c Cs]tjdd|}|j\}} tt|||t|t| |} || S(NRR(RRRRRRf( RRRRRRRRRRR((s./usb/backend/libusb01.pyt__read s  (RRRRYRRRRRRRRRRRRRRRRRRRR(((s./usb/backend/libusb01.pyRos(    % cCscy7tdkr/tatttjntSWn%tk r^tjddt dSXdS(Ns Error loading libusb 0.1 backendRQ( RRUR`Rtusb_initRt ExceptionRYRZR[(((s./usb/backend/libusb01.pyRs      (4RRt ctypes.utilRt usb.backendRNtusb.utilRRVtusb.coreRt usb._debugRtloggingt __author__t__all__t getLoggerRYt _PC_PATH_MAXRWtpathconft _PATH_MAXtobjectRR t StructureR RRRR'R*R1R>R?Rtc_int8RkR RjRtc_chartc_uint32RcRURR`RRtbackendtIBackendRR(((s./usb/backend/libusb01.pytsf                   quisk-3.6.11/usb/backend/openusb.py0000644000175000017500000005361011632372224016532 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. from ctypes import * import ctypes.util import usb.util import sys from usb._debug import methodtrace import logging __author__ = 'Wander Lairson Costa' __all__ = ['get_backend'] _logger = logging.getLogger('usb.backend.openusb') class _usb_endpoint_desc(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bEndpointAddress', c_uint8), ('bmAttributes', c_uint8), ('wMaxPacketSize', c_uint16), ('bInterval', c_uint8), ('bRefresh', c_uint8), ('bSynchAddress', c_uint8)] class _usb_interface_desc(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bInterfaceNumber', c_uint8), ('bAlternateSetting', c_uint8), ('bNumEndpoints', c_uint8), ('bInterfaceClass', c_uint8), ('bInterfaceSubClass', c_uint8), ('bInterfaceProtocol', c_uint8), ('iInterface', c_uint8)] class _usb_config_desc(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('wTotalLength', c_uint16), ('bNumInterfaces', c_uint8), ('bConfigurationValue', c_uint8), ('iConfiguration', c_uint8), ('bmAttributes', c_uint8), ('bMaxPower', c_uint8)] class _usb_device_desc(Structure): _fields_ = [('bLength', c_uint8), ('bDescriptorType', c_uint8), ('bcdUSB', c_uint16), ('bDeviceClass', c_uint8), ('bDeviceSubClass', c_uint8), ('bDeviceProtocol', c_uint8), ('bMaxPacketSize0', c_uint8), ('idVendor', c_uint16), ('idProduct', c_uint16), ('bcdDevice', c_uint16), ('iManufacturer', c_uint8), ('iProduct', c_uint8), ('iSerialNumber', c_uint8), ('bNumConfigurations', c_uint8)] class _openusb_request_result(Structure): _fields_ = [('status', c_int32), ('transfered_bytes', c_uint32)] class _openusb_ctrl_request(Structure): class _openusb_ctrl_setup(Structure): _fields_ = [('bmRequestType', c_uint8), ('bRequest', c_uint8), ('wValue', c_uint16), ('wIndex', c_uint16)] _fields_ = [('payload', POINTER(c_uint8)), ('length', c_uint32), ('timeout', c_uint32), ('flags', c_uint32), ('result', _openusb_request_result), ('next', c_void_p)] class _openusb_intr_request(Structure): _fields_ = [('interval', c_uint16), ('payload', POINTER(c_uint8)), ('length', c_uint32), ('timeout', c_uint32), ('flags', c_uint32), ('result', _openusb_request_result), ('next', c_void_p)] class _openusb_bulk_request(Structure): _fields_ = [('payload', POINTER(c_uint8)), ('length', c_uint32), ('timeout', c_uint32), ('flags', c_uint32), ('result', _openusb_request_result), ('next', c_void_p)] class _openusb_isoc_pkts(Structure): class _openusb_isoc_packet(Structure): _fields_ = [('payload', POINTER(c_uint8)), ('length', c_uint32)] _fields_ = [('num_packets', c_uint32), ('packets', POINTER(_openusb_isoc_packet))] class _openusb_isoc_request(Structure): _fields_ = [('start_frame', c_uint32), ('flags', c_uint32), ('pkts', _openusb_isoc_pkts), ('isoc_results', POINTER(_openusb_request_result)), ('isoc_status', c_int32), ('next', c_void_p)] _openusb_devid = c_uint64 _openusb_busid = c_uint64 _openusb_handle = c_uint64 _openusb_dev_handle = c_uint64 _lib = None _ctx = None def _load_library(): libname = ctypes.util.find_library('openusb') if libname is None: raise OSError('USB library could not be found') return CDLL(libname) def _setup_prototypes(lib): # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle); lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)] lib.openusb.restype = c_int32 # void openusb_fini(openusb_handle_t handle ); lib.openusb_fini.argtypes = [_openusb_handle] # uint32_t openusb_get_busid_list(openusb_handle_t handle, # openusb_busid_t **busids, # uint32_t *num_busids); lib.openusb_get_busid_list.argtypes = [ _openusb_handle, POINTER(POINTER(_openusb_busid)), POINTER(c_uint32) ] # void openusb_free_busid_list(openusb_busid_t * busids); lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)] # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle, # openusb_busid_t busid, # openusb_devid_t **devids, # uint32_t *num_devids); lib.openusb_get_devids_by_bus.argtypes = [ _openusb_handle, _openusb_busid, POINTER(POINTER(_openusb_devid)), POINTER(c_uint32) ] lib.openusb_get_devids_by_bus.restype = c_int32 # void openusb_free_devid_list(openusb_devid_t * devids); lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)] # int32_t openusb_open_device(openusb_handle_t handle, # openusb_devid_t devid , # uint32_t flags, # openusb_dev_handle_t *dev); lib.openusb_open_device.argtypes = [ _openusb_handle, _openusb_devid, c_uint32, POINTER(_openusb_dev_handle) ] lib.openusb_open_device.restype = c_int32 # int32_t openusb_close_device(openusb_dev_handle_t dev); lib.openusb_close_device.argtypes = [_openusb_dev_handle] lib.openusb_close_device.restype = c_int32 # int32_t openusb_set_configuration(openusb_dev_handle_t dev, # uint8_t cfg); lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8] lib.openusb_set_configuration.restype = c_int32 # int32_t openusb_claim_interface(openusb_dev_handle_t dev, # uint8_t ifc, # openusb_init_flag_t flags); lib.openusb_claim_interface.argtypes = [ _openusb_dev_handle, c_uint8, c_int ] lib.openusb_claim_interface.restype = c_int32 # int32_t openusb_release_interface(openusb_dev_handle_t dev, # uint8_t ifc); lib.openusb_release_interface.argtypes = [ _openusb_dev_handle, c_uint8 ] lib.openusb_release_interface.restype = c_int32 # int32_topenusb_set_altsetting(openusb_dev_handle_t dev, # uint8_t ifc, # uint8_t alt); lib.openusb_set_altsetting.argtypes = [ _openusb_dev_handle, c_uint8, c_uint8 ] lib.openusb_set_altsetting.restype = c_int32 # int32_t openusb_reset(openusb_dev_handle_t dev); lib.openusb_reset.argtypes = [_openusb_dev_handle] lib.openusb_reset.restype = c_int32 # int32_t openusb_parse_device_desc(openusb_handle_t handle, # openusb_devid_t devid, # uint8_t *buffer, # uint16_t buflen, # usb_device_desc_t *devdesc); lib.openusb_parse_device_desc.argtypes = [ _openusb_handle, _openusb_devid, POINTER(c_uint8), c_uint16, POINTER(_usb_device_desc) ] lib.openusb_parse_device_desc.restype = c_int32 # int32_t openusb_parse_config_desc(openusb_handle_t handle, # openusb_devid_t devid, # uint8_t *buffer, # uint16_t buflen, # uint8_t cfgidx, # usb_config_desc_t *cfgdesc); lib.openusb_parse_config_desc.argtypes = [ _openusb_handle, _openusb_devid, POINTER(c_uint8), c_uint16, c_uint8, POINTER(_usb_config_desc) ] lib.openusb_parse_config_desc.restype = c_int32 # int32_t openusb_parse_interface_desc(openusb_handle_t handle, # openusb_devid_t devid, # uint8_t *buffer, # uint16_t buflen, # uint8_t cfgidx, # uint8_t ifcidx, # uint8_t alt, # usb_interface_desc_t *ifcdesc); lib.openusb_parse_interface_desc.argtypes = [ _openusb_handle, _openusb_devid, POINTER(c_uint8), c_uint16, c_uint8, c_uint8, c_uint8, POINTER(_usb_interface_desc) ] lib.openusb_parse_interface_desc.restype = c_int32 # int32_t openusb_parse_endpoint_desc(openusb_handle_t handle, # openusb_devid_t devid, # uint8_t *buffer, # uint16_t buflen, # uint8_t cfgidx, # uint8_t ifcidx, # uint8_t alt, # uint8_t eptidx, # usb_endpoint_desc_t *eptdesc); lib.openusb_parse_endpoint_desc.argtypes = [ _openusb_handle, _openusb_devid, POINTER(c_uint8), c_uint16, c_uint8, c_uint8, c_uint8, c_uint8, POINTER(_usb_endpoint_desc) ] lib.openusb_parse_interface_desc.restype = c_int32 # const char *openusb_strerror(int32_t error ); lib.openusb_strerror.argtypes = [c_int32] lib.openusb_strerror.restype = c_char_p # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev, # uint8_t ifc, # uint8_t ept, # openusb_ctrl_request_t *ctrl); lib.openusb_ctrl_xfer.argtypes = [ _openusb_dev_handle, c_uint8, c_uint8, POINTER(_openusb_ctrl_request) ] lib.openusb_ctrl_xfer.restype = c_int32 # int32_t openusb_intr_xfer(openusb_dev_handle_t dev, # uint8_t ifc, # uint8_t ept, # openusb_intr_request_t *intr); lib.openusb_intr_xfer.argtypes = [ _openusb_dev_handle, c_uint8, c_uint8, POINTER(_openusb_intr_request) ] lib.openusb_bulk_xfer.restype = c_int32 # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev, # uint8_t ifc, # uint8_t ept, # openusb_bulk_request_t *bulk); lib.openusb_bulk_xfer.argtypes = [ _openusb_dev_handle, c_uint8, c_uint8, POINTER(_openusb_bulk_request) ] lib.openusb_bulk_xfer.restype = c_int32 # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev, # uint8_t ifc, # uint8_t ept, # openusb_isoc_request_t *isoc); lib.openusb_isoc_xfer.argtypes = [ _openusb_dev_handle, c_uint8, c_uint8, POINTER(_openusb_isoc_request) ] lib.openusb_isoc_xfer.restype = c_int32 def _check(retval): if retval.value != 0: from usb.core import USBError raise USBError(_lib.openusb_strerror(retval).value) return retval class _Context(object): def __init__(self): self.handle = _openusb_handle() _check(_lib.openusb_init(0, byref(self.handle))) def __del__(self): _lib.openusb_fini(self.handle) class _BusIterator(object): def __init__(self): self.buslist = POINTER(openusb_busid)() num_busids = c_uint32() _check(_lib.openusb_get_busid_list(_ctx.handle, byref(self.buslist), byref(num_busids))) self.num_busids = num_busids.value def __iter__(self): for i in range(self.num_busids): yield self.buslist[i] def __del__(self): _lib.openusb_free_busid_list(self.buslist) class _DevIterator(object): def __init__(self, busid): self.devlist = POINTER(_openusb_devid)() num_devids = c_uint32() _check(_lib.openusb_get_devids_by_bus(_ctx.handle, busid, byref(self.devlist), byref(num_devids))) self.num_devids = num_devids.value def __iter__(self): for i in range(self.num_devids): yield self.devlist[i] def __del__(self): _lib.openusb_free_devid_list(self.devlist) class _OpenUSB(usb.backend.IBackend): @methodtrace(_logger) def enumerate_devices(self): for bus in _BusIterator(): for devid in _DevIterator(bus): yield devid @methodtrace(_logger) def get_device_descriptor(self, dev): desc = _usb_device_desc() _check(_lib.openusb_parse_device_desc(_ctx.handle, dev, None, 0, byref(desc))) return desc @methodtrace(_logger) def get_configuration_descriptor(self, dev, config): desc = _usb_config_desc() _check(_lib.openusb_parse_config_desc(_ctx.handle, dev, None, 0, config, byref(desc))) return desc @methodtrace(_logger) def get_interface_descriptor(self, dev, intf, alt, config): desc = _usb_interface_desc() _check(_lib.openusb_parse_interface_desc(_ctx.handle, dev, None, 0, config, intf, alt, byref(desc))) return desc @methodtrace(_logger) def get_endpoint_descriptor(self, dev, ep, intf, alt, config): desc = _usb_endpoint_desc() _check(_lib.openusb_parse_endpoint_desc(_ctx.handle, dev, None, 0, config, intf, alt, ep, byref(desc))) return desc @methodtrace(_logger) def open_device(self, dev): handle = _openusb_dev_handle() _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle))) return handle @methodtrace(_logger) def close_device(self, dev_handle): _lib.openusb_close_device(dev_handle) @methodtrace(_logger) def set_configuration(self, dev_handle, config_value): _check(_lib.openusb_set_configuration(dev_handle, config_value)) @methodtrace(_logger) def set_interface_altsetting(self, dev_handle, intf, altsetting): _check(_lib.set_altsetting(dev_handle, intf, altsetting)) @methodtrace(_logger) def claim_interface(self, dev_handle, intf): _check(_lib.openusb_claim_interface(dev_handle, intf, 0)) @methodtrace(_logger) def release_interface(self, dev_handle, intf): _lib.openusb_release_interface(dev_handle, intf) @methodtrace(_logger) def bulk_write(self, dev_handle, ep, intf, data, timeout): request = _openusb_bulk_request() memset(byref(request), 0, sizeof(request)) request.payload, request.length = data.buffer_info() request.timeout = timeout _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request))) return request.transfered_bytes.value @methodtrace(_logger) def bulk_read(self, dev_handle, ep, intf, size, timeout): request = _openusb_bulk_request() buffer = array.array('B', '\x00' * size) memset(byref(request), 0, sizeof(request)) request.payload, request.length = buffer.buffer_info() request.timeout = timeout _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request))) return buffer[:request.transfered_bytes.value] @methodtrace(_logger) def intr_write(self, dev_handle, ep, intf, data, timeout): request = _openusb_intr_request() memset(byref(request), 0, sizeof(request)) payload, request.length = data.buffer_info() request.payload = cast(payload, POINTER(c_uint8)) request.timeout = timeout _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) return request.transfered_bytes.value @methodtrace(_logger) def intr_read(self, dev_handle, ep, intf, size, timeout): request = _openusb_intr_request() buffer = array.array('B', '\x00' * size) memset(byref(request), 0, sizeof(request)) payload, request.length = buffer.buffer_info() request.payload = cast(payload, POINTER(c_uint8)) request.timeout = timeout _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) return buffer[:request.transfered_bytes.value] # TODO: implement isochronous # @methodtrace(_logger) # def iso_write(self, dev_handle, ep, intf, data, timeout): # pass # @methodtrace(_logger) # def iso_read(self, dev_handle, ep, intf, size, timeout): # pass @methodtrace(_logger) def ctrl_transfer(self, dev_handle, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout): request = _openusb_ctrl_request() request.setup.bmRequestType = bmRequestType request.setup.bRequest = bRequest request.setup.wValue request.setup.wIndex request.timeout = timeout direction = usb.util.ctrl_direction(bmRequestType) if direction == ENDPOINT_OUT: buffer = data_or_wLength else: buffer = array.array('B', '\x00' * data_or_wLength) payload, request.length = buffer.buffer_info() request.payload = cast(payload, POINTER(c_uint8)) ret = _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request))) if direction == ENDPOINT_OUT: ret else: buffer[:ret] @methodtrace(_logger) def reset_device(self, dev_handle): _check(_lib.openusb_reset(dev_handle)) def get_backend(): try: global _lib, _ctx if _lib is None: _lib = _load_library() _setup_prototypes(_lib) _ctx = _Context() return _OpenUSB() except Exception: _logger.error('Error loading OpenUSB backend', exc_info=True) return None quisk-3.6.11/usb/backend/__init__.py0000644000175000017500000003556311632372224016625 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. r"""usb.backend - Backend interface. This module exports: IBackend - backend interface. Backends are Python objects which implement the IBackend interface. The easiest way to do so is inherinting from IBackend. PyUSB already provides backends for libusb versions 0.1 and 1.0, and OpenUSB library. Backends modules included with PyUSB are required to export the get_backend() function, which returns an instance of a backend object. You can provide your own customized backend if you want to. Bellow you find a skeleton of a backend implementation module: import usb.backend class MyBackend(usb.backend.IBackend): pass def get_backend(): return MyBackend() You can use your customized backend by passing it as the backend parameter of the usb.core.find() function. For example: import custom_backend import usb.core myidVendor = 0xfffe myidProduct = 0x0001 mybackend = custom_backend.get_backend() dev = usb.core.find(backend = mybackend, idProduct=myidProduct, idVendor=myidVendor) For custom backends, you are not required to supply the get_backend() function, since the application code will instantiate the backend. If you do not provide a backend to the find() function, it will use one of the defaults backend according to its internal rules. For details, consult the find() function documentation. """ __author__ = 'Wander Lairson Costa' __all__ = ['IBackend', 'libusb01', 'libusb10', 'openusb'] def _not_implemented(func): raise NotImplementedError(func.__name__) class IBackend(object): r"""Backend interface. IBackend is the basic interface for backend implementations. By default, the methods of the interface raise a NotImplementedError exception. A backend implementation should replace the methods to provide the funcionality necessary. As Python is a dynamic typed language, you are not obligated to inherit from IBackend: everything that bahaves like an IBackend is an IBackend. But you are strongly recommended to do so, inheriting from IBackend provides consistent default behavior. """ def enumerate_devices(self): r"""This function is required to return an iterable object which yields an implementation defined device identification for each USB device found in the system. The device identification object is used as argument to other methods of the interface. """ _not_implemented(self.enumerate_devices) def get_device_descriptor(self, dev): r"""Return the device descriptor of the given device. The object returned is required to have all the Device Descriptor fields accessible as member variables. They must be convertible (but not required to be equal) to the int type. dev is an object yielded by the iterator returned by the enumerate_devices() method. """ _not_implemented(self.get_device_descriptor) def get_configuration_descriptor(self, dev, config): r"""Return a configuration descriptor of the given device. The object returned is required to have all the Configuration Descriptor fields acessible as member variables. They must be convertible (but not required to be equal) to the int type. The dev parameter is the already described device identification object. config is the logical index of the configuration (not the bConfigurationValue field). By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. """ _not_implemented(self.get_configuration_descriptor) def get_interface_descriptor(self, dev, intf, alt, config): r"""Return an interface descriptor of the given device. The object returned is required to have all the Interface Descriptor fields accessible as member variables. They must be convertible (but not required to be equal) to the int type. The dev parameter is the already described device identification object. The intf parameter is the interface logical index (not the bInterfaceNumber field) and alt is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alt parameter should be zero. config is the configuration logical index (not the bConfigurationValue field). """ _not_implemented(self.get_interface_descriptor) def get_endpoint_descriptor(self, dev, ep, intf, alt, config): r"""Return an endpoint descriptor of the given device. The object returned is required to have all the Endpoint Descriptor fields acessible as member variables. They must be convertible (but not required to be equal) to the int type. The ep parameter is the endpoint logical index (not the bEndpointAddress field) of the endpoint descriptor desired. intf, alt and config are the same values already described in the get_interface_descriptor() method. """ _not_implemented(self.get_endpoint_descriptor) def open_device(self, dev): r"""Open the device for data exchange. This method opens the device identified by the dev parameter for communication. This method must be called before calling any communication related method, such as transfer methods. It returns a handle identifying the communication instance. This handle must be passed to the communication methods. """ _not_implemented(self.open_device) def close_device(self, dev_handle): r"""Close the device handle. This method closes the device communication channel and releases any system resources related to it. """ _not_implemented(self.close_device) def set_configuration(self, dev_handle, config_value): r"""Set the active device configuration. This method should be called to set the active configuration of the device. The dev_handle parameter is the value returned by the open_device() method and the config_value parameter is the bConfigurationValue field of the related configuration descriptor. """ _not_implemented(self.set_configuration) def set_interface_altsetting(self, dev_handle, intf, altsetting): r"""Set the interface alternate setting. This method should only be called when the interface has more than one alternate setting. The dev_handle is the value returned by the open_device() method. intf and altsetting are respectivelly the bInterfaceNumber and bAlternateSetting fields of the related interface. """ _not_implemented(self.set_interface_altsetting) def claim_interface(self, dev_handle, intf): r"""Claim the given interface. Interface claiming is not related to USB spec itself, but it is generally an necessary call of the USB libraries. It requests exclusive access to the interface on the system. This method must be called before using one of the transfer methods. dev_handle is the value returned by the open_device() method and intf is the bInterfaceNumber field of the desired interface. """ _not_implemented(self.claim_interface) def release_interface(self, dev_handle, intf): r"""Release the claimed interface. dev_handle and intf are the same parameters of the claim_interface method. """ _not_implemented(self.release_interface) def bulk_write(self, dev_handle, ep, intf, data, timeout): r"""Perform a bulk write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent. It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. """ _not_implemented(self.bulk_write) def bulk_read(self, dev_handle, ep, intf, size, timeout): r"""Perform a bulk read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. """ _not_implemented(self.bulk_read) def intr_write(self, dev_handle, ep, intf, data, timeout): r"""Perform an interrupt write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent. It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. """ _not_implemented(self.intr_write) def intr_read(self, dev_handle, ep, intf, size, timeout): r"""Perform an interrut read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. """ _not_implemented(self.intr_read) def iso_write(self, dev_handle, ep, intf, data, timeout): r"""Perform an isochronous write. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be sent to. intf is the bInterfaceNumber field of the interface containing the endpoint. The data parameter is the data to be sent.It must be an instance of the array.array class. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns the number of bytes written. """ _not_implemented(self.iso_write) def iso_read(self, dev_handle, ep, intf, size, timeout): r"""Perform an isochronous read. dev_handle is the value returned by the open_device() method. The ep parameter is the bEndpointAddress field whose endpoint the data will be received from. intf is the bInterfaceNumber field of the interface containing the endpoint. The size parameter is the number of bytes to be read. The timeout parameter specifies a time limit to the operation in miliseconds. The method returns an array.array object containing the data read. """ _not_implemented(self.iso_read) def ctrl_transfer(self, dev_handle, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout): r"""Perform a control transfer on the endpoint 0. The direction of the transfer is inferred from the bmRequestType field of the setup packet. dev_handle is the value returned by the open_device() method. bmRequestType, bRequest, wValue and wIndex are the same fields of the setup packet. data_or_wLength is either the payload to be sent to the device, if any, as an array.array object (None there is no payload) for OUT requests in the data stage or the wLength field specifying the number of bytes to read for IN requests in the data stage. The timeout parameter specifies a time limit to the operation in miliseconds. Return the number of bytes written (for OUT transfers) or the data read (for IN transfers), as an array.array object. """ _not_implemented(self.ctrl_transfer) def reset_device(self, dev_handle): r"""Reset the device.""" _not_implemented(self.reset_device) def is_kernel_driver_active(self, dev_handle, intf): r"""Determine if a kernel driver is active on an interface. If a kernel driver is active, you cannot claim the interface, and the backend will be unable to perform I/O. """ _not_implemented(self.is_kernel_driver_active) def detach_kernel_driver(self, dev_handle, intf): r"""Detach a kernel driver from an interface. If successful, you will then be able to claim the interface and perform I/O. """ _not_implemented(self.detach_kernel_driver) def attach_kernel_driver(self, dev_handle, intf): r"""Re-attach an interface's kernel driver, which was previously detached using detach_kernel_driver().""" _not_implemented(self.attach_kernel_driver) quisk-3.6.11/usb/legacy.py0000644000175000017500000002665211632372224014742 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. import usb.core as core import usb.util as util import usb._interop as _interop from usb.core import USBError __author__ = 'Wander Lairson Costa' CLASS_AUDIO = 1 CLASS_COMM = 2 CLASS_DATA = 10 CLASS_HID = 3 CLASS_HUB = 9 CLASS_MASS_STORAGE = 8 CLASS_PER_INTERFACE = 0 CLASS_PRINTER = 7 CLASS_VENDOR_SPEC = 255 DT_CONFIG = 2 DT_CONFIG_SIZE = 9 DT_DEVICE = 1 DT_DEVICE_SIZE = 18 DT_ENDPOINT = 5 DT_ENDPOINT_AUDIO_SIZE = 9 DT_ENDPOINT_SIZE = 7 DT_HID = 33 DT_HUB = 41 DT_HUB_NONVAR_SIZE = 7 DT_INTERFACE = 4 DT_INTERFACE_SIZE = 9 DT_PHYSICAL = 35 DT_REPORT = 34 DT_STRING = 3 ENDPOINT_ADDRESS_MASK = 15 ENDPOINT_DIR_MASK = 128 ENDPOINT_IN = 128 ENDPOINT_OUT = 0 ENDPOINT_TYPE_BULK = 2 ENDPOINT_TYPE_CONTROL = 0 ENDPOINT_TYPE_INTERRUPT = 3 ENDPOINT_TYPE_ISOCHRONOUS = 1 ENDPOINT_TYPE_MASK = 3 ERROR_BEGIN = 500000 MAXALTSETTING = 128 MAXCONFIG = 8 MAXENDPOINTS = 32 MAXINTERFACES = 32 RECIP_DEVICE = 0 RECIP_ENDPOINT = 2 RECIP_INTERFACE = 1 RECIP_OTHER = 3 REQ_CLEAR_FEATURE = 1 REQ_GET_CONFIGURATION = 8 REQ_GET_DESCRIPTOR = 6 REQ_GET_INTERFACE = 10 REQ_GET_STATUS = 0 REQ_SET_ADDRESS = 5 REQ_SET_CONFIGURATION = 9 REQ_SET_DESCRIPTOR = 7 REQ_SET_FEATURE = 3 REQ_SET_INTERFACE = 11 REQ_SYNCH_FRAME = 12 TYPE_CLASS = 32 TYPE_RESERVED = 96 TYPE_STANDARD = 0 TYPE_VENDOR = 64 class Endpoint(object): r"""Endpoint descriptor object.""" def __init__(self, ep): self.address = ep.bEndpointAddress self.interval = ep.bInterval self.maxPacketSize = ep.wMaxPacketSize self.type = util.endpoint_type(ep.bmAttributes) class Interface(object): r"""Interface descriptor object.""" def __init__(self, intf): self.alternateSetting = intf.bAlternateSetting self.interfaceNumber = intf.bInterfaceNumber self.iInterface = intf.iInterface self.interfaceClass = intf.bInterfaceClass self.interfaceSubClass = intf.bInterfaceSubClass self.interfaceProtocol = intf.bInterfaceProtocol self.endpoints = [Endpoint(e) for e in intf] class Configuration(object): r"""Configuration descriptor object.""" def __init__(self, cfg): self.iConfiguration = cfg.iConfiguration self.maxPower = cfg.bMaxPower << 2 self.remoteWakeup = (cfg.bmAttributes >> 5) & 1 self.selfPowered = (cfg.bmAttributes >> 6) & 1 self.totalLength = cfg.wTotalLength self.value = cfg.bConfigurationValue self.interfaces = [ list(g) for k, g in _interop._groupby( _interop._sorted( [Interface(i) for i in cfg], key=lambda i: i.interfaceNumber ), lambda i: i.alternateSetting) ] class DeviceHandle(object): def __init__(self, dev): self.dev = dev self.__claimed_interface = -1 def bulkWrite(self, endpoint, buffer, timeout = 100): r"""Perform a bulk write request to the endpoint specified. Arguments: endpoint: endpoint number. buffer: sequence data buffer to write. This parameter can be any sequence type. timeout: operation timeout in miliseconds. (default: 100) Returns the number of bytes written. """ return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout) def bulkRead(self, endpoint, size, timeout = 100): r"""Performs a bulk read request to the endpoint specified. Arguments: endpoint: endpoint number. size: number of bytes to read. timeout: operation timeout in miliseconds. (default: 100) Return a tuple with the data read. """ return self.dev.read(endpoint, size, self.__claimed_interface, timeout) def interruptWrite(self, endpoint, buffer, timeout = 100): r"""Perform a interrupt write request to the endpoint specified. Arguments: endpoint: endpoint number. buffer: sequence data buffer to write. This parameter can be any sequence type. timeout: operation timeout in miliseconds. (default: 100) Returns the number of bytes written. """ return self.dev.write(endpoint, buffer, self.__claimed_interface, timeout) def interruptRead(self, endpoint, size, timeout = 100): r"""Performs a interrupt read request to the endpoint specified. Arguments: endpoint: endpoint number. size: number of bytes to read. timeout: operation timeout in miliseconds. (default: 100) Return a tuple with the data read. """ return self.dev.read(endpoint, size, self.__claimed_interface, timeout) def controlMsg(self, requestType, request, buffer, value = 0, index = 0, timeout = 100): r"""Perform a control request to the default control pipe on a device. Arguments: requestType: specifies the direction of data flow, the type of request, and the recipient. request: specifies the request. buffer: if the transfer is a write transfer, buffer is a sequence with the transfer data, otherwise, buffer is the number of bytes to read. value: specific information to pass to the device. (default: 0) index: specific information to pass to the device. (default: 0) timeout: operation timeout in miliseconds. (default: 100) Return the number of bytes written. """ return self.dev.ctrl_transfer( requestType, request, wValue = value, wIndex = index, data_or_wLength = buffer, timeout = timeout ) def clearHalt(self, endpoint): r"""Clears any halt status on the specified endpoint. Arguments: endpoint: endpoint number. """ raise NotImplemented('This function has not been implemented yet') def claimInterface(self, interface): r"""Claims the interface with the Operating System. Arguments: interface: interface number or an Interface object. """ util.claim_interface(self.dev, interface) self.__claimed_interface = interface def releaseInterface(self): r"""Release an interface previously claimed with claimInterface.""" util.release_interface(self.dev, self.__claimed_interface) self.__claimed_interface = -1 def reset(self): r"""Reset the specified device by sending a RESET down the port it is connected to.""" self.dev.reset() def resetEndpoint(self, endpoint): r"""Reset all states for the specified endpoint. Arguments: endpoint: endpoint number. """ self.clearHalt(endpoint) def setConfiguration(self, configuration): r"""Set the active configuration of a device. Arguments: configuration: a configuration value or a Configuration object. """ self.dev.set_configuration(configuration) def setAltInterface(self, alternate): r"""Sets the active alternate setting of the current interface. Arguments: alternate: an alternate setting number or an Interface object. """ self.dev.set_interface_altsetting(self.__claimed_interface, alternate) def getString(self, index, len, langid = -1): r"""Retrieve the string descriptor specified by index and langid from a device. Arguments: index: index of descriptor in the device. len: number of bytes of the string langid: Language ID. If it is omittedi, will be used the first language. """ raise NotImplemented('This function has not been implemented yet') def getDescriptor(self, type, index, len, endpoint = -1): r"""Retrieves a descriptor from the device identified by the type and index of the descriptor. Arguments: type: descriptor type. index: index of the descriptor. len: descriptor length. endpoint: endpoint number from descriptor is read. If it is omitted, the descriptor is read from default control pipe. """ raise NotImplemented('This function has not been implemented yet') def detachKernelDriver(self, interface): r"""Detach a kernel driver from the interface (if one is attached, we have permission and the operation is supported by the OS) Arguments: interface: interface number or an Interface object. """ self.dev.detach_kernel_driver(interface) class Device(object): r"""Device descriptor object""" def __init__(self, dev): self.deviceClass = dev.bDeviceClass self.deviceSubClass = dev.bDeviceSubClass self.deviceProtocol = dev.bDeviceProtocol self.deviceVersion = dev.bcdDevice self.devnum = None self.filename = '' self.iManufacturer = dev.iManufacturer self.iProduct = dev.iProduct self.iSerialNumber = dev.iSerialNumber self.idProduct = dev.idProduct self.idVendor = dev.idVendor self.maxPacketSize = dev.bMaxPacketSize0 self.usbVersion = dev.bcdUSB self.configurations = [Configuration(c) for c in dev] self.dev = dev def open(self): r"""Open the device for use. Return a DeviceHandle object """ return DeviceHandle(self.dev) class Bus(object): r"""Bus object.""" def __init__(self): self.dirname = '' self.localtion = 0 self.devices = [Device(d) for d in core.find(find_all=True)] def busses(): r"""Return a tuple with the usb busses.""" return (Bus(),) quisk-3.6.11/usb/_interop.py0000644000175000017500000001077611632372224015315 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. # All the hacks necessary to assure compatibility across all # supported versions come here. # Please, note that there is one version check for each # hack we need to do, this makes maintenance easier... ^^ import sys __all__ = ['_reduce', '_set', '_next', '_groupby', '_sorted', '_update_wrapper'] # we support Python >= 2.3 assert sys.hexversion >= 0x020300f0 # On Python 3, reduce became a functools module function try: import functools _reduce = functools.reduce except (ImportError, AttributeError): _reduce = reduce # we only have the builtin set type since 2.5 version try: _set = set except NameError: import sets _set = sets.Set # On Python >= 2.6, we have the builtin next() function # On Python 2.5 and before, we have to call the iterator method next() def _next(iter): try: return next(iter) except NameError: return iter.next() # groupby is available only since 2.4 version try: import itertools _groupby = itertools.groupby except (ImportError, AttributeError): # stolen from Python docs class _groupby(object): # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D def __init__(self, iterable, key=None): if key is None: key = lambda x: x self.keyfunc = key self.it = iter(iterable) self.tgtkey = self.currkey = self.currvalue = object() def __iter__(self): return self def next(self): while self.currkey == self.tgtkey: self.currvalue = _next(self.it) # Exit on StopIteration self.currkey = self.keyfunc(self.currvalue) self.tgtkey = self.currkey return (self.currkey, self._grouper(self.tgtkey)) def _grouper(self, tgtkey): while self.currkey == tgtkey: yield self.currvalue self.currvalue = _next(self.it) # Exit on StopIteration self.currkey = self.keyfunc(self.currvalue) # builtin sorted function is only availale since 2.4 version try: _sorted = sorted except NameError: def _sorted(l, key=None, reverse=False): # sort function on Python 2.3 does not # support 'key' parameter class KeyToCmp(object): def __init__(self, K): self.key = K def __call__(self, x, y): kx = self.key(x) ky = self.key(y) if kx < ky: return reverse and 1 or -1 elif kx > ky: return reverse and -1 or 1 else: return 0 tmp = list(l) tmp.sort(KeyToCmp(key)) return tmp try: import functools _update_wrapper = functools.update_wrapper except (ImportError, AttributeError): def _update_wrapper(wrapper, wrapped): wrapper.__name__ = wrapped.__name__ wrapper.__module__ = wrapped.__module__ wrapper.__doc__ = wrapped.__doc__ wrapper.__dict__ = wrapped.__dict__ quisk-3.6.11/usb/core.pyc0000644000175000017500000007072012146140537014565 0ustar jimjim00000000000000 iNc@s3dZdZdddddgZddlZddljZddlZddlZddlZddl j Z ddl Z e j d Z d Zd Zd efd YZdefdYZdefdYZdefdYZdefdYZdefdYZeeedZdS(s=usb.core - Core USB features. This module exports: Device - a class representing a USB device. Configuration - a class representing a configuration descriptor. Interface - a class representing an interface descriptor. Endpoint - a class representing an endpoint descriptor. find() - a function to find USB devices. sWander Lairson CostatDevicet Configurationt InterfacetEndpointtfindiNsusb.coreicCs4x-|D]%}t||tt||qWdS(N(tsetattrtinttgetattr(tinputtoutputtfieldstf((s ./usb/core.pyt _set_attr8s t_ResourceManagercBsweZdZdZdZdZdZdZdZdZ dZ d Z d Z e d ZRS( cCsI||_d|_||_d|_tj|_i|_i|_ dS(N( tbackendtNonet_active_cfg_indextdevthandlet_interopt_sett _claimed_intft_alt_sett _ep_type_map(tselftparentRR((s ./usb/core.pyt__init__=s     cCs1|jdkr*|jj|j|_n|jS(N(RRRt open_deviceR(R((s ./usb/core.pyt managed_openEscCs2|jdk r.|jj|jd|_ndS(N(RRRt close_device(R((s ./usb/core.pyt managed_closeIscCs|dkr|d}n-t|tr1|}ntj|d|}|j|jj|j|j |j |_ |j j |jj dS(NitbConfigurationValue(Rt isinstanceRtutiltfind_descriptorRRtset_configurationRRtindexRRtclearR(Rtdevicetconfigtcfg((s ./usb/core.pytmanaged_set_configurationMs      cCs|j|dkr2|j}|dj}n!t|trM|j}n|}||jkr|jj|j ||jj |ndS(Ni(ii( RRtget_active_configurationtbInterfaceNumberR RRRtclaim_interfaceRtadd(RR&tintfR(ti((s ./usb/core.pytmanaged_claim_interface^s    cCs|dkr+|j|}|dj}n!t|trF|j}n|}||jkr|jj|j||jj |ndS(Ni(ii( RR*R+R RRRtrelease_interfaceRtremove(RR&R.R(R/((s ./usb/core.pytmanaged_release_interfacejs  cCs|dkr!|j||}nft|tr9|}nN|j|}|dk rrtj|d|d|}ntj|d|}|j|||dkr|j}n|j j |j |j |||j |j >> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> for i in cfg: >>> for e in i: >>> print e.bEndpointAddress ic Cst||_t||||}|j|_||_|jj}|j|jj||||}t ||d d S( s)Initialize the Endpoint object. The device parameter is the device object returned by the find() function. endpoint is the endpoint logical index (not the endpoint address). The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). The interface parameter is the interface logical index (not the bInterfaceNumber field) and alternate_setting is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alternate_setting parameter should be zero. By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. tbLengthtbDescriptorTypeR9R<twMaxPacketSizet bIntervaltbRefresht bSynchAddressN(RLRMsbEndpointAddresss bmAttributesswMaxPacketSizes bIntervalRPRQ( R&RR+t interfaceR$t_ctxRtget_endpoint_descriptorRR ( RR&tendpointRRtalternate_settingt configurationR.Rtdesc((s ./usb/core.pyRs,      cCs|jj|j||j|S(sfWrite data to the endpoint. The parameter data contains the data to be sent to the endpoint and timeout is the time limit of the operation. The transfer type and endpoint address are automatically inferred. The method returns the number of bytes written. For details, see the Device.write() method. (R&twriteR9RR(Rtdatattimeout((s ./usb/core.pyRYs cCs|jj|j||j|S(sdRead data from the endpoint. The parameter size is the number of bytes to read and timeout is the time limit of the operation.The transfer type and endpoint address are automatically inferred. The method returns an array.array object with the data read. For details, see the Device.read() method. (R&treadR9RR(RtsizeR[((s ./usb/core.pyR\s N(RGRHRKRRRYR\(((s ./usb/core.pyRs , cBs;eZdZddddZdZdZdZRS(sRepresent an interface object. This class contains all fields of the Interface Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bInterfaceNumber of the interface descriptor: >>> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> for i in cfg: >>> print i.bInterfaceNumber ic Cse||_||_||_||_|jj}|j|jjj|||}t||d d S( sInitialize the interface object. The device parameter is the device object returned by the find() function. The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). The interface parameter is the interface logical index (not the bInterfaceNumber field) and alternate_setting is the alternate setting logical index (not the bAlternateSetting value). Not every interface has more than one alternate setting. In this case, the alternate_setting parameter should be zero. By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. RLRMR+R4t bNumEndpointstbInterfaceClasstbInterfaceSubClasstbInterfaceProtocolt iInterfaceN( sbLengthsbDescriptorTypesbInterfaceNumbersbAlternateSettings bNumEndpointssbInterfaceClasssbInterfaceSubClasssbInterfaceProtocols iInterface( R&talternate_indexR$RWRSRtget_interface_descriptorRR (RR&RRRVRWRRX((s ./usb/core.pyR"s,       cCs|jj|j|jdS(s$Set the interface alternate setting.N(R&R6R+R4(R((s ./usb/core.pytset_altsettingNs ccsAx:t|jD])}t|j||j|j|jVqWdS(s,Iterate over all endpoints of the interface.N(trangeR^RR&R$RcRW(RR/((s ./usb/core.pyt__iter__UscCs"t|j||j|j|jS(s1Return the Endpoint object in the given position.(RR&R$RcRW(RR$((s ./usb/core.pyt __getitem___s (RGRHRKRReRgRh(((s ./usb/core.pyRs  +  cBs5eZdZddZdZdZdZRS(sRepresent a configuration object. This class contains all fields of the Configuration Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bConfigurationValue of the configuration descriptor: >>> import usb.core >>> dev = usb.core.find() >>> for cfg in dev: >>> print cfg.bConfigurationValue ic CsM||_||_|jj}|j|jjj|}t||d d S( sInitialize the configuration object. The device parameter is the device object returned by the find() function. The configuration parameter is the logical index of the configuration (not the bConfigurationValue field). By "logical index" we mean the relative order of the configurations returned by the peripheral as a result of GET_DESCRIPTOR request. RLRMt wTotalLengthtbNumInterfacesRtiConfigurationR<t bMaxPowerN(sbLengthsbDescriptorTypes wTotalLengthsbNumInterfacessbConfigurationValuesiConfigurations bmAttributess bMaxPower(R&R$RSRtget_configuration_descriptorRR (RR&RWRRX((s ./usb/core.pyRws"     cCs|jj|jdS(s)Set this configuration as the active one.N(R&R#R(R((s ./usb/core.pytsetsccssxlt|jD][}d}y5x.trOt|j|||jV|d7}q"WWqttfk rjqXqWdS(s1Iterate over all interfaces of the configuration.iiN(RfRjRIRR&R$RJt IndexError(RR/R7((s ./usb/core.pyRgs cCs!t|j|d|d|jS(sReturn the Interface object in the given position. index is a tuple of two values with interface index and alternate setting index, respectivally. Example: >>> interface = config[(0, 0)] ii(RR&R$(RR$((s ./usb/core.pyRhs(RGRHRKRRnRgRh(((s ./usb/core.pyRis   "  cBseZdZdZddZdZdddZddZdZ dddZ dddZ d d ddd Z d Z d Zd ZdZdZdZdZdZdZeeeddZRS(sDevice object. This class contains all fields of the Device Descriptor according to the USB Specification. You may access them as class properties. For example, to access the field bDescriptorType of the device descriptor: >>> import usb.core >>> dev = usb.core.find() >>> dev.bDescriptorType Additionally, the class provides methods to communicate with the hardware. Typically, an application will first call the set_configuration() method to put the device in a known configured state, optionally call the set_interface_altsetting() to select the alternate setting (if there is more than one) of the interface used, and call the write() and read() method to send and receive data. When working in a new hardware, one first try would be like this: >>> import usb.core >>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId) >>> dev.set_configuration() >>> dev.write(1, 'teste') This sample finds the device of interest (myVendorId and myProductId should be replaced by the corresponding values of your device), then configures the device (by default, the configuration value is 1, which is a typical value for most devices) and then writes some data to the endpoint 0x01. Timeout values for the write, read and ctrl_transfer methods are specified in miliseconds. If the parameter is omitted, Device.default_timeout value will be used instead. This property can be set by the user at anytime. cCsAt||||_t|_|j|}t||ddS(sCInitialize the Device object. Library users should normally get a Device instance through the find function. The dev parameter is the identification of a device to the backend and its meaning is opaque outside of it. The backend parameter is a instance of a backend object. RLRMtbcdUSBt bDeviceClasstbDeviceSubClasstbDeviceProtocoltbMaxPacketSize0tidVendort idProductt bcdDevicet iManufacturertiProductt iSerialNumbertbNumConfigurationsN(sbLengthsbDescriptorTypesbcdUSBs bDeviceClasssbDeviceSubClasssbDeviceProtocolsbMaxPacketSize0sidVendors idProducts bcdDevices iManufacturersiProducts iSerialNumbersbNumConfigurations(R RSt_DEFAULT_TIMEOUTt_Device__default_timeouttget_device_descriptorR (RRRRX((s ./usb/core.pyRs(  cCs|jj||dS(sSet the active configuration. The configuration parameter is the bConfigurationValue field of the configuration you want to set as active. If you call this method without parameter, it will use the first configuration found. As a device hardly ever has more than one configuration, calling the method without parameter is enough to get the device ready. N(RSR)(RRW((s ./usb/core.pyR#s cCs|jj|S(sIReturn a Configuration object representing the current configuration set.(RSR*(R((s ./usb/core.pyR*scCs|jj|||dS(sSet the alternate setting for an interface. When you want to use an interface and it has more than one alternate setting, you should call this method to select the alternate setting you would like to use. If you call the method without one or the two parameters, it will be selected the first one found in the Device in the same way of set_configuration method. Commonly, an interface has only one alternate setting and this call is not necessary. For most of the devices, either it has more than one alternate setting or not, it is not harmful to make a call to this method with no arguments, as devices will silently ignore the request when there is only one alternate setting, though the USB Spec allows devices with no additional alternate setting return an error to the Host in response to a SET_INTERFACE request. If you are in doubt, you may want to call it with no arguments wrapped by a try/except clause: >>> try: >>> dev.set_interface_altsetting() >>> except usb.core.USBError: >>> pass N(RSR8(RRRRV((s ./usb/core.pyR6scCs|jj||S(s8Get the active alternate setting of the given interface.(RSR5(RRR((s ./usb/core.pytget_interface_altsetting"scCs0|jj|t|jjj|jjdS(sReset the device.N(RSRFtFalseRt reset_deviceR(R((s ./usb/core.pytreset&sc Cs|jj}i|jtj6|jtj6|jtj6}|jj ||}||jj |||}|jj ||||jj ||j tjd||j|S(sWrite data to the endpoint. This method is used to send data to the device. The endpoint parameter corresponds to the bEndpointAddress member whose endpoint you want to communicate with. The interface parameter is the bInterfaceNumber field of the interface descriptor which contains the endpoint. If you do not provide one, the first one found will be used, as explained in the set_interface_altsetting() method. The data parameter should be a sequence like type convertible to array type (see array module). The timeout is specified in miliseconds. The method returns the number of bytes written. tB(RSRt bulk_writeR!tENDPOINT_TYPE_BULKt intr_writetENDPOINT_TYPE_INTRt iso_writetENDPOINT_TYPE_ISOR5RAR0RR+tarrayt_Device__get_timeout( RRURZRRR[Rtfn_mapR.tfn((s ./usb/core.pyRY+s    c Cs|jj}i|jtj6|jtj6|jtj6}|jj ||}||jj |||}|jj ||||jj ||j ||j|S(sRead data from the endpoint. This method is used to receive data from the device. The endpoint parameter corresponds to the bEndpointAddress member whose endpoint you want to communicate with. The interface parameter is the bInterfaceNumber field of the interface descriptor which contains the endpoint. If you do not provide one, the first one found will be used, as explained in the set_interface_altsetting() method. The size parameters tells how many bytes you want to read. The timeout is specified in miliseconds. The method returns an array object with the data read. (RSRt bulk_readR!Rt intr_readRtiso_readRR5RAR0RR+R( RRUR]RRR[RRR.R((s ./usb/core.pyR\Ps    ic Cstj|tjkrK|dkr6tjd}qftjd|}n|dkr`d}n|}|jj|jjj|jj ||||||j |S(sDo a control transfer on the endpoint 0. This method is used to issue a control transfer over the endpoint 0(endpoint 0 is required to always be a control endpoint). The parameters bmRequestType, bRequest, wValue and wIndex are the same of the USB Standard Control Request format. Control requests may or may not have a data payload to write/read. In cases which it has, the direction bit of the bmRequestType field is used to infere the desired request direction. For host to device requests (OUT), data_or_wLength parameter is the data payload to send, and it must be a sequence type convertible to an array object. In this case, the return value is the number of data payload written. For device to host requests (IN), data_or_wLength is the wLength parameter of the control request specifying the number of bytes to read in data payload. In this case, the return value is the data payload read, as an array object. RiN( R!tctrl_directiontCTRL_OUTRRRSRRt ctrl_transferRR(Rt bmRequestTypetbRequesttwValuetwIndextdata_or_wLengthR[ta((s ./usb/core.pyRts       cCs)|jj|jjj|jj|S(sDetermine if there is kernel driver associated with the interface. If a kernel driver is active, and the object will be unable to perform I/O. (RSRRtis_kernel_driver_activeR(RRR((s ./usb/core.pyRs cCs-|jj|jjj|jj|dS(s^Detach a kernel driver. If successful, you will then be able to perform I/O. N(RSRRtdetach_kernel_driverR(RRR((s ./usb/core.pyRs cCs-|jj|jjj|jj|dS(skRe-attach an interface's kernel driver, which was previously detached using detach_kernel_driver().N(RSRRtattach_kernel_driverR(RRR((s ./usb/core.pyRs ccs,x%t|jD]}t||VqWdS(s.Iterate over all configurations of the device.N(RfR{R(RR/((s ./usb/core.pyRgscCs t||S(s6Return the Configuration object in the given position.(R(RR$((s ./usb/core.pyRhscCs|jj|dS(N(RSRF(R((s ./usb/core.pyt__del__scCs|dk r|S|jS(N(RR}(RR[((s ./usb/core.pyt __get_timeouts cCs(|dkrtdn||_dS(Nis"Timeout cannot be a negative value(t ValueErrorR}(Rttmo((s ./usb/core.pyt __set_def_tmos cCs|jS(N(R}(R((s ./usb/core.pyt __get_def_tmostdocs*Default timeout for transfer I/O functionsN(RGRHRKRRR#R*R6RRRYR\RRRRRgRhRRt_Device__set_def_tmot_Device__get_def_tmotpropertytdefault_timeout(((s ./usb/core.pyRs0" #   %$*         c  sfd}dkrddljj}ddljj}ddljj}xU|||fD]5}|jdk rdt j d|j PqdqdWt dn|j |j} } |rg|| | D] } | ^qSytj|| | SWntk rdSXdS(s Find an USB device and return it. find() is the function used to discover USB devices. You can pass as arguments any combination of the USB Device Descriptor fields to match a device. For example: find(idVendor=0x3f4, idProduct=0x2009) will return the Device object for the device with idVendor Device descriptor field equals to 0x3f4 and idProduct equals to 0x2009. If there is more than one device which matchs the criteria, the first one found will be returned. If a matching device cannot be found the function returns None. If you want to get all devices, you can set the parameter find_all to True, then find will return an list with all matched devices. If no matching device is found, it will return an empty list. Example: printers = find(find_all=True, bDeviceClass=7) This call will get all the USB printers connected to the system. (actually may be not, because some devices put their class information in the Interface Descriptor). You can also use a customized match criteria: dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009) A more accurate printer finder using a customized match would be like so: def is_printer(dev): import usb.util if dev.bDeviceClass == 7: return True for cfg in dev: if util.find_descriptor(cfg, bInterfaceClass=7) is not None: return True printers = find(find_all=True, custom_match = is_printer) Now even if the device class code is in the interface descriptor the printer will be found. You can combine a customized match with device descriptor fields. In this case, the fields must match and the custom_match must return True. In the our previous example, if we would like to get all printers belonging to the manufacturer 0x3f4, the code would be like so: printers = find(find_all=True, idVendor=0x3f4, custom_match=is_printer) If you want to use find as a 'list all devices' function, just call it with find_all = True: devices = find(find_all=True) Finally, you may pass a custom backend to the find function: find(backend = MyBackend()) PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB. If you do not supply a backend explicitly, find() function will select one of the predefineds backends according to system availability. Backends are explained in the usb.backend module. c 3sx|jD]n}t|dks:r tjdttj|tfd|tr Vq q WdS(NcSs |o |S(N((Rtb((s ./usb/core.pytscs t|S(N(R(R/(td(s ./usb/core.pyR"s( tenumerate_devicesRRRt_reducetmaptoperatorteqRI(tktvR(t custom_matchR(Rs ./usb/core.pyt device_iters iNsfind(): using backend "%s"sNo backend available(Rtusb.backend.libusb10Rtlibusb10tusb.backend.libusb01tlibusb01tusb.backend.openusbtopenusbt get_backendt_loggertinfoRGRtkeystvaluesRt_nextt StopIteration( tfind_allRRtargsRRRRtmRRR((RRs ./usb/core.pyRs$E     (RKt __author__t__all__Rtusb.utilR!RBtsysRt usb._interopRtloggingt getLoggerRR|R tobjectR tIOErrorRJRRRRRRR(((s ./usb/core.pyt&s(      yWVI#quisk-3.6.11/usb/LICENSE0000644000175000017500000000257711632372224014131 0ustar jimjim00000000000000Copyright (C) 2009-2010 Wander Lairson Costa. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. quisk-3.6.11/usb/__init__.pyc0000644000175000017500000000352412146140537015372 0ustar jimjim00000000000000 iNc@sTdZddlZddlZdZddddgZdZedd lTdS( smPyUSB - Easy USB access in Python This package exports the following modules and subpackages: core - the main USB implementation legacy - the compatibility layer with 0.x version backend - the support for backend implementations. Since version 1.0, main PyUSB implementation lives in the 'usb.core' module. New applications are encouraged to use it. iNsWander Lairson CostatlegacytcoretbackendtutilcCstjd}tjd}|dk rtjd}itjd6tjd6tjd6tjd6tj d6}|j |tj d }|j d |ytj |}Wntj }nXtjd }|j||j|n)d tjfd Y}|j|dS(NtusbtPYUSB_DEBUG_LEVELtPYUSB_LOG_FILENAMEtdebugtinfotwarningterrortcriticali tlevels.%(asctime)s %(levelname)s:%(name)s:%(message)st NullHandlercBseZdZRS(cSsdS(N((tselftrecord((s./usb/__init__.pytemitKs(t__name__t __module__R(((s./usb/__init__.pyR Js(tloggingt getLoggertostgetenvtNonetDEBUGtINFOtWARNINGtERRORtCRITICALtgettsetLevelt FileHandlert StreamHandlert Formattert setFormattert addHandlertHandler(tloggert debug_leveltfilenametLEVELSR thandlertfmtR ((s./usb/__init__.pyt _setup_log1s(       (t*(t__doc__RRt __author__t__all__R+t usb.legacy(((s./usb/__init__.pyt's   quisk-3.6.11/usb/ACKNOWLEDGEMENTS0000644000175000017500000000100411632372224015361 0ustar jimjim00000000000000This is a list of people who has contributed to PyUSB 1.0 development. If I forgot you, please email me. PyUSB 1.0.0 (alpha 0) --------------------- - Thomas Reitmayr: thanks for your patches to get PyUSB running with libusb 1.0. - Carl Ritson: thanks for your patch to get minimal working of legacy layer. - Romain Aviolat: thanks for pointing out a mistake in the tutorial and to report a bug in ctrl_transfer. - Xiaofan Chen: thanks for your effort testing PyUSB with libusb 1.0 Windows backend and on FreeBSD. quisk-3.6.11/usb/_interop.pyc0000644000175000017500000000602712146140537015453 0ustar jimjim00000000000000 iNc@sdddlZddddddgZejdks9tyddlZejZWneefk rqeZnXy e Z Wn&e k rddl Z e j Z nXd ZyddlZejZWn-eefk rdefd YZnXy eZWn e k r#ded ZnXyddlZejZWn eefk r_d ZnXdS( iNt_reducet_sett_nextt_groupbyt_sortedt_update_wrappericCs-yt|SWntk r(|jSXdS(N(tnextt NameError(titer((s./usb/_interop.pyR9s cBs/eZddZdZdZdZRS(cCsN|dkrd}n||_t||_t|_|_|_dS(NcSs|S(N((tx((s./usb/_interop.pytJs(tNonetkeyfuncRtittobjectttgtkeytcurrkeyt currvalue(tselftiterabletkey((s./usb/_interop.pyt__init__Hs    cCs|S(N((R((s./usb/_interop.pyt__iter__NscCsex=|j|jkr?t|j|_|j|j|_qW|j|_|j|j|jfS(N(RRRR RR t_grouper(R((s./usb/_interop.pyRPs  ccsIxB|j|krD|jVt|j|_|j|j|_qWdS(N(RRRR R (RR((s./usb/_interop.pyRVsN(t__name__t __module__R RRRR(((s./usb/_interop.pyREs   cs?dtffdY}t|}|j|||S(NtKeyToCmpcs eZdZfdZRS(cSs ||_dS(N(R(RtK((s./usb/_interop.pyRdscs^|j|}|j|}||kr:r6dp9dS||krVrRdpUdSdSdS(Niii(R(RR tytkxtky(treverse(s./usb/_interop.pyt__call__fs  (RRRR ((R(s./usb/_interop.pyRcs (Rtlisttsort(tlRRRttmp((Rs./usb/_interop.pyR`s cCs4|j|_|j|_|j|_|j|_dS(N(RRt__doc__t__dict__(twrappertwrapped((s./usb/_interop.pyRws   (tsyst__all__t hexversiontAssertionErrort functoolstreduceRt ImportErrortAttributeErrortsetRRtsetstSetRt itertoolstgroupbyRRtsortedRR tFalsetupdate_wrapperR(((s./usb/_interop.pyt"s6               quisk-3.6.11/usb/legacy.pyc0000644000175000017500000003144412146140537015101 0ustar jimjim00000000000000 iNc@s*ddljZddljZddljZddlmZdZdZdZ dZ dZ dZ d Z d Zd Zd ZdZdZdZd ZdZdZd ZdZdZd ZdZdZdZdZdZdZ dZ!dZ"d Z#dZ$d Z%dZ&dZ'dZ(dZ)dZ*d Z+dZ,dZ-d Z.dZ/dZ0dZ1dZ2d Z3dZ4dZ5d Z6dZ7dZ8d Z9dZ:dZ;dZ<dZ=dZ>d Z?dZ@deAfdYZBdeAfd YZCd!eAfd"YZDd#eAfd$YZEd%eAfd&YZFd'eAfd(YZGd)ZHdS(*iN(tUSBErrorsWander Lairson Costaiii ii iiiiiii!i)ii#i"iii i ii i i`i@tEndpointcBseZdZdZRS(sEndpoint descriptor object.cCs=|j|_|j|_|j|_tj|j|_ dS(N( tbEndpointAddresstaddresst bIntervaltintervaltwMaxPacketSizet maxPacketSizetutilt endpoint_typet bmAttributesttype(tselftep((s./usb/legacy.pyt__init__`s   (t__name__t __module__t__doc__R(((s./usb/legacy.pyR^st InterfacecBseZdZdZRS(sInterface descriptor object.cCsn|j|_|j|_|j|_|j|_|j|_|j |_ g|D]}t |^qO|_ dS(N( tbAlternateSettingtalternateSettingtbInterfaceNumbertinterfaceNumbert iInterfacetbInterfaceClasstinterfaceClasstbInterfaceSubClasstinterfaceSubClasstbInterfaceProtocoltinterfaceProtocolRt endpoints(R tintfte((s./usb/legacy.pyRhs      (RRRR(((s./usb/legacy.pyRfst ConfigurationcBseZdZdZRS(s Configuration descriptor object.cCs|j|_|jd>|_|jd?d@|_|jd?d@|_|j|_|j|_ gt j t j g|D]}t |^qrdddD]\}}t|^q|_dS(NiiiitkeycSs|jS(N(R(ti((s./usb/legacy.pyt~scSs|jS(N(R(R#((s./usb/legacy.pyR$s(tiConfigurationt bMaxPowertmaxPowerR t remoteWakeupt selfPoweredt wTotalLengtht totalLengthtbConfigurationValuetvaluet_interopt_groupbyt_sortedRtlistt interfaces(R tcfgR#tktg((s./usb/legacy.pyRss     (RRRR(((s./usb/legacy.pyR!qst DeviceHandlecBseZdZddZddZddZddZddddZdZd Z d Z d Z d Z d Z dZddZddZdZRS(cCs||_d|_dS(Ni(tdevt _DeviceHandle__claimed_interface(R R7((s./usb/legacy.pyRs idcCs|jj|||j|S(sPerform a bulk write request to the endpoint specified. Arguments: endpoint: endpoint number. buffer: sequence data buffer to write. This parameter can be any sequence type. timeout: operation timeout in miliseconds. (default: 100) Returns the number of bytes written. (R7twriteR8(R tendpointtbufferttimeout((s./usb/legacy.pyt bulkWrites cCs|jj|||j|S(s+Performs a bulk read request to the endpoint specified. Arguments: endpoint: endpoint number. size: number of bytes to read. timeout: operation timeout in miliseconds. (default: 100) Return a tuple with the data read. (R7treadR8(R R:tsizeR<((s./usb/legacy.pytbulkReads cCs|jj|||j|S(sPerform a interrupt write request to the endpoint specified. Arguments: endpoint: endpoint number. buffer: sequence data buffer to write. This parameter can be any sequence type. timeout: operation timeout in miliseconds. (default: 100) Returns the number of bytes written. (R7R9R8(R R:R;R<((s./usb/legacy.pytinterruptWrites cCs|jj|||j|S(s0Performs a interrupt read request to the endpoint specified. Arguments: endpoint: endpoint number. size: number of bytes to read. timeout: operation timeout in miliseconds. (default: 100) Return a tuple with the data read. (R7R>R8(R R:R?R<((s./usb/legacy.pyt interruptReads ic Cs+|jj||d|d|d|d|S(sPerform a control request to the default control pipe on a device. Arguments: requestType: specifies the direction of data flow, the type of request, and the recipient. request: specifies the request. buffer: if the transfer is a write transfer, buffer is a sequence with the transfer data, otherwise, buffer is the number of bytes to read. value: specific information to pass to the device. (default: 0) index: specific information to pass to the device. (default: 0) timeout: operation timeout in miliseconds. (default: 100) Return the number of bytes written. twValuetwIndextdata_or_wLengthR<(R7t ctrl_transfer(R t requestTypetrequestR;R-tindexR<((s./usb/legacy.pyt controlMsgs cCstddS(suClears any halt status on the specified endpoint. Arguments: endpoint: endpoint number. s*This function has not been implemented yetN(tNotImplemented(R R:((s./usb/legacy.pyt clearHaltscCs tj|j|||_dS(sClaims the interface with the Operating System. Arguments: interface: interface number or an Interface object. N(Rtclaim_interfaceR7R8(R t interface((s./usb/legacy.pytclaimInterfacescCs#tj|j|jd|_dS(s<Release an interface previously claimed with claimInterface.iN(Rtrelease_interfaceR7R8(R ((s./usb/legacy.pytreleaseInterfacescCs|jjdS(s[Reset the specified device by sending a RESET down the port it is connected to.N(R7treset(R ((s./usb/legacy.pyRRscCs|j|dS(spReset all states for the specified endpoint. Arguments: endpoint: endpoint number. N(RL(R R:((s./usb/legacy.pyt resetEndpointscCs|jj|dS(sSet the active configuration of a device. Arguments: configuration: a configuration value or a Configuration object. N(R7tset_configuration(R t configuration((s./usb/legacy.pytsetConfigurationscCs|jj|j|dS(sSets the active alternate setting of the current interface. Arguments: alternate: an alternate setting number or an Interface object. N(R7tset_interface_altsettingR8(R t alternate((s./usb/legacy.pytsetAltInterfacesicCstddS(sBRetrieve the string descriptor specified by index and langid from a device. Arguments: index: index of descriptor in the device. len: number of bytes of the string langid: Language ID. If it is omittedi, will be used the first language. s*This function has not been implemented yetN(RK(R RItlentlangid((s./usb/legacy.pyt getStrings cCstddS(sRetrieves a descriptor from the device identified by the type and index of the descriptor. Arguments: type: descriptor type. index: index of the descriptor. len: descriptor length. endpoint: endpoint number from descriptor is read. If it is omitted, the descriptor is read from default control pipe. s*This function has not been implemented yetN(RK(R R RIRZR:((s./usb/legacy.pyt getDescriptor s cCs|jj|dS(sDetach a kernel driver from the interface (if one is attached, we have permission and the operation is supported by the OS) Arguments: interface: interface number or an Interface object. N(R7tdetach_kernel_driver(R RN((s./usb/legacy.pytdetachKernelDrivers(RRRR=R@RARBRJRLRORQRRRSRVRYR\R]R_(((s./usb/legacy.pyR6s          tDevicecBs eZdZdZdZRS(sDevice descriptor objectcCs|j|_|j|_|j|_|j|_d|_ d|_ |j |_ |j |_ |j |_ |j|_|j|_|j|_|j|_g|D]}t|^q|_||_dS(Nt(t bDeviceClasst deviceClasstbDeviceSubClasstdeviceSubClasstbDeviceProtocoltdeviceProtocolt bcdDevicet deviceVersiontNonetdevnumtfilenamet iManufacturertiProductt iSerialNumbert idProducttidVendortbMaxPacketSize0RtbcdUSBt usbVersionR!tconfigurationsR7(R R7tc((s./usb/legacy.pyR%s             "cCs t|jS(sGOpen the device for use. Return a DeviceHandle object (R6R7(R ((s./usb/legacy.pytopen6s(RRRRRw(((s./usb/legacy.pyR`#s tBuscBseZdZdZRS(s Bus object.cCsDd|_d|_gtjdtD]}t|^q%|_dS(NRaitfind_all(tdirnamet localtiontcoretfindtTrueR`tdevices(R td((s./usb/legacy.pyR?s  (RRRR(((s./usb/legacy.pyRx=scCs tfS(s#Return a tuple with the usb busses.(Rx(((s./usb/legacy.pytbussesDs(Itusb.coreR|tusb.utilRt usb._interopR.Rt __author__t CLASS_AUDIOt CLASS_COMMt CLASS_DATAt CLASS_HIDt CLASS_HUBtCLASS_MASS_STORAGEtCLASS_PER_INTERFACEt CLASS_PRINTERtCLASS_VENDOR_SPECt DT_CONFIGtDT_CONFIG_SIZEt DT_DEVICEtDT_DEVICE_SIZEt DT_ENDPOINTtDT_ENDPOINT_AUDIO_SIZEtDT_ENDPOINT_SIZEtDT_HIDtDT_HUBtDT_HUB_NONVAR_SIZEt DT_INTERFACEtDT_INTERFACE_SIZEt DT_PHYSICALt DT_REPORTt DT_STRINGtENDPOINT_ADDRESS_MASKtENDPOINT_DIR_MASKt ENDPOINT_INt ENDPOINT_OUTtENDPOINT_TYPE_BULKtENDPOINT_TYPE_CONTROLtENDPOINT_TYPE_INTERRUPTtENDPOINT_TYPE_ISOCHRONOUStENDPOINT_TYPE_MASKt ERROR_BEGINt MAXALTSETTINGt MAXCONFIGt MAXENDPOINTSt MAXINTERFACESt RECIP_DEVICEtRECIP_ENDPOINTtRECIP_INTERFACEt RECIP_OTHERtREQ_CLEAR_FEATUREtREQ_GET_CONFIGURATIONtREQ_GET_DESCRIPTORtREQ_GET_INTERFACEtREQ_GET_STATUStREQ_SET_ADDRESStREQ_SET_CONFIGURATIONtREQ_SET_DESCRIPTORtREQ_SET_FEATUREtREQ_SET_INTERFACEtREQ_SYNCH_FRAMEt TYPE_CLASSt TYPE_RESERVEDt TYPE_STANDARDt TYPE_VENDORtobjectRRR!R6R`RxR(((s./usb/legacy.pyts quisk-3.6.11/usb/util.py0000644000175000017500000001571511632372224014451 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. r"""usb.util - Utility functions.""" __author__ = 'Wander Lairson Costa' import operator import usb._interop as _interop # descriptor type DESC_TYPE_DEVICE = 0x01 DESC_TYPE_CONFIG = 0x02 DESC_TYPE_STRING = 0x03 DESC_TYPE_INTERFACE = 0x04 DESC_TYPE_ENDPOINT = 0x05 # endpoint direction ENDPOINT_IN = 0x80 ENDPOINT_OUT = 0x00 # endpoint type ENDPOINT_TYPE_CTRL = 0x00 ENDPOINT_TYPE_ISO = 0x01 ENDPOINT_TYPE_BULK = 0x02 ENDPOINT_TYPE_INTR = 0x03 # control request type CTRL_TYPE_STANDARD = 0 CTRL_TYPE_CLASS = 1 CTRL_TYPE_VENDOR = 2 CTRL_TYPE_RESERVED = 3 # control request recipient CTRL_RECIPIENT_DEVICE = 0 CTRL_RECIPIENT_INTERFACE = 1 CTRL_RECIPIENT_ENDPOINT = 2 CTRL_RECIPIENT_OTHER = 3 # control request direction CTRL_OUT = 0x00 CTRL_IN = 0x80 _ENDPOINT_ADDR_MASK = 0x0f _ENDPOINT_DIR_MASK = 0x80 _ENDPOINT_TRANSFER_TYPE_MASK = 0x03 _CTRL_DIR_MASK = 0x80 def endpoint_address(address): r"""Return the endpoint absolute address. The address parameter is the bEndpointAddress field of the endpoint descriptor. """ return address & _ENDPOINT_ADDR_MASK def endpoint_direction(address): r"""Return the endpoint direction. The address parameter is the bEndpointAddress field of the endpoint descriptor. The possible return values are ENDPOINT_OUT or ENDPOINT_IN. """ return address & _ENDPOINT_DIR_MASK def endpoint_type(bmAttributes): r"""Return the transfer type of the endpoint. The bmAttributes parameter is the bmAttributes field of the endpoint descriptor. The possible return values are: ENDPOINT_TYPE_CTRL, ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR. """ return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK def ctrl_direction(bmRequestType): r"""Return the direction of a control request. The bmRequestType parameter is the value of the bmRequestType field of a control transfer. The possible return values are CTRL_OUT or CTRL_IN. """ return bmRequestType & _CTRL_DIR_MASK def build_request_type(direction, type, recipient): r"""Build a bmRequestType field for control requests. These is a conventional function to build a bmRequestType for a control request. The direction parameter can be CTRL_OUT or CTRL_IN. The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS, CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values. The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE, CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER. Return the bmRequestType value. """ return recipient | (type << 5) | direction def find_descriptor(desc, find_all=False, custom_match=None, **args): r"""Find an inner descriptor. find_descriptor works in the same way the core.find() function does, but it acts on general descriptor objects. For example, suppose you have a Device object called dev and want a Configuration of this object with its bConfigurationValue equals to 1, the code would be like so: >>> cfg = util.find_descriptor(dev, bConfigurationValue=1) You can use any field of the Descriptor as a match criteria, and you can supply a customized match just like core.find() does. The find_descriptor function also accepts the find_all parameter to get a list of descriptor instead of just one. """ def desc_iter(k, v): for d in desc: if (custom_match is None or custom_match(d)) and \ _interop._reduce( lambda a, b: a and b, map( operator.eq, v, map(lambda i: getattr(d, i), k) ), True ): yield d k, v = args.keys(), args.values() if find_all: return [d for d in desc_iter(k, v)] else: try: return _interop._next(desc_iter(k, v)) except StopIteration: return None def claim_interface(device, interface): r"""Explicitly claim an interface. PyUSB users normally do not have to worry about interface claiming, as the library takes care of it automatically. But there are situations where you need deterministic interface claiming. For these uncommon cases, you can use claim_interface. If the interface is already claimed, either through a previously call to claim_interface or internally by the device object, nothing happens. """ device._ctx.managed_claim_interface(device, interface) def release_interface(device, interface): r"""Explicitly release an interface. This function is used to release an interface previously claimed, either through a call to claim_interface or internally by the device object. Normally, you do not need to worry about claiming policies, as the device object takes care of it automatically. """ device._ctx.managed_release_interface(device, interface) def dispose_resources(device): r"""Release internal resources allocated by the object. Sometimes you need to provide deterministic resources freeing, for example to allow another application to talk to the device. As Python does not provide deterministic destruction, this function releases all internal resources allocated by the device, like device handle and interface policy. After calling this function, you can continue using the device object normally. If the resources will be necessary again, it will allocate them automatically. """ device._ctx.dispose(device) quisk-3.6.11/usb/_debug.pyc0000644000175000017500000000374712146140542015063 0ustar jimjim00000000000000 iNc@sXdZddgZddlZddlZddljZdZdZdZdS(sWander Lairson Costat methodtracet functiontraceiNcOsM|j|ddjd|Ddjd|jDddS(Nt(s, css|]}t|VqdS(N(tstr(t.0tval((s./usb/_debug.pys )scss)|]\}}|dt|VqdS(t=N(R(RtnameR((s./usb/_debug.pys *st)(tdebugtjointitems(tloggertfnametargst named_args((s./usb/_debug.pyt_trace_function_call%scsfd}|S(Ncs&fd}tj||S(NcsZtjjkrMt|djdj}t||d|n||S(Nit.i(tloggingtDEBUGtgetEffectiveLevelttypet__name__R(RRtfn(tfR (s./usb/_debug.pytdo_trace0s(t_interopt_update_wrapper(RR(R (Rs./usb/_debug.pytdecorator_logging/s((R R((R s./usb/_debug.pyR.s csfd}|S(Ncs&fd}tj||S(Ncs;tjjkr.tjt|n||S(N(RRRRRtuargs(RR(RR (s./usb/_debug.pyR=s(RR(RR(R (Rs./usb/_debug.pyR<s((R R((R s./usb/_debug.pyR;s( t __author__t__all__Rttypest usb._interopRRRR(((s./usb/_debug.pyts    quisk-3.6.11/usb/TODO0000644000175000017500000000103611632372224013601 0ustar jimjim000000000000001.0.0-a0: * Implement standard control requests API. * Finish implementation of legacy compatibility layer. * Determine automatically current configuration when user hasn't set it. * Validate it on platforms other than Windows and Linux. * Finish implementation and test of OpenUSB backend. * Validate it on Python 2.3 and Python 3.x. * Samples. * Improve documentation. * Implement isochronous transfers. * Upgrade PIC test firmware to use 2.6a version Microchip USB stack. * Test, test and test. quisk-3.6.11/usb/_debug.py0000644000175000017500000000571211632372224014715 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. __author__ = 'Wander Lairson Costa' __all__ = ['methodtrace', 'functiontrace'] import logging import types import usb._interop as _interop def _trace_function_call(logger, fname, *args, **named_args): logger.debug( # TODO: check if 'f' is a method or a free function fname + '(' + \ ', '.join((str(val) for val in args)) + \ ', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')' ) # decorator for methods calls tracing def methodtrace(logger): def decorator_logging(f): def do_trace(*args, **named_args): # this if is just a optimization to avoid unecessary string formatting if logging.DEBUG >= logger.getEffectiveLevel(): fn = type(args[0]).__name__ + '.' + f.__name__ _trace_function_call(logger, fn, *args[1:], **named_args) return f(*args, **named_args) _interop._update_wrapper(do_trace, f) return do_trace return decorator_logging # decorator for methods calls tracing def functiontrace(logger): def decorator_logging(f): def do_trace(*args, **named_args): # this if is just a optimization to avoid unecessary string formatting if logging.DEBUG >= logger.getEffectiveLevel(): _trace_function_call(logger, f.__name__, *uargs, **named_args) return f(*args, **named_args) _interop._update_wrapper(do_trace, f) return do_trace return decorator_logging quisk-3.6.11/usb/__init__.py0000644000175000017500000000575111632372224015232 0ustar jimjim00000000000000# Copyright (C) 2009-2010 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. r"""PyUSB - Easy USB access in Python This package exports the following modules and subpackages: core - the main USB implementation legacy - the compatibility layer with 0.x version backend - the support for backend implementations. Since version 1.0, main PyUSB implementation lives in the 'usb.core' module. New applications are encouraged to use it. """ import logging import os __author__ = 'Wander Lairson Costa' __all__ = ['legacy', 'core', 'backend', 'util'] def _setup_log(): logger = logging.getLogger('usb') debug_level = os.getenv('PYUSB_DEBUG_LEVEL') if debug_level is not None: filename = os.getenv('PYUSB_LOG_FILENAME') LEVELS = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'critical': logging.CRITICAL} level = LEVELS.get(debug_level, logging.CRITICAL + 10) logger.setLevel(level = level) try: handler = logging.FileHandler(filename) except: handler = logging.StreamHandler() fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s') handler.setFormatter(fmt) logger.addHandler(handler) else: class NullHandler(logging.Handler): def emit(self, record): pass logger.addHandler(NullHandler()) _setup_log() # We import all 'legacy' module symbols to provide compatility # with applications that use 0.x versions. from usb.legacy import * quisk-3.6.11/usb/README0000644000175000017500000000535011632372224013774 0ustar jimjim00000000000000======================================= PyUSB 1.0 - Easy USB access from Python ======================================= Introduction ============ The PyUSB module provides Python with easy access to the host machine's Universal Serial Bus (USB) system. Until 0.4 version, PyUSB used to be a thin wrapper aroung libusb. With 1.0 version, things changed considerably. Now PyUSB is an API rich, backend neutral Python USB module easy to use. As with most Python modules, PyUSB's documentation is based on Python doc strings and can therefore be manipulated by tools such as pydoc. You can also find a tutorial at: http://pyusb.sourceforge.net/docs/1.0/tutotial.html. PyUSB is being developed and tested in Linux and Windows, but it should work fine in any platform running Python >= 2.3, ctypes and at least one of the builtin backends. PyUSB supports libusb 0.1, libusb 1.0 and OpenUSB, but the user does not need to worry about that, unless in some corner cases. If you have any question about PyUSB, you can use the PyUSB mailing list hosted in the SourceForge. In the PyUSB website (http://pyusb.sourceforge.net) you can find instructions on how to subscribe to the mailing list. Installing PyUSB on GNU/Linux Systems ===================================== These instructions are for Debian-based systems. Instructions for other flavors of GNU/Linux should be similar. You will first need to install the following packages: 1) python (PyUSB is useless without it), version >= 2.3 2) At least one of the supported libraries (libusb 1.0, libusb 0.1 or OpenUSB) 3) If your Python version is < 2.5, you have to install ctypes as a separate package, because these versions of Python does not ship it. For example, the command sudo apt-get install python libusb should install all these packages on most Debian-based systems with access to the proper package repositories. Once the above packages are installed, you can install PyUSB with the command python setup.py install run as root from within the same directory as this README file. Installing PyUSB on Windows =========================== Now that PyUSB is 100% written in Python, you install it on Windows in the same way you do on Linux, but libusb for Windows is done through libusb-win32 package (libusb 1.0 backend is in progress). To install it you do as usual: python setup.py install Reporting bugs/Submitting patches ================================= Some people have been sending me patches and reporting bugs directly in my email. Please, do it through SourceForge tracker, I had a hardtime tracking their names to put them in the acknowledgments file. ;-) PS: this README file was based on the great Josh Lifton's one... ^_^ quisk-3.6.11/quisk0000644000175000017500000000026011632372224013375 0ustar jimjim00000000000000#!/usr/bin/python import quisk # May be quisk.py or package quisk if quisk.__file__.find('__init__') >= 0: # quisk is the package import quisk.quisk as quisk quisk.main() quisk-3.6.11/portaudio.py0000644000175000017500000000553712124354050014704 0ustar jimjim00000000000000#! /usr/bin/python # Test for PortAudio devices using ctypes from __future__ import print_function import ctypes, ctypes.util class PaDeviceInfo (ctypes.Structure): _fields_ = [ ('structVersion', ctypes.c_int), ('name', ctypes.c_char_p), ('hostApi', ctypes.c_int), # PaHostApiIndex ('maxInputChannels', ctypes.c_int), ('maxOutputChannels', ctypes.c_int), ('defaultLowInputLatency', ctypes.c_double), # PaTime ('defaultLowOutputLatency', ctypes.c_double), # PaTime ('defaultHighInputLatency', ctypes.c_double), # PaTime ('defaultHighOutputLatency', ctypes.c_double), # PaTime ('defaultSampleRate', ctypes.c_double), ] class PaHostApiInfo (ctypes.Structure): _fields_ = [ ('structVersion', ctypes.c_int), ('type', ctypes.c_int), # enum PaHostApiTypeId ('name', ctypes.c_char_p), ('deviceCount', ctypes.c_int), ('defaultInputDevice', ctypes.c_int), ('defaultOutputDevice', ctypes.c_int), ] class PaStreamParameters (ctypes.Structure): _fields_ = [ ('device', ctypes.c_int), #PaDeviceIndex ('channelCount', ctypes.c_int), ('sampleFormat', ctypes.c_ulong), #PaSampleFormat ('suggestedLatency', ctypes.c_double), # PaTime ('hostApiSpecificStreamInfo', ctypes.c_void_p), ] pa_name = ctypes.util.find_library("portaudio") pa = ctypes.CDLL(pa_name) pa.Pa_GetDeviceInfo.restype = ctypes.POINTER(PaDeviceInfo) pa.Pa_GetHostApiInfo.restype = ctypes.POINTER(PaHostApiInfo) pa.Pa_GetVersionText.restype = ctypes.c_char_p inputParameters = PaStreamParameters (device=0, channelCount=2, sampleFormat=2, suggestedLatency=0, # format 2 is paInt32 hostApiSpecificStreamInfo=ctypes.c_void_p() ) outputParameters = PaStreamParameters (device=0, channelCount=2, sampleFormat=2, suggestedLatency=0, # format 2 is paInt32 hostApiSpecificStreamInfo=ctypes.c_void_p() ) print('Open', pa.Pa_Initialize()) try: print('Version', pa.Pa_GetVersion()) print('Version Text', pa.Pa_GetVersionText()) count = pa.Pa_GetDeviceCount() print('NumDev', count) for i in range(count): pt_info = pa.Pa_GetDeviceInfo(i) info = pt_info.contents print("Device %2d, host api %s" % (i, pa.Pa_GetHostApiInfo(info.hostApi).contents.name)) print(" Name %s" % info.name) print(" Max inputs %d, Max outputs %d" % (info.maxInputChannels, info.maxOutputChannels)) inputParameters.device = i outputParameters.device = i if info.maxInputChannels >= 2: ptIn = ctypes.pointer(inputParameters) else: ptIn = ctypes.c_void_p() if info.maxOutputChannels >= 2: ptOut = ctypes.pointer(outputParameters) else: ptOut = ctypes.c_void_p() print(" Speeds for 2-channel paInt32:", end=' ') for speed in (44100, 48000, 96000, 192000): if pa.Pa_IsFormatSupported(ptIn, ptOut, ctypes.c_double(speed)) == 0: print(" %d" % speed, end=' ') print() finally: print('Close', pa.Pa_Terminate()) quisk-3.6.11/filter.c0000666000175000017500000002700412122654207013757 0ustar jimjim00000000000000#include #include #include #include // Use native C99 complex type for fftw3 #include "quisk.h" #include "filter.h" #include "filters.h" void quisk_filt_cInit(struct quisk_cFilter * filter, double * coefs, int taps) { // Prepare a new filter using coefs and taps. Samples are complex. filter->dCoefs = coefs; filter->cpxCoefs = NULL; filter->cSamples = (complex *)malloc(taps * sizeof(complex)); memset(filter->cSamples, 0, taps * sizeof(complex)); filter->ptcSamp = filter->cSamples; filter->nTaps = taps; filter->counter = 0; filter->cBuf = NULL; filter->nBuf = 0; } void quisk_filt_dInit(struct quisk_dFilter * filter, double * coefs, int taps) { // Prepare a new filter using coefs and taps. Samples are double. filter->dCoefs = coefs; filter->cpxCoefs = NULL; filter->dSamples = (double *)malloc(taps * sizeof(double)); memset(filter->dSamples, 0, taps * sizeof(double)); filter->ptdSamp = filter->dSamples; filter->nTaps = taps; filter->counter = 0; filter->dBuf = NULL; filter->nBuf = 0; } void quisk_filt_tune(struct quisk_dFilter * filter, double freq, int ssb_upper) { // Tune a filter into an analytic I/Q filter with complex coefficients. // freq is the center frequency / sample rate. Reverse coef if ssb_upper == 0. // This is used for both quisk_dFilter and quisk_cFilter with a cast. int i; complex coef, tune; double D; if ( ! filter->cpxCoefs) filter->cpxCoefs = (complex *)malloc(filter->nTaps * sizeof(complex)); tune = I * 2.0 * M_PI * freq; D = (filter->nTaps - 1.0) / 2.0; for (i = 0; i < filter->nTaps; i++) { coef = 2.0 * cexp(tune * (i - D)) * filter->dCoefs[i]; if (ssb_upper) filter->cpxCoefs[i] = coef; else filter->cpxCoefs[i] = cimag(coef) + I * creal(coef); } } complex quisk_dC_out(double sample, struct quisk_dFilter * filter) { complex csample; complex * ptCoef; double * ptSample; int k; // FIR bandpass filter; separate double sample into I and Q. // Put samples into buffer left to right. Use samples right to left. ptSample = filter->ptdSamp; *ptSample = sample; ptCoef = filter->cpxCoefs; csample = 0; for (k = 0; k < filter->nTaps; k++, ptCoef++) { csample += *ptSample * *ptCoef; if (--ptSample < filter->dSamples) ptSample = filter->dSamples + filter->nTaps - 1; } if (++filter->ptdSamp >= filter->dSamples + filter->nTaps) filter->ptdSamp = filter->dSamples; return csample; } #if 0 complex quisk_cC_out(complex sample, struct quisk_cFilter * filter) { complex csample; complex * ptCoef; complex * ptSample; int k; // FIR bandpass filter; filter complex samples by complex coeffs. // Put samples into buffer left to right. Use samples right to left. ptSample = filter->ptcSamp; *ptSample = sample; ptCoef = filter->cpxCoefs; csample = 0; for (k = 0; k < filter->nTaps; k++, ptCoef++) { csample += *ptSample * *ptCoef; if (--ptSample < filter->cSamples) ptSample = filter->cSamples + filter->nTaps - 1; } if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) filter->ptcSamp = filter->cSamples; return csample; } #endif int quisk_cInterpolate(complex * cSamples, int count, struct quisk_cFilter * filter, int interp) { // This uses the double coefficients of filter (not the complex). Samples are complex. int i, j, k, nOut; double * ptCoef; complex * ptSample; complex csample; if (count > filter->nBuf) { // increase size of sample buffer filter->nBuf = count * 2; if (filter->cBuf) free(filter->cBuf); filter->cBuf = (complex *)malloc(filter->nBuf * sizeof(complex)); } memcpy(filter->cBuf, cSamples, count * sizeof(complex)); nOut = 0; for (i = 0; i < count; i++) { // Put samples into buffer left to right. Use samples right to left. *filter->ptcSamp = filter->cBuf[i]; for (j = 0; j < interp; j++) { ptSample = filter->ptcSamp; ptCoef = filter->dCoefs + j; csample = 0; for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) { csample += *ptSample * *ptCoef; if (--ptSample < filter->cSamples) ptSample = filter->cSamples + filter->nTaps - 1; } cSamples[nOut++] = csample * interp; } if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) filter->ptcSamp = filter->cSamples; } return nOut; } int quisk_dInterpolate(double * dSamples, int count, struct quisk_dFilter * filter, int interp) { // This uses the double coefficients of filter (not the complex). Samples are double. int i, j, k, nOut; double * ptCoef; double * ptSample; double dsample; if (count > filter->nBuf) { // increase size of sample buffer filter->nBuf = count * 2; if (filter->dBuf) free(filter->dBuf); filter->dBuf = (double *)malloc(filter->nBuf * sizeof(double)); } memcpy(filter->dBuf, dSamples, count * sizeof(double)); nOut = 0; for (i = 0; i < count; i++) { // Put samples into buffer left to right. Use samples right to left. *filter->ptdSamp = filter->dBuf[i]; for (j = 0; j < interp; j++) { ptSample = filter->ptdSamp; ptCoef = filter->dCoefs + j; dsample = 0; for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) { dsample += *ptSample * *ptCoef; if (--ptSample < filter->dSamples) ptSample = filter->dSamples + filter->nTaps - 1; } dSamples[nOut++] = dsample * interp; } if (++filter->ptdSamp >= filter->dSamples + filter->nTaps) filter->ptdSamp = filter->dSamples; } return nOut; } int quisk_cDecimate(complex * cSamples, int count, struct quisk_cFilter * filter, int decim) { // This uses the double coefficients of filter (not the complex). int i, k, nOut; complex * ptSample; double * ptCoef; complex csample; nOut = 0; for (i = 0; i < count; i++) { *filter->ptcSamp = cSamples[i]; if (++filter->counter >= decim) { filter->counter = 0; // output a sample csample = 0; ptSample = filter->ptcSamp; ptCoef = filter->dCoefs; for (k = 0; k < filter->nTaps; k++, ptCoef++) { csample += *ptSample * *ptCoef; if (--ptSample < filter->cSamples) ptSample = filter->cSamples + filter->nTaps - 1; } cSamples[nOut++] = csample; } if (++filter->ptcSamp >= filter->cSamples + filter->nTaps) filter->ptcSamp = filter->cSamples; } return nOut; } int quisk_dDecimate(double * dSamples, int count, struct quisk_dFilter * filter, int decim) { // This uses the double coefficients of filter (not the complex). int i, k, nOut; double * ptSample; double * ptCoef; double dsample; nOut = 0; for (i = 0; i < count; i++) { *filter->ptdSamp = dSamples[i]; if (++filter->counter >= decim) { filter->counter = 0; // output a sample dsample = 0; ptSample = filter->ptdSamp; ptCoef = filter->dCoefs; for (k = 0; k < filter->nTaps; k++, ptCoef++) { dsample += *ptSample * *ptCoef; if (--ptSample < filter->dSamples) ptSample = filter->dSamples + filter->nTaps - 1; } dSamples[nOut++] = dsample; } if (++filter->ptdSamp >= filter->dSamples + filter->nTaps) filter->ptdSamp = filter->dSamples; } return nOut; } int quisk_dFilter(double * dSamples, int count, struct quisk_dFilter * filter) { // Filter double samples. int i, k, nOut; double * ptSample; double * ptCoef; double dsample; nOut = 0; for (i = 0; i < count; i++) { *filter->ptdSamp = dSamples[i]; dsample = 0; ptSample = filter->ptdSamp; ptCoef = filter->dCoefs; for (k = 0; k < filter->nTaps; k++, ptCoef++) { dsample += *ptSample * *ptCoef; if (--ptSample < filter->dSamples) ptSample = filter->dSamples + filter->nTaps - 1; } dSamples[nOut++] = dsample; if (++filter->ptdSamp >= filter->dSamples + filter->nTaps) filter->ptdSamp = filter->dSamples; } return nOut; } int quisk_cDecim2HB45(complex * cSamples, int count, struct quisk_cHB45Filter * filter) { // This uses the double coefficients of filter (not the complex). // Half band filter, sample rate 96 Hz, pass 16, center 24, stop 32, good BW 2/3, 45 taps. int i, nOut; complex * samples, * center; static double coef[12] = { 0.000018566625444266, -0.000118469698701817, 0.000457318798253456, -0.001347840471412094, 0.003321838571445455, -0.007198422696929033, 0.014211106939802483, -0.026424776824073383, 0.048414810444971007, -0.096214669073304823, 0.314881034738348550, 0.500000000000000000 }; // Rate 96, cutoff 16-24-32, atten 120 dB. Coef[0] and [44] are zero. nOut = 0; samples = filter->samples; center = filter->center; for (i = 0; i < count; i++) { if (filter->toggle == 0){ filter->toggle = 1; memmove(center + 1, center, sizeof(complex) * 10); center[0] = cSamples[i]; } else { filter->toggle = 0; memmove(samples + 1, samples, sizeof(complex) * 21); samples[0] = cSamples[i]; // output a sample cSamples[nOut++] = (samples[ 0] + samples[21]) * coef[0] + (samples[ 1] + samples[20]) * coef[1] + (samples[ 2] + samples[19]) * coef[2] + (samples[ 3] + samples[18]) * coef[3] + (samples[ 4] + samples[17]) * coef[4] + (samples[ 5] + samples[16]) * coef[5] + (samples[ 6] + samples[15]) * coef[6] + (samples[ 7] + samples[14]) * coef[7] + (samples[ 8] + samples[13]) * coef[8] + (samples[ 9] + samples[12]) * coef[9] + (samples[10] + samples[11]) * coef[10] + center[10] * coef[11]; } } return nOut; } int quisk_dInterp2HB45(double * dsamples, int count, struct quisk_dHB45Filter * filter) { // Half-Band interpolation by 2 int i, k, nOut, nCoef, nSamp; double out; double * samples; static double coef[12] = { 0.000018566625444266, -0.000118469698701817, 0.000457318798253456, -0.001347840471412094, 0.003321838571445455, -0.007198422696929033, 0.014211106939802483, -0.026424776824073383, 0.048414810444971007, -0.096214669073304823, 0.314881034738348550, 0.500000000000000000 }; // Rate 96, cutoff 16-24-32, atten 120 dB. Coef[0] and [44] are zero. if (count > filter->nBuf) { // increase size of sample buffer filter->nBuf = count * 2; if (filter->dBuf) free(filter->dBuf); filter->dBuf = (double *)malloc(filter->nBuf * sizeof(double)); } nCoef = 12; nSamp = (nCoef - 1) * 2; memcpy(filter->dBuf, dsamples, count * sizeof(double)); samples = filter->samples; nOut = 0; for (i = 0; i < count; i++) { memmove(samples + 1, samples, (nSamp - 1) * sizeof(double)); samples[0] = filter->dBuf[i]; dsamples[nOut++] = samples[nCoef - 1] * coef[nCoef - 1] * 2; out = 0; for (k = 0; k < nSamp / 2; k++) out += (samples[k] + samples[nSamp - 1 - k]) * coef[k]; dsamples[nOut++] = out * 2; } return nOut; } int quisk_cInterp2HB45(complex * cSamples, int count, struct quisk_cHB45Filter * filter) { // Half-Band interpolation by 2 int i, k, nOut, nCoef, nSamp; complex out; complex * samples; static double coef[12] = { 0.000018566625444266, -0.000118469698701817, 0.000457318798253456, -0.001347840471412094, 0.003321838571445455, -0.007198422696929033, 0.014211106939802483, -0.026424776824073383, 0.048414810444971007, -0.096214669073304823, 0.314881034738348550, 0.500000000000000000 }; // Rate 96, cutoff 16-24-32, atten 120 dB. Coef[0] and [44] are zero. if (count > filter->nBuf) { // increase size of sample buffer filter->nBuf = count * 2; if (filter->cBuf) free(filter->cBuf); filter->cBuf = (complex *)malloc(filter->nBuf * sizeof(complex)); } nCoef = 12; nSamp = (nCoef - 1) * 2; memcpy(filter->cBuf, cSamples, count * sizeof(complex)); samples = filter->samples; nOut = 0; for (i = 0; i < count; i++) { memmove(samples + 1, samples, (nSamp - 1) * sizeof(complex)); samples[0] = filter->cBuf[i]; cSamples[nOut++] = samples[nCoef - 1] * coef[nCoef - 1] * 2; out = 0; for (k = 0; k < nSamp / 2; k++) out += (samples[k] + samples[nSamp - 1 - k]) * coef[k]; cSamples[nOut++] = out * 2; } return nOut; } quisk-3.6.11/quisk_conf_sdr8600.py0000644000175000017500000000235511641070520016220 0ustar jimjim00000000000000# These are the configuration parameters for receiving the # 10.7 MHz IF output of the AOR AR8600 receiver with the # SDR-IQ by RfSpace. This results in a 100 kHz to 3 GHz # wide range receiver with pan adapter. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. # Use this hardware module to control the AR8600 and SDR-IQ import quisk_hardware_sdr8600 as quisk_hardware # Start in FM mode default_mode = 'FM' use_sdriq = 1 # Use the SDR-IQ #sdriq_name = "/dev/ft2450" # Name of the SDR-IQ device to open sdriq_name = "/dev/ttyUSB2" # Name of the SDR-IQ device to open sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal) sdriq_decimation = 1250 # Must be 360, 500, 600, or 1250 sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this name_of_sound_capt = "" # We do not capture from the soundcard name_of_sound_play = "hw:0" # Play back on this soundcard # Note: For the SDR-IQ, playback is stereo at 48000 Hertz. channel_i = 0 # Soundcard index of left channel channel_q = 1 # Soundcard index of right channel display_fraction = 0.85 # The edges of the full bandwidth are not valid quisk-3.6.11/license.txt0000644000175000017500000004275711632372224014522 0ustar jimjim00000000000000This software is Copyright (C) 2007-2011 by James C. Ahlstrom, and is licensed for use under the GNU General Public License (GPL). See http://www.opensource.org. Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!! The GNU General Public License (GPL) Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. One line to give the program's name and a brief idea of what it does. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. quisk-3.6.11/quisk_hardware_hamlib.py0000664000175000017500000001342412124354341017222 0ustar jimjim00000000000000# This is a hardware file for control of a rig using the Hamlib rigctld daemon. # This hardware will not start the daemon rigctld, so you must start it yourself. # This hardware will connect to rigctld, and rigctld connects to the rig. You can test # rigctld with the command rigctl. See the hamlib documentation for rigctld and rigctl. # # If you change the frequency in Quisk, the change is sent to rigctld. This hardware # will query (poll) rigctld for its frequency at intervals to see if the rig changed # the frequency. If it did, the change is sent to Quisk. # # These are the attributes we watch: Rx frequency, mode from __future__ import print_function DEBUG = 0 import socket, time, traceback import _quisk as QS from quisk_hardware_model import Hardware as BaseHardware class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.hamlib_rigctld_port = 4532 # Standard rigctld control port self.hamlib_poll_seconds = 0.2 # Time interval to poll for changes self.hamlib_connected = False self.radio_freq = None self.radio_mode = None self.quisk_freq = None self.quisk_vfo = None self.quisk_mode = 'USB' self.received = '' self.toggle = False self.time0 = 0 def open(self): ret = BaseHardware.open(self) self.hamlib_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.hamlib_socket.settimeout(0.0) self.ConnectRigctld() return ret def close(self): self.hamlib_socket.close() self.hamlib_connected = False return BaseHardware.close(self) def ConnectRigctld(self): if self.hamlib_connected: return True try: self.hamlib_socket.connect(('localhost', self.hamlib_rigctld_port)) except: return False # Failure to connect self.hamlib_connected = True if DEBUG: print("rigctld connected") return True # Success def ChangeFrequency(self, tune, vfo, source='', band='', event=None): self.quisk_freq = tune self.quisk_vfo = tune if DEBUG: print('Change', source, tune) return self.quisk_freq, self.quisk_vfo def ReturnFrequency(self): # Return the current tuning and VFO frequency. If neither have changed, # you can return (None, None). This is called at about 10 Hz by the main. return self.quisk_freq, self.quisk_vfo def ChangeMode(self, mode): # Change the tx/rx mode # mode is a string: "USB", "AM", etc. if mode == 'CWU': mode = 'CW' elif mode == 'CWL': mode = 'CW' elif mode[0:4] == 'DGT-': mode = 'USB' self.quisk_mode = mode if DEBUG: print('Change', mode) def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. pass def HeartBeat(self): # Called at about 10 Hz by the main if not self.hamlib_connected: # Continually try to connect try: self.hamlib_socket.connect(('localhost', self.hamlib_rigctld_port)) except: return else: self.hamlib_connected = True if DEBUG: print("rigctld Connected") self.ReadHamlib() if time.time() - self.time0 < self.hamlib_poll_seconds: return self.time0 = time.time() if self.quisk_mode != self.radio_mode: self.HamlibSend("|M %s 0\n" % self.quisk_mode) elif self.quisk_freq != self.radio_freq: self.HamlibSend("|F %d\n" % self.quisk_freq) elif self.toggle: self.toggle = False self.HamlibSend("|f\n") # Poll for frequency else: self.toggle = True self.HamlibSend("|m\n") # Poll for mode def HamlibSend(self, text): if DEBUG: print('Send', text, end=' ') try: self.hamlib_socket.sendall(text) except socket.error: pass def ReadHamlib(self): if not self.hamlib_connected: return try: # Read any data from the socket text = self.hamlib_socket.recv(1024) except socket.timeout: # This does not work pass except socket.error: # Nothing to read pass else: # We got some characters self.received += text while '\n' in self.received: # A complete response ending with newline is available reply, self.received = self.received.split('\n', 1) # Split off the reply, save any further characters reply = reply.strip() # Here is our reply if reply[-6:] != 'RPRT 0': if DEBUG: print('Reject', reply) continue try: if reply[0:9] == 'set_freq:': # set_freq: 18120472|RPRT 0 freq, status = reply[9:].split('|') freq = int(freq) if DEBUG: print(' Radio S freq', freq) self.radio_freq = freq elif reply[0:9] == 'get_freq:': # get_freq:|Frequency: 18120450|RPRT 0 z, freq, status = reply.split('|') z, freq = freq.split(':') freq = int(freq) if DEBUG: print(' Radio G freq', freq) if self.quisk_freq == self.radio_freq: self.radio_freq = freq self.ChangeFrequency(freq, self.quisk_vfo, 'hamlib') elif reply[0:9] == 'set_mode:': # set_mode: FM 0|RPRT 0 mode, status = reply[9:].split('|') mode, z = mode.split() if DEBUG: print(' Radio S mode', mode) self.radio_mode = mode elif reply[0:9] == 'get_mode:': # get_mode:|Mode: FM|Passband: 12000|RPRT 0 z, mode, passb, status = reply.split('|') z, mode = mode.split() if DEBUG: print(' Radio G mode', mode) if self.quisk_mode == self.radio_mode: if self.radio_mode != mode: # The radio changed the mode self.radio_mode = mode self.quisk_mode = mode if mode in ('CW', 'CWR'): mode = 'CWU' self.application.OnBtnMode(None, mode) # Set mode else: if DEBUG: print('Unknown', reply) except: if DEBUG: traceback.print_exc() quisk-3.6.11/PKG-INFO0000664000175000017500000000300512164330433013412 0ustar jimjim00000000000000Metadata-Version: 1.1 Name: quisk Version: 3.6.11 Summary: QUISK, which rhymes with "brisk", is a Software Defined Radio (SDR). Home-page: http://james.ahlstrom.name/quisk/ Author: James C. Ahlstrom Author-email: jahlstr@gmail.com License: UNKNOWN Download-URL: http://james.ahlstrom.name/quisk/ Description: QUISK is a Software Defined Radio (SDR). You supply a complex (I/Q) mixer to convert radio spectrum to an intermediate frequency (IF) and send that IF to the left and right inputs of the sound card in your computer. The QUISK software will read the sound card data, tune it, filter it, demodulate it, and send the audio to the same sound card for output to external headphones or speakers. Quisk can also control and demodulate data from the SDR-IQ from RfSpace. Quisk works with the quisk_lppan_k3 package by Leigh, WA5ZNU, to control the N8LP LP-PAN panadapter and the Elecraft K3. Platform: UNKNOWN Classifier: Development Status :: 6 - Mature Classifier: Environment :: X11 Applications Classifier: Environment :: Win32 (MS Windows) Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: English Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python Classifier: Programming Language :: C Classifier: Topic :: Communications :: Ham Radio quisk-3.6.11/filters.py0000666000175000017500000021123211752275365014362 0ustar jimjim00000000000000# Rate 24000 sps, ripple 0.2 dB, atten 100 dB, shape 1.2 Filters = { 8500: # 55 taps [ -0.001578241201420500, -0.002488309592652162, 0.001185909979889287, 0.000286041612735020, -0.001914552184024928, 0.002760744242385052, -0.001796589368523962, -0.001056335106849282, 0.004390770806455585, -0.005824325923037834, 0.003465568616258560, 0.002462568821267293, -0.008988281812658983, 0.011629434198087422, -0.007027876977623796, -0.004272818661253936, 0.016890540812408691, -0.022619963224181760, 0.014949848668575091, 0.006115840936585570, -0.031813780331403710, 0.046915611796058194, -0.036226209362519565, -0.007500120805011563, 0.078216492123247466, -0.156996838729026640, 0.218668091485032380, 0.758014834761081340, 0.218668091485032380, -0.156996838729026640, 0.078216492123247466, -0.007500120805011563, -0.036226209362519565, 0.046915611796058194, -0.031813780331403710, 0.006115840936585570, 0.014949848668575091, -0.022619963224181760, 0.016890540812408691, -0.004272818661253936, -0.007027876977623796, 0.011629434198087422, -0.008988281812658983, 0.002462568821267293, 0.003465568616258560, -0.005824325923037834, 0.004390770806455585, -0.001056335106849282, -0.001796589368523962, 0.002760744242385052, -0.001914552184024928, 0.000286041612735020, 0.001185909979889287, -0.002488309592652162, -0.001578241201420500], 7500: # 62 taps [ 0.000094561136776712, 0.001408783281963872, 0.003252521294198745, 0.001088470223697677, -0.002238006126669353, 0.000797427337925380, 0.001818354390057951, -0.002971083246008131, 0.000737271087741229, 0.003304967641132078, -0.004678221609224611, 0.000618143813431047, 0.005732278632558854, -0.007264716193352521, 0.000382151456262394, 0.009375552017313197, -0.011107789354244654, 0.000048810931888440, 0.014797494013431127, -0.016988015917755381, -0.000322746345617388, 0.023289857616213484, -0.026716501910571362, -0.000681860486120778, 0.038508535988246995, -0.045999278172093885, -0.000961050429347091, 0.076884527279961243, -0.108006033576806130, -0.001113929105132611, 0.551548401015432340, 0.551548401015432340, -0.001113929105132611, -0.108006033576806130, 0.076884527279961243, -0.000961050429347091, -0.045999278172093885, 0.038508535988246995, -0.000681860486120778, -0.026716501910571362, 0.023289857616213484, -0.000322746345617388, -0.016988015917755381, 0.014797494013431127, 0.000048810931888440, -0.011107789354244654, 0.009375552017313197, 0.000382151456262394, -0.007264716193352521, 0.005732278632558854, 0.000618143813431047, -0.004678221609224611, 0.003304967641132078, 0.000737271087741229, -0.002971083246008131, 0.001818354390057951, 0.000797427337925380, -0.002238006126669353, 0.001088470223697677, 0.003252521294198745, 0.001408783281963872, 0.000094561136776712], 6000: # 77 taps [0.000208183216794497, 0.001160220144497454, 0.002498877019501132, 0.002217684703504632, -0.000364985361618348, -0.001823661861823501, 0.000356579314286080, 0.002005946277037424, -0.000685757071824683, -0.002428321330453817, 0.001256816376812629, 0.002943833745660115, -0.002130949481744204, -0.003446793644558851, 0.003380457505759830, 0.003807055791440830, -0.005074958590792311, -0.003869772827804518, 0.007242784565398008, 0.003418656761533474, -0.009894698971107840, -0.002211451952907241, 0.012977467451293289, -0.000058006701182926, -0.016390443243429843, 0.003773319671211690, 0.019989716564592076, -0.009449626980637388, -0.023581188491464997, 0.017927337095200193, 0.026945533578336647, -0.030887338584165511, -0.029856365801280219, 0.052657593695444822, 0.032108551641510746, -0.099253908185103573, -0.033533139787951992, 0.315983886115891840, 0.534019780032233380, 0.315983886115891840, -0.033533139787951992, -0.099253908185103573, 0.032108551641510746, 0.052657593695444822, -0.029856365801280219, -0.030887338584165511, 0.026945533578336647, 0.017927337095200193, -0.023581188491464997, -0.009449626980637388, 0.019989716564592076, 0.003773319671211690, -0.016390443243429843, -0.000058006701182926, 0.012977467451293289, -0.002211451952907241, -0.009894698971107840, 0.003418656761533474, 0.007242784565398008, -0.003869772827804518, -0.005074958590792311, 0.003807055791440830, 0.003380457505759830, -0.003446793644558851, -0.002130949481744204, 0.002943833745660115, 0.001256816376812629, -0.002428321330453817, -0.000685757071824683, 0.002005946277037424, 0.000356579314286080, -0.001823661861823501, -0.000364985361618348, 0.002217684703504632, 0.002498877019501132, 0.001160220144497454, 0.000208183216794497], 5000: # 92 taps [ 0.000172282027074915, 0.000805722137099302, 0.001789488027434626, 0.002208898476835740, 0.001133555920432830, -0.000798012231727563, -0.001468876483570138, 0.000053213574826391, 0.001640044205108085, 0.000693959429133929, -0.001663633271521857, -0.001609719846438075, 0.001334915862232435, 0.002601113060240987, -0.000511327252542249, -0.003459777069001452, -0.000863807590293483, 0.003915575549171324, 0.002725579328876624, -0.003678783180717698, -0.004875619345633069, 0.002500119680365451, 0.006978228022424931, -0.000223624762857588, -0.008586543420189311, -0.003156720729060025, 0.009180028261871051, 0.007460886285077675, -0.008222908809263846, -0.012298402032805727, 0.005219135899689294, 0.017069401572755501, 0.000240426913514277, -0.020971624610692834, -0.008474182212803629, 0.022996901553415793, 0.019787130769856574, -0.021836278313112276, -0.034759648853466663, 0.015468734639474426, 0.055194479055695952, 0.000590985958335975, -0.088238504731419823, -0.043831925654670714, 0.182996493758220890, 0.409587845444253250, 0.409587845444253250, 0.182996493758220890, -0.043831925654670714, -0.088238504731419823, 0.000590985958335975, 0.055194479055695952, 0.015468734639474426, -0.034759648853466663, -0.021836278313112276, 0.019787130769856574, 0.022996901553415793, -0.008474182212803629, -0.020971624610692834, 0.000240426913514277, 0.017069401572755501, 0.005219135899689294, -0.012298402032805727, -0.008222908809263846, 0.007460886285077675, 0.009180028261871051, -0.003156720729060025, -0.008586543420189311, -0.000223624762857588, 0.006978228022424931, 0.002500119680365451, -0.004875619345633069, -0.003678783180717698, 0.002725579328876624, 0.003915575549171324, -0.000863807590293483, -0.003459777069001452, -0.000511327252542249, 0.002601113060240987, 0.001334915862232435, -0.001609719846438075, -0.001663633271521857, 0.000693959429133929, 0.001640044205108085, 0.000053213574826391, -0.001468876483570138, -0.000798012231727563, 0.001133555920432830, 0.002208898476835740, 0.001789488027434626, 0.000805722137099302, 0.000172282027074915], 4000: # 115 taps [ 0.000078524780320715, 0.000329316620713670, 0.000756688762644958, 0.001124260123708105, 0.001012255791778806, 0.000167097630541898, -0.001099970608704988, -0.001940975178324101, -0.001625045960154994, -0.000333634994172134, 0.000774600995458535, 0.000561151578352762, -0.000854751315214004, -0.001984988321940357, -0.001407739886101419, 0.000563473972774177, 0.001900424989770745, 0.000925528523083090, -0.001609328373038515, -0.002935359144493341, -0.001199176692593675, 0.002118199425756780, 0.003340065554812114, 0.000621160360920014, -0.003467567745617676, -0.004224605385298791, -0.000122849763708023, 0.004757557369118008, 0.004664298923525774, -0.001148493552322016, -0.006629807337962404, -0.005080846185003255, 0.002831233307698604, 0.008609924128977818, 0.004891354675929344, -0.005425659232916345, -0.010937452229276256, -0.004116901228197529, 0.008877312794209294, 0.013300805492116527, 0.002232134062032589, -0.013614806007146969, -0.015720726837983701, 0.001140172406302503, 0.019985979932262889, 0.017946437617680795, -0.007018595519087580, -0.029113241143045584, -0.019901010720465118, 0.017502959326722210, 0.043879416112787749, 0.021395356319346116, -0.039872421015430898, -0.076438935865810770, -0.022353637195009195, 0.124776719393937450, 0.286085089477746360, 0.356006518780215160, 0.286085089477746360, 0.124776719393937450, -0.022353637195009195, -0.076438935865810770, -0.039872421015430898, 0.021395356319346116, 0.043879416112787749, 0.017502959326722210, -0.019901010720465118, -0.029113241143045584, -0.007018595519087580, 0.017946437617680795, 0.019985979932262889, 0.001140172406302503, -0.015720726837983701, -0.013614806007146969, 0.002232134062032589, 0.013300805492116527, 0.008877312794209294, -0.004116901228197529, -0.010937452229276256, -0.005425659232916345, 0.004891354675929344, 0.008609924128977818, 0.002831233307698604, -0.005080846185003255, -0.006629807337962404, -0.001148493552322016, 0.004664298923525774, 0.004757557369118008, -0.000122849763708023, -0.004224605385298791, -0.003467567745617676, 0.000621160360920014, 0.003340065554812114, 0.002118199425756780, -0.001199176692593675, -0.002935359144493341, -0.001609328373038515, 0.000925528523083090, 0.001900424989770745, 0.000563473972774177, -0.001407739886101419, -0.001984988321940357, -0.000854751315214004, 0.000561151578352762, 0.000774600995458535, -0.000333634994172134, -0.001625045960154994, -0.001940975178324101, -0.001099970608704988, 0.000167097630541898, 0.001012255791778806, 0.001124260123708105, 0.000756688762644958, 0.000329316620713670, 0.000078524780320715], 3000: # 153 taps [ 0.000035516842253053, 0.000120241356692793, 0.000262655558849812, 0.000421822903927101, 0.000504577556110132, 0.000393748344899348, 0.000013887896365045, -0.000595749610102644, -0.001250516069080062, -0.001672797229233531, -0.001624666112532619, -0.001059802835950466, -0.000199611602796516, 0.000539126532493226, 0.000756552265297489, 0.000316087930054194, -0.000530090257617794, -0.001244496438584232, -0.001312107606392913, -0.000583465448463906, 0.000572285419075017, 0.001440987738923421, 0.001399231913182619, 0.000355359654986622, -0.001108071194955440, -0.002036249585608732, -0.001707924634389252, -0.000169594756520662, 0.001685676765584473, 0.002618141236597755, 0.001855681542593165, -0.000301881949096732, -0.002542398236828585, -0.003317624887398237, -0.001892391320644168, 0.001031582912020721, 0.003613502326574886, 0.004009329165673526, 0.001661239094822322, -0.002143832449766766, -0.004935146076383144, -0.004634572876828250, -0.001061541395886805, 0.003698344992855291, 0.006465358367957256, 0.005053382115343493, -0.000073525601278193, -0.005791007488487868, -0.008166064459464053, -0.005109407447857288, 0.001926336767092539, 0.008511258651897639, 0.009958456933858797, 0.004574761558815073, -0.004759500034603159, -0.012000283350062089, -0.011748002733961208, -0.003120526928071337, 0.008993494047071084, 0.016529385910476514, 0.013426861274101313, 0.000181178754148492, -0.015466003330041472, -0.022748666494653846, -0.014877802849879123, 0.005502737892245722, 0.026345716718994539, 0.032621748472455206, 0.016002483863926359, -0.017887767208878101, -0.049636964594866217, -0.054713319818683277, -0.016713474537575129, 0.061906959876918494, 0.157995584096340960, 0.236648015289099320, 0.266956938993864910, 0.236648015289099320, 0.157995584096340960, 0.061906959876918494, -0.016713474537575129, -0.054713319818683277, -0.049636964594866217, -0.017887767208878101, 0.016002483863926359, 0.032621748472455206, 0.026345716718994539, 0.005502737892245722, -0.014877802849879123, -0.022748666494653846, -0.015466003330041472, 0.000181178754148492, 0.013426861274101313, 0.016529385910476514, 0.008993494047071084, -0.003120526928071337, -0.011748002733961208, -0.012000283350062089, -0.004759500034603159, 0.004574761558815073, 0.009958456933858797, 0.008511258651897639, 0.001926336767092539, -0.005109407447857288, -0.008166064459464053, -0.005791007488487868, -0.000073525601278193, 0.005053382115343493, 0.006465358367957256, 0.003698344992855291, -0.001061541395886805, -0.004634572876828250, -0.004935146076383144, -0.002143832449766766, 0.001661239094822322, 0.004009329165673526, 0.003613502326574886, 0.001031582912020721, -0.001892391320644168, -0.003317624887398237, -0.002542398236828585, -0.000301881949096732, 0.001855681542593165, 0.002618141236597755, 0.001685676765584473, -0.000169594756520662, -0.001707924634389252, -0.002036249585608732, -0.001108071194955440, 0.000355359654986622, 0.001399231913182619, 0.001440987738923421, 0.000572285419075017, -0.000583465448463906, -0.001312107606392913, -0.001244496438584232, -0.000530090257617794, 0.000316087930054194, 0.000756552265297489, 0.000539126532493226, -0.000199611602796516, -0.001059802835950466, -0.001624666112532619, -0.001672797229233531, -0.001250516069080062, -0.000595749610102644, 0.000013887896365045, 0.000393748344899348, 0.000504577556110132, 0.000421822903927101, 0.000262655558849812, 0.000120241356692793, 0.000035516842253053], 2800: # 164 taps [ 0.000031131729843669, 0.000101363194753254, 0.000221445426297415, 0.000366876574918002, 0.000474767078312489, 0.000455842035531617, 0.000232260566090893, -0.000211274148558287, -0.000789599231892209, -0.001321558408924163, -0.001590694231360794, -0.001445876584766002, -0.000895790759735873, -0.000140741015448872, 0.000492974178868593, 0.000701994832615354, 0.000371048524479058, -0.000337331657814867, -0.001034893398244673, -0.001296923457098872, -0.000901505495786621, 0.000013737161230886, 0.000983722390445291, 0.001446949255083495, 0.001067648443145340, -0.000031354774249279, -0.001279007610852184, -0.001938862367504847, -0.001531888866790246, -0.000161657161535566, 0.001470243306104189, 0.002410991575715065, 0.002003292184824320, 0.000324608046693798, -0.001764616004515830, -0.003045092340783782, -0.002637146414877572, -0.000580772176139985, 0.002073712223135724, 0.003782183003317882, 0.003389875946583850, 0.000885046737439423, -0.002455184150014141, -0.004690784048082864, -0.004326357662532086, -0.001279167957787954, 0.002902671922490944, 0.005795008254325585, 0.005478283962467929, 0.001772012477148658, -0.003450331904449436, -0.007166940301855534, -0.006922766471023288, -0.002399780547747377, 0.004134972375816635, 0.008909643621809859, 0.008776960071400969, 0.003217389082858829, -0.005021094247026112, -0.011201040385085154, -0.011246577131734643, -0.004323921802028225, 0.006225285499714047, 0.014372818914766290, 0.014725605621083649, 0.005913959753070873, -0.007987043798634774, -0.019127577707865114, -0.020080950001885520, -0.008435384367710340, 0.010879472951485192, 0.027244661531034900, 0.029649597250285761, 0.013188790214990415, -0.016693663421477496, -0.044885495280403948, -0.052572421004629472, -0.026098663081897257, 0.035426680640922303, 0.117691081437968410, 0.195575709828410660, 0.242828423889182740, 0.242828423889182740, 0.195575709828410660, 0.117691081437968410, 0.035426680640922303, -0.026098663081897257, -0.052572421004629472, -0.044885495280403948, -0.016693663421477496, 0.013188790214990415, 0.029649597250285761, 0.027244661531034900, 0.010879472951485192, -0.008435384367710340, -0.020080950001885520, -0.019127577707865114, -0.007987043798634774, 0.005913959753070873, 0.014725605621083649, 0.014372818914766290, 0.006225285499714047, -0.004323921802028225, -0.011246577131734643, -0.011201040385085154, -0.005021094247026112, 0.003217389082858829, 0.008776960071400969, 0.008909643621809859, 0.004134972375816635, -0.002399780547747377, -0.006922766471023288, -0.007166940301855534, -0.003450331904449436, 0.001772012477148658, 0.005478283962467929, 0.005795008254325585, 0.002902671922490944, -0.001279167957787954, -0.004326357662532086, -0.004690784048082864, -0.002455184150014141, 0.000885046737439423, 0.003389875946583850, 0.003782183003317882, 0.002073712223135724, -0.000580772176139985, -0.002637146414877572, -0.003045092340783782, -0.001764616004515830, 0.000324608046693798, 0.002003292184824320, 0.002410991575715065, 0.001470243306104189, -0.000161657161535566, -0.001531888866790246, -0.001938862367504847, -0.001279007610852184, -0.000031354774249279, 0.001067648443145340, 0.001446949255083495, 0.000983722390445291, 0.000013737161230886, -0.000901505495786621, -0.001296923457098872, -0.001034893398244673, -0.000337331657814867, 0.000371048524479058, 0.000701994832615354, 0.000492974178868593, -0.000140741015448872, -0.000895790759735873, -0.001445876584766002, -0.001590694231360794, -0.001321558408924163, -0.000789599231892209, -0.000211274148558287, 0.000232260566090893, 0.000455842035531617, 0.000474767078312489, 0.000366876574918002, 0.000221445426297415, 0.000101363194753254, 0.000031131729843669], 2500: # 184 taps [ 0.000025917992771962, 0.000080053245121681, 0.000175970492512707, 0.000306338738553062, 0.000441565642149420, 0.000529323030925432, 0.000506924615738917, 0.000324946604356638, -0.000025129491557388, -0.000491406291157732, -0.000962621820235116, -0.001296070805120129, -0.001367486032675225, -0.001125819560345427, -0.000629044038382859, -0.000039974702137716, 0.000424508165741649, 0.000577252836600570, 0.000345217289298406, -0.000184075454087644, -0.000781983763019378, -0.001165504636264451, -0.001120965614204760, -0.000611972955861357, 0.000181852749867249, 0.000923465749187075, 0.001259585458205595, 0.000987840637523650, 0.000172679353454093, -0.000852839379782549, -0.001614970097646428, -0.001711408440970664, -0.001014931729801465, 0.000231871248756494, 0.001490613857222986, 0.002154309898448981, 0.001835132214640792, 0.000579040055238457, -0.001106680482118841, -0.002448432281636389, -0.002754083239929045, -0.001760402090267228, 0.000190461179667856, 0.002251447413131553, 0.003429705849477585, 0.003056701038439272, 0.001150595364468159, -0.001518817798865299, -0.003726827835919960, -0.004345414044232734, -0.002906143603126905, 0.000100825920300210, 0.003366376342127399, 0.005318377282596896, 0.004864845763651887, 0.001979300066273931, -0.002175246374000726, -0.005692516278767321, -0.006780045002879058, -0.004649909783330805, -0.000010396809644141, 0.005123662380431661, 0.008280363892442090, 0.007693898397635463, 0.003246147289573304, -0.003296547115364492, -0.008942285826077026, -0.010803588267982528, -0.007523983582706444, -0.000118131836810526, 0.008247900700950585, 0.013549640285344118, 0.012768247956349992, 0.005492469173933735, -0.005544176969275239, -0.015378525898323159, -0.018928522076093565, -0.013447400254072768, -0.000204681888673014, 0.015499492179231059, 0.026221846254622386, 0.025562428680330915, 0.011389219733612054, -0.012327402868838598, -0.036056520568517325, -0.047698955925824099, -0.037076675237560336, -0.000252599132841553, 0.058062325226935912, 0.125125149137395140, 0.183789926776792010, 0.217965757483672360, 0.217965757483672360, 0.183789926776792010, 0.125125149137395140, 0.058062325226935912, -0.000252599132841553, -0.037076675237560336, -0.047698955925824099, -0.036056520568517325, -0.012327402868838598, 0.011389219733612054, 0.025562428680330915, 0.026221846254622386, 0.015499492179231059, -0.000204681888673014, -0.013447400254072768, -0.018928522076093565, -0.015378525898323159, -0.005544176969275239, 0.005492469173933735, 0.012768247956349992, 0.013549640285344118, 0.008247900700950585, -0.000118131836810526, -0.007523983582706444, -0.010803588267982528, -0.008942285826077026, -0.003296547115364492, 0.003246147289573304, 0.007693898397635463, 0.008280363892442090, 0.005123662380431661, -0.000010396809644141, -0.004649909783330805, -0.006780045002879058, -0.005692516278767321, -0.002175246374000726, 0.001979300066273931, 0.004864845763651887, 0.005318377282596896, 0.003366376342127399, 0.000100825920300210, -0.002906143603126905, -0.004345414044232734, -0.003726827835919960, -0.001518817798865299, 0.001150595364468159, 0.003056701038439272, 0.003429705849477585, 0.002251447413131553, 0.000190461179667856, -0.001760402090267228, -0.002754083239929045, -0.002448432281636389, -0.001106680482118841, 0.000579040055238457, 0.001835132214640792, 0.002154309898448981, 0.001490613857222986, 0.000231871248756494, -0.001014931729801465, -0.001711408440970664, -0.001614970097646428, -0.000852839379782549, 0.000172679353454093, 0.000987840637523650, 0.001259585458205595, 0.000923465749187075, 0.000181852749867249, -0.000611972955861357, -0.001120965614204760, -0.001165504636264451, -0.000781983763019378, -0.000184075454087644, 0.000345217289298406, 0.000577252836600570, 0.000424508165741649, -0.000039974702137716, -0.000629044038382859, -0.001125819560345427, -0.001367486032675225, -0.001296070805120129, -0.000962621820235116, -0.000491406291157732, -0.000025129491557388, 0.000324946604356638, 0.000506924615738917, 0.000529323030925432, 0.000441565642149420, 0.000306338738553062, 0.000175970492512707, 0.000080053245121681, 0.000025917992771962], 2200: #208 taps [ 0.000019773973500698, 0.000050300702719923, 0.000099108356371034, 0.000158194404233062, 0.000210525538441445, 0.000229815943545636, 0.000185844232898202, 0.000053925802103604, -0.000173777821813056, -0.000478713240844808, -0.000812707500835325, -0.001104087723445511, -0.001273942998532759, -0.001259278130931017, -0.001036517683714317, -0.000637135855849719, -0.000147905388336950, 0.000307371053002897, 0.000601888175399474, 0.000646481239850203, 0.000423598448328852, 0.000001477795930511, -0.000479511456398659, -0.000847542574860787, -0.000956181777710176, -0.000738934578391376, -0.000241404176917473, 0.000383518196967566, 0.000920251953818672, 0.001163208934048226, 0.000993921481591226, 0.000434388361798019, -0.000346030182304409, -0.001078079759008518, -0.001482742622315739, -0.001374843351537245, -0.000742498373847161, 0.000230275873300524, 0.001212510588437732, 0.001835971920260912, 0.001830429895718975, 0.001135824361158899, -0.000053708874146025, -0.001337763115758486, -0.002240751224958943, -0.002384735614959788, -0.001642386517013215, -0.000209813690831605, 0.001436458922346993, 0.002693390382420342, 0.003048363283850710, 0.002282591868736866, 0.000582131982803615, -0.001494683726987109, -0.003194641328318874, -0.003837926603637492, -0.003083544121084786, -0.001090420131933939, 0.001496937564140111, 0.003749027796032780, 0.004778960997800515, 0.004083937494744029, 0.001771796479680179, -0.001424175363221383, -0.004367185919670888, -0.005912778052177615, -0.005343837748934002, -0.002682898015250491, 0.001248211259214371, 0.005067191417250770, 0.007305293729039890, 0.006958279310681562, 0.003912446091368335, -0.000927394507475861, -0.005884363717650123, -0.009072440354829070, -0.009093145110623519, -0.005615743824657722, 0.000389138616762466, 0.006884468473346532, 0.011428522924352827, 0.012058034647345471, 0.008084684337356606, 0.000498409327693868, -0.008214286092348189, -0.014832606629260737, -0.016526271123526743, -0.011969567139734955, -0.002035744936384088, 0.010229678038446030, 0.020433030409654745, 0.024256700710114647, 0.019055511377788287, 0.005093243716641166, -0.014044229049919777, -0.032091634104820632, -0.041707387370849711, -0.036619723239870061, -0.013689386302707808, 0.025758635108220899, 0.075797616878918297, 0.127078744612693170, 0.169056056140688250, 0.192658606871644660, 0.192658606871644660, 0.169056056140688250, 0.127078744612693170, 0.075797616878918297, 0.025758635108220899, -0.013689386302707808, -0.036619723239870061, -0.041707387370849711, -0.032091634104820632, -0.014044229049919777, 0.005093243716641166, 0.019055511377788287, 0.024256700710114647, 0.020433030409654745, 0.010229678038446030, -0.002035744936384088, -0.011969567139734955, -0.016526271123526743, -0.014832606629260737, -0.008214286092348189, 0.000498409327693868, 0.008084684337356606, 0.012058034647345471, 0.011428522924352827, 0.006884468473346532, 0.000389138616762466, -0.005615743824657722, -0.009093145110623519, -0.009072440354829070, -0.005884363717650123, -0.000927394507475861, 0.003912446091368335, 0.006958279310681562, 0.007305293729039890, 0.005067191417250770, 0.001248211259214371, -0.002682898015250491, -0.005343837748934002, -0.005912778052177615, -0.004367185919670888, -0.001424175363221383, 0.001771796479680179, 0.004083937494744029, 0.004778960997800515, 0.003749027796032780, 0.001496937564140111, -0.001090420131933939, -0.003083544121084786, -0.003837926603637492, -0.003194641328318874, -0.001494683726987109, 0.000582131982803615, 0.002282591868736866, 0.003048363283850710, 0.002693390382420342, 0.001436458922346993, -0.000209813690831605, -0.001642386517013215, -0.002384735614959788, -0.002240751224958943, -0.001337763115758486, -0.000053708874146025, 0.001135824361158899, 0.001830429895718975, 0.001835971920260912, 0.001212510588437732, 0.000230275873300524, -0.000742498373847161, -0.001374843351537245, -0.001482742622315739, -0.001078079759008518, -0.000346030182304409, 0.000434388361798019, 0.000993921481591226, 0.001163208934048226, 0.000920251953818672, 0.000383518196967566, -0.000241404176917473, -0.000738934578391376, -0.000956181777710176, -0.000847542574860787, -0.000479511456398659, 0.000001477795930511, 0.000423598448328852, 0.000646481239850203, 0.000601888175399474, 0.000307371053002897, -0.000147905388336950, -0.000637135855849719, -0.001036517683714317, -0.001259278130931017, -0.001273942998532759, -0.001104087723445511, -0.000812707500835325, -0.000478713240844808, -0.000173777821813056, 0.000053925802103604, 0.000185844232898202, 0.000229815943545636, 0.000210525538441445, 0.000158194404233062, 0.000099108356371034, 0.000050300702719923, 0.000019773973500698], 2000: # 230 taps [ 0.000018263332334824, 0.000047149978647285, 0.000097406241243338, 0.000168379817473922, 0.000253967146823514, 0.000340023431940833, 0.000404952972379638, 0.000422974737428721, 0.000369902505736477, 0.000230539284736893, 0.000005684130024729, -0.000283317092531425, -0.000594762485225633, -0.000872546941267996, -0.001057521343918215, -0.001102228302856328, -0.000985222996371773, -0.000720881682050162, -0.000360902436481765, 0.000014352678995945, 0.000313854754768513, 0.000459361314264358, 0.000408357201159471, 0.000169601665199639, -0.000194309748856567, -0.000579769259034295, -0.000868450605965827, -0.000960850467769566, -0.000807759775150557, -0.000429923379846805, 0.000081456338895501, 0.000585585033204507, 0.000930280363007829, 0.000997553630123726, 0.000743304377770887, 0.000218142932019430, -0.000439021999187466, -0.001035464584506922, -0.001379274582853274, -0.001339118806894442, -0.000890898584125663, -0.000135426700809927, 0.000721291534689607, 0.001422586528925900, 0.001736709146196323, 0.001531678957580429, 0.000825809348346554, -0.000204332584606896, -0.001264953954035041, -0.002026681147110289, -0.002224767812024736, -0.001747989347578871, -0.000687126008900549, 0.000675855233958752, 0.001939810141526326, 0.002700254906709327, 0.002676337670079708, 0.001809809227907344, 0.000302346385971505, -0.001425894059131038, -0.002850111164443048, -0.003497344177823653, -0.003099785097153715, -0.001696282588251145, 0.000354381431382131, 0.002459975729847483, 0.003962117890550910, 0.004338291351008917, 0.003377760857642002, 0.001273722107127891, -0.001404260811957126, -0.003858729944018619, -0.005296868477641261, -0.005180794578143301, -0.003418238131210470, -0.000428690403667462, 0.002946095146143898, 0.005671970307130408, 0.006832059383649537, 0.005925580242615656, 0.003061135525037048, -0.001025055462746871, -0.005146493168885704, -0.008000447007066858, -0.008567643322000875, -0.006458387751298429, -0.002092389293377035, 0.003358433615988978, 0.008267542643372157, 0.011021009169962534, 0.010525039504447272, 0.006600477461859877, 0.000131874225722409, -0.007098295196117369, -0.012870086951713777, -0.015169746940300757, -0.012839241513492812, -0.006035689378457242, 0.003657448927275838, 0.013537787301098309, 0.020464471653522786, 0.021753420096582588, 0.016052407125049746, 0.003944898543127921, -0.011915101650258511, -0.027222337492958711, -0.036934437155297005, -0.036483323022197825, -0.022992339899140058, 0.003814121297142671, 0.041261656200314752, 0.084061156150449762, 0.125284573669860120, 0.157774677964436120, 0.175667194419142110, 0.175667194419142110, 0.157774677964436120, 0.125284573669860120, 0.084061156150449762, 0.041261656200314752, 0.003814121297142671, -0.022992339899140058, -0.036483323022197825, -0.036934437155297005, -0.027222337492958711, -0.011915101650258511, 0.003944898543127921, 0.016052407125049746, 0.021753420096582588, 0.020464471653522786, 0.013537787301098309, 0.003657448927275838, -0.006035689378457242, -0.012839241513492812, -0.015169746940300757, -0.012870086951713777, -0.007098295196117369, 0.000131874225722409, 0.006600477461859877, 0.010525039504447272, 0.011021009169962534, 0.008267542643372157, 0.003358433615988978, -0.002092389293377035, -0.006458387751298429, -0.008567643322000875, -0.008000447007066858, -0.005146493168885704, -0.001025055462746871, 0.003061135525037048, 0.005925580242615656, 0.006832059383649537, 0.005671970307130408, 0.002946095146143898, -0.000428690403667462, -0.003418238131210470, -0.005180794578143301, -0.005296868477641261, -0.003858729944018619, -0.001404260811957126, 0.001273722107127891, 0.003377760857642002, 0.004338291351008917, 0.003962117890550910, 0.002459975729847483, 0.000354381431382131, -0.001696282588251145, -0.003099785097153715, -0.003497344177823653, -0.002850111164443048, -0.001425894059131038, 0.000302346385971505, 0.001809809227907344, 0.002676337670079708, 0.002700254906709327, 0.001939810141526326, 0.000675855233958752, -0.000687126008900549, -0.001747989347578871, -0.002224767812024736, -0.002026681147110289, -0.001264953954035041, -0.000204332584606896, 0.000825809348346554, 0.001531678957580429, 0.001736709146196323, 0.001422586528925900, 0.000721291534689607, -0.000135426700809927, -0.000890898584125663, -0.001339118806894442, -0.001379274582853274, -0.001035464584506922, -0.000439021999187466, 0.000218142932019430, 0.000743304377770887, 0.000997553630123726, 0.000930280363007829, 0.000585585033204507, 0.000081456338895501, -0.000429923379846805, -0.000807759775150557, -0.000960850467769566, -0.000868450605965827, -0.000579769259034295, -0.000194309748856567, 0.000169601665199639, 0.000408357201159471, 0.000459361314264358, 0.000313854754768513, 0.000014352678995945, -0.000360902436481765, -0.000720881682050162, -0.000985222996371773, -0.001102228302856328, -0.001057521343918215, -0.000872546941267996, -0.000594762485225633, -0.000283317092531425, 0.000005684130024729, 0.000230539284736893, 0.000369902505736477, 0.000422974737428721, 0.000404952972379638, 0.000340023431940833, 0.000253967146823514, 0.000168379817473922, 0.000097406241243338, 0.000047149978647285, 0.000018263332334824], 1200: # 390 taps [ -0.000004331430434813, 0.000000895178754483, 0.000004819206934844, 0.000012387135981227, 0.000024702874344864, 0.000042904801446151, 0.000067985064859609, 0.000100627030615644, 0.000141025873402660, 0.000188738905083740, 0.000242545741476270, 0.000300399529662751, 0.000359433330154281, 0.000416062388387887, 0.000466131771574125, 0.000505276256945394, 0.000529201721306850, 0.000534142706869689, 0.000517270879752382, 0.000477091889474874, 0.000413779420856055, 0.000329374266276144, 0.000227844055373822, 0.000114956874548630, -0.000002037964985788, -0.000114915331771079, -0.000215124321927526, -0.000294538502564660, -0.000346261198238618, -0.000365357958551737, -0.000349492174517184, -0.000299346594446952, -0.000218781210350266, -0.000114696259371792, 0.000003439467944363, 0.000124342943768293, 0.000235923038322712, 0.000326439472488279, 0.000385716174095538, 0.000406270345323467, 0.000384244892423745, 0.000320026589486952, 0.000218451713387220, 0.000088560889198400, -0.000057113100623293, -0.000203679685243764, -0.000335341513050654, -0.000437048860128537, -0.000496163931220179, -0.000503976472887228, -0.000456879139659229, -0.000357064175200153, -0.000212619491029857, -0.000036988477009561, 0.000152196470731637, 0.000334813551887072, 0.000490329017689163, 0.000600045160004744, 0.000649282295414473, 0.000629236561431697, 0.000538304340843976, 0.000382670778203303, 0.000176071280391891, -0.000061311579103233, -0.000304731538051063, -0.000527388822625111, -0.000703310824877695, -0.000810309677712974, -0.000832681816046785, -0.000763333939111765, -0.000605059771056946, -0.000370777976208385, -0.000082637093413831, 0.000229962373724818, 0.000533282556646377, 0.000792807201162301, 0.000977090407652497, 0.001061465563886132, 0.001031195280476629, 0.000883666665500652, 0.000629337435771274, 0.000291251466919408, -0.000096894708513463, -0.000493996123025552, -0.000855794020410478, -0.001139717153414092, -0.001309782074955667, -0.001341010390430392, -0.001222824367769252, -0.000960990590585683, -0.000577807284515617, -0.000110428182918688, 0.000392587860975165, 0.000876197024190483, 0.001284780403728217, 0.001568419571371085, 0.001688844037687690, 0.001624356624161237, 0.001373126810656710, 0.000954389812320343, 0.000407316271842430, -0.000212443049446438, -0.000838254589610985, -0.001399522686014101, -0.001829507546348522, -0.002073092512801241, -0.002093612886275790, -0.001877924713394541, -0.001439048979367570, -0.000815971265919441, -0.000070480695977658, 0.000718736847294852, 0.001464215661002276, 0.002079218519234449, 0.002487627013869813, 0.002633104169545422, 0.002486455189532861, 0.002050261072858978, 0.001360126142354939, 0.000482234298234895, -0.000492687418387142, -0.001458485408297803, -0.002304891424791415, -0.002929849705482365, -0.003251510669015779, -0.003218513620108414, -0.002817308401190046, -0.002075543578763564, -0.001060944493273319, 0.000124409621994965, 0.001353984612741832, 0.002489950284201132, 0.003398266860636230, 0.003964087731928019, 0.004105749968228098, 0.003785703607610913, 0.003016991173328030, 0.001864327522378759, 0.000439388406465501, -0.001109448711112102, -0.002612032761559656, -0.003894589690524808, -0.004799215003224437, -0.005202582868054837, -0.005031731058566960, -0.004274996752467488, -0.002986628326221043, -0.001284225000364678, 0.000661081413588171, 0.002640990158453115, 0.004431457793095885, 0.005817070614785085, 0.006615805917154524, 0.006701450960612391, 0.006021062146242219, 0.004605255832862724, 0.002569791244804701, 0.000107781839820803, -0.002527142979701336, -0.005045394324250144, -0.007151459446961864, -0.008576455016121923, -0.009109805876143171, -0.008626557809676316, -0.007107110348255605, -0.004646780506669336, -0.001453545516455117, 0.002166532839260334, 0.005835432981396591, 0.009138830213137229, 0.011668164700843125, 0.013065169962452085, 0.013064440018490608, 0.011529579182106710, 0.008478886219133458, 0.004097368728152922, -0.001266921998658053, -0.007122790428060381, -0.012871021717463436, -0.017852189458389456, -0.021403262319433757, -0.022918110896739993, -0.021906440359153793, -0.018045605353792606, -0.011220225882222989, -0.001545481108326266, 0.010628660576177286, 0.024733344647961189, 0.040016116357312823, 0.055593053292742431, 0.070513617769391357, 0.083832869405100041, 0.094684919293335654, 0.102351302009811070, 0.106318317517167070, 0.106318317517167070, 0.102351302009811070, 0.094684919293335654, 0.083832869405100041, 0.070513617769391357, 0.055593053292742431, 0.040016116357312823, 0.024733344647961189, 0.010628660576177286, -0.001545481108326266, -0.011220225882222989, -0.018045605353792606, -0.021906440359153793, -0.022918110896739993, -0.021403262319433757, -0.017852189458389456, -0.012871021717463436, -0.007122790428060381, -0.001266921998658053, 0.004097368728152922, 0.008478886219133458, 0.011529579182106710, 0.013064440018490608, 0.013065169962452085, 0.011668164700843125, 0.009138830213137229, 0.005835432981396591, 0.002166532839260334, -0.001453545516455117, -0.004646780506669336, -0.007107110348255605, -0.008626557809676316, -0.009109805876143171, -0.008576455016121923, -0.007151459446961864, -0.005045394324250144, -0.002527142979701336, 0.000107781839820803, 0.002569791244804701, 0.004605255832862724, 0.006021062146242219, 0.006701450960612391, 0.006615805917154524, 0.005817070614785085, 0.004431457793095885, 0.002640990158453115, 0.000661081413588171, -0.001284225000364678, -0.002986628326221043, -0.004274996752467488, -0.005031731058566960, -0.005202582868054837, -0.004799215003224437, -0.003894589690524808, -0.002612032761559656, -0.001109448711112102, 0.000439388406465501, 0.001864327522378759, 0.003016991173328030, 0.003785703607610913, 0.004105749968228098, 0.003964087731928019, 0.003398266860636230, 0.002489950284201132, 0.001353984612741832, 0.000124409621994965, -0.001060944493273319, -0.002075543578763564, -0.002817308401190046, -0.003218513620108414, -0.003251510669015779, -0.002929849705482365, -0.002304891424791415, -0.001458485408297803, -0.000492687418387142, 0.000482234298234895, 0.001360126142354939, 0.002050261072858978, 0.002486455189532861, 0.002633104169545422, 0.002487627013869813, 0.002079218519234449, 0.001464215661002276, 0.000718736847294852, -0.000070480695977658, -0.000815971265919441, -0.001439048979367570, -0.001877924713394541, -0.002093612886275790, -0.002073092512801241, -0.001829507546348522, -0.001399522686014101, -0.000838254589610985, -0.000212443049446438, 0.000407316271842430, 0.000954389812320343, 0.001373126810656710, 0.001624356624161237, 0.001688844037687690, 0.001568419571371085, 0.001284780403728217, 0.000876197024190483, 0.000392587860975165, -0.000110428182918688, -0.000577807284515617, -0.000960990590585683, -0.001222824367769252, -0.001341010390430392, -0.001309782074955667, -0.001139717153414092, -0.000855794020410478, -0.000493996123025552, -0.000096894708513463, 0.000291251466919408, 0.000629337435771274, 0.000883666665500652, 0.001031195280476629, 0.001061465563886132, 0.000977090407652497, 0.000792807201162301, 0.000533282556646377, 0.000229962373724818, -0.000082637093413831, -0.000370777976208385, -0.000605059771056946, -0.000763333939111765, -0.000832681816046785, -0.000810309677712974, -0.000703310824877695, -0.000527388822625111, -0.000304731538051063, -0.000061311579103233, 0.000176071280391891, 0.000382670778203303, 0.000538304340843976, 0.000629236561431697, 0.000649282295414473, 0.000600045160004744, 0.000490329017689163, 0.000334813551887072, 0.000152196470731637, -0.000036988477009561, -0.000212619491029857, -0.000357064175200153, -0.000456879139659229, -0.000503976472887228, -0.000496163931220179, -0.000437048860128537, -0.000335341513050654, -0.000203679685243764, -0.000057113100623293, 0.000088560889198400, 0.000218451713387220, 0.000320026589486952, 0.000384244892423745, 0.000406270345323467, 0.000385716174095538, 0.000326439472488279, 0.000235923038322712, 0.000124342943768293, 0.000003439467944363, -0.000114696259371792, -0.000218781210350266, -0.000299346594446952, -0.000349492174517184, -0.000365357958551737, -0.000346261198238618, -0.000294538502564660, -0.000215124321927526, -0.000114915331771079, -0.000002037964985788, 0.000114956874548630, 0.000227844055373822, 0.000329374266276144, 0.000413779420856055, 0.000477091889474874, 0.000517270879752382, 0.000534142706869689, 0.000529201721306850, 0.000505276256945394, 0.000466131771574125, 0.000416062388387887, 0.000359433330154281, 0.000300399529662751, 0.000242545741476270, 0.000188738905083740, 0.000141025873402660, 0.000100627030615644, 0.000067985064859609, 0.000042904801446151, 0.000024702874344864, 0.000012387135981227, 0.000004819206934844, 0.000000895178754483, -0.000004331430434813], 800: # 576 taps [ 0.000007812421315026, 0.000008939491599758, 0.000013730623424634, 0.000019922294330328, 0.000027648080357536, 0.000037033583075960, 0.000048143861498476, 0.000060975611534136, 0.000075478577997365, 0.000091486545323856, 0.000108759338791293, 0.000126959389238696, 0.000145652693573148, 0.000164310512299333, 0.000182322037177544, 0.000198999590569024, 0.000213614009898736, 0.000225404773677130, 0.000233610866318186, 0.000237501949870309, 0.000236413452609260, 0.000229779689874953, 0.000217172712546861, 0.000198326327006374, 0.000173169245803356, 0.000141846034715806, 0.000104732554871058, 0.000062442756567725, 0.000015827588463025, -0.000034041343381570, -0.000085892061029301, -0.000138290085401831, -0.000189681915226441, -0.000238447248218383, -0.000282958234132596, -0.000321645514236948, -0.000353063703221184, -0.000375960779331289, -0.000389338959490572, -0.000392510765617404, -0.000385145111580360, -0.000367301005108244, -0.000339445383884735, -0.000302456824898826, -0.000257608154338197, -0.000206533574886596, -0.000151176196094362, -0.000093718946756075, -0.000036501336346782, 0.000018073847262639, 0.000067643276268719, 0.000109986899426513, 0.000143132709269975, 0.000165454349492432, 0.000175757544777044, 0.000173350787020117, 0.000158097036687462, 0.000130440616590328, 0.000091410233747216, 0.000042593436932362, -0.000013915345466225, -0.000075592647414163, -0.000139587283955501, -0.000202842130917589, -0.000262229388149273, -0.000314696298480236, -0.000357412309140960, -0.000387912413334777, -0.000404229097174175, -0.000405005829251745, -0.000389585053939050, -0.000358067160688509, -0.000311334118688652, -0.000251037234855322, -0.000179546871425107, -0.000099865220473760, -0.000015504805729649, 0.000069662241126261, 0.000151579558482804, 0.000226197017031803, 0.000289669081062027, 0.000338550686637535, 0.000369981142430884, 0.000381846581094768, 0.000372912653196213, 0.000342918280693206, 0.000292625889758754, 0.000223822598023746, 0.000139271063990380, 0.000042610318846710, -0.000061790478444653, -0.000169020516263524, -0.000273849135305279, -0.000370972701089329, -0.000455274194431906, -0.000522083581325246, -0.000567425902673365, -0.000588244271105343, -0.000582585214321533, -0.000549736803809912, -0.000490309633189676, -0.000406255267998045, -0.000300818490773199, -0.000178423294758992, -0.000044495794702522, 0.000094768978920233, 0.000232687846388931, 0.000362404482394644, 0.000477224887882656, 0.000570957019366285, 0.000638237711550962, 0.000674829917199715, 0.000677874702997924, 0.000646082835685789, 0.000579855135491155, 0.000481322426719260, 0.000354300348814663, 0.000204158180969291, 0.000037605243749942, -0.000137597792476766, -0.000312990053930070, -0.000479809451013147, -0.000629420667419594, -0.000753751787384093, -0.000845717937205157, -0.000899610318070534, -0.000911429428339170, -0.000879144467901314, -0.000802862554846735, -0.000684896491503848, -0.000529724099269400, -0.000343837417747543, -0.000135485422990712, 0.000085680046384777, 0.000309041306180360, 0.000523514975880865, 0.000718092538346410, 0.000882395437488790, 0.001007217243930078, 0.001085025011663583, 0.001110393602574907, 0.001080348246990215, 0.000994595533680270, 0.000855627164276610, 0.000668686966519433, 0.000441598292681654, 0.000184456030731509, -0.000090806124488888, -0.000370954941565034, -0.000642080313861205, -0.000890272488296022, -0.001102321495571061, -0.001266404272056495, -0.001372724600470066, -0.001414071700002426, -0.001386267150663963, -0.001288473577308051, -0.001123345195626614, -0.000897007516317755, -0.000618861629989936, -0.000301217045862462, 0.000041233610152644, 0.000392077118279518, 0.000733950102097711, 0.001049382185659160, 0.001321671816520764, 0.001535751682495805, 0.001678999613916214, 0.001741952717366617, 0.001718885253761411, 0.001608217075415199, 0.001412726517149060, 0.001139550679396572, 0.000799966281315092, 0.000408955257020119, -0.000015430291445883, -0.000452877901224665, -0.000881764419386712, -0.001280202174740378, -0.001627132056108478, -0.001903410054728627, -0.002092832630669335, -0.002183047066222210, -0.002166297669634002, -0.002039964832379242, -0.001806863227100527, -0.001475276496367705, -0.001058718218567234, -0.000575422161543602, -0.000047579005659538, 0.000499650640507829, 0.001039304486976568, 0.001543915361236087, 0.001986875765177565, 0.002343803978935238, 0.002593843111794459, 0.002720826151891805, 0.002714244052422841, 0.002569962094668674, 0.002290640442950059, 0.001885828071941918, 0.001371714610702517, 0.000770541414234860, 0.000109689735095918, -0.000579518937674694, -0.001263260162418279, -0.001906817708604015, -0.002476294031416823, -0.002940338141748221, -0.003271805587759476, -0.003449265353836316, -0.003458273739088719, -0.003292343903957135, -0.002953552492773730, -0.002452740833751403, -0.001809286792967657, -0.001050443545598396, -0.000210263213371804, 0.000671856047428268, 0.001552940847463649, 0.002388454943494185, 0.003134462521134076, 0.003749841173565993, 0.004198437225205720, 0.004451055565195895, 0.004487180085620033, 0.004296330509189801, 0.003878975870600702, 0.003246943568337220, 0.002423285251527749, 0.001441585983790830, 0.000344729182561098, -0.000816843070689627, -0.001987309118898022, -0.003107997569512837, -0.004120159055022873, -0.004967855525593480, -0.005600832763225632, -0.005977237320460713, -0.006066041703895594, -0.005849050345318046, -0.005322373876566778, -0.004497280230451145, -0.003400356983323659, -0.002072948915619172, -0.000569867563016818, 0.001042597072372037, 0.002689299061586182, 0.004289398058621653, 0.005759936423629122, 0.007019685172079656, 0.007993094199877881, 0.008614171947670925, 0.008830116409127314, 0.008604524292277297, 0.007920018129346281, 0.006780151368661940, 0.005210478633443022, 0.003258711582163722, 0.000993917994210585, -0.001495237701498300, -0.004103172616953404, -0.006710901704621617, -0.009190272912439044, -0.011408767543032211, -0.013234683860549021, -0.014542500326924340, -0.015218201853231224, -0.015164348354310610, -0.014304669860257387, -0.012587987008943695, -0.009991279084291772, -0.006521752749437525, -0.002217802857491734, 0.002851200149507507, 0.008586315129089878, 0.014861597832277761, 0.021527754009268797, 0.028416755733892799, 0.035347257703852740, 0.042130616026199795, 0.048577285227121583, 0.054503351348228368, 0.059736951256086870, 0.064124330411942668, 0.067535303652784234, 0.069867905879939018, 0.071052050289491700, 0.071052050289491700, 0.069867905879939018, 0.067535303652784234, 0.064124330411942668, 0.059736951256086870, 0.054503351348228368, 0.048577285227121583, 0.042130616026199795, 0.035347257703852740, 0.028416755733892799, 0.021527754009268797, 0.014861597832277761, 0.008586315129089878, 0.002851200149507507, -0.002217802857491734, -0.006521752749437525, -0.009991279084291772, -0.012587987008943695, -0.014304669860257387, -0.015164348354310610, -0.015218201853231224, -0.014542500326924340, -0.013234683860549021, -0.011408767543032211, -0.009190272912439044, -0.006710901704621617, -0.004103172616953404, -0.001495237701498300, 0.000993917994210585, 0.003258711582163722, 0.005210478633443022, 0.006780151368661940, 0.007920018129346281, 0.008604524292277297, 0.008830116409127314, 0.008614171947670925, 0.007993094199877881, 0.007019685172079656, 0.005759936423629122, 0.004289398058621653, 0.002689299061586182, 0.001042597072372037, -0.000569867563016818, -0.002072948915619172, -0.003400356983323659, -0.004497280230451145, -0.005322373876566778, -0.005849050345318046, -0.006066041703895594, -0.005977237320460713, -0.005600832763225632, -0.004967855525593480, -0.004120159055022873, -0.003107997569512837, -0.001987309118898022, -0.000816843070689627, 0.000344729182561098, 0.001441585983790830, 0.002423285251527749, 0.003246943568337220, 0.003878975870600702, 0.004296330509189801, 0.004487180085620033, 0.004451055565195895, 0.004198437225205720, 0.003749841173565993, 0.003134462521134076, 0.002388454943494185, 0.001552940847463649, 0.000671856047428268, -0.000210263213371804, -0.001050443545598396, -0.001809286792967657, -0.002452740833751403, -0.002953552492773730, -0.003292343903957135, -0.003458273739088719, -0.003449265353836316, -0.003271805587759476, -0.002940338141748221, -0.002476294031416823, -0.001906817708604015, -0.001263260162418279, -0.000579518937674694, 0.000109689735095918, 0.000770541414234860, 0.001371714610702517, 0.001885828071941918, 0.002290640442950059, 0.002569962094668674, 0.002714244052422841, 0.002720826151891805, 0.002593843111794459, 0.002343803978935238, 0.001986875765177565, 0.001543915361236087, 0.001039304486976568, 0.000499650640507829, -0.000047579005659538, -0.000575422161543602, -0.001058718218567234, -0.001475276496367705, -0.001806863227100527, -0.002039964832379242, -0.002166297669634002, -0.002183047066222210, -0.002092832630669335, -0.001903410054728627, -0.001627132056108478, -0.001280202174740378, -0.000881764419386712, -0.000452877901224665, -0.000015430291445883, 0.000408955257020119, 0.000799966281315092, 0.001139550679396572, 0.001412726517149060, 0.001608217075415199, 0.001718885253761411, 0.001741952717366617, 0.001678999613916214, 0.001535751682495805, 0.001321671816520764, 0.001049382185659160, 0.000733950102097711, 0.000392077118279518, 0.000041233610152644, -0.000301217045862462, -0.000618861629989936, -0.000897007516317755, -0.001123345195626614, -0.001288473577308051, -0.001386267150663963, -0.001414071700002426, -0.001372724600470066, -0.001266404272056495, -0.001102321495571061, -0.000890272488296022, -0.000642080313861205, -0.000370954941565034, -0.000090806124488888, 0.000184456030731509, 0.000441598292681654, 0.000668686966519433, 0.000855627164276610, 0.000994595533680270, 0.001080348246990215, 0.001110393602574907, 0.001085025011663583, 0.001007217243930078, 0.000882395437488790, 0.000718092538346410, 0.000523514975880865, 0.000309041306180360, 0.000085680046384777, -0.000135485422990712, -0.000343837417747543, -0.000529724099269400, -0.000684896491503848, -0.000802862554846735, -0.000879144467901314, -0.000911429428339170, -0.000899610318070534, -0.000845717937205157, -0.000753751787384093, -0.000629420667419594, -0.000479809451013147, -0.000312990053930070, -0.000137597792476766, 0.000037605243749942, 0.000204158180969291, 0.000354300348814663, 0.000481322426719260, 0.000579855135491155, 0.000646082835685789, 0.000677874702997924, 0.000674829917199715, 0.000638237711550962, 0.000570957019366285, 0.000477224887882656, 0.000362404482394644, 0.000232687846388931, 0.000094768978920233, -0.000044495794702522, -0.000178423294758992, -0.000300818490773199, -0.000406255267998045, -0.000490309633189676, -0.000549736803809912, -0.000582585214321533, -0.000588244271105343, -0.000567425902673365, -0.000522083581325246, -0.000455274194431906, -0.000370972701089329, -0.000273849135305279, -0.000169020516263524, -0.000061790478444653, 0.000042610318846710, 0.000139271063990380, 0.000223822598023746, 0.000292625889758754, 0.000342918280693206, 0.000372912653196213, 0.000381846581094768, 0.000369981142430884, 0.000338550686637535, 0.000289669081062027, 0.000226197017031803, 0.000151579558482804, 0.000069662241126261, -0.000015504805729649, -0.000099865220473760, -0.000179546871425107, -0.000251037234855322, -0.000311334118688652, -0.000358067160688509, -0.000389585053939050, -0.000405005829251745, -0.000404229097174175, -0.000387912413334777, -0.000357412309140960, -0.000314696298480236, -0.000262229388149273, -0.000202842130917589, -0.000139587283955501, -0.000075592647414163, -0.000013915345466225, 0.000042593436932362, 0.000091410233747216, 0.000130440616590328, 0.000158097036687462, 0.000173350787020117, 0.000175757544777044, 0.000165454349492432, 0.000143132709269975, 0.000109986899426513, 0.000067643276268719, 0.000018073847262639, -0.000036501336346782, -0.000093718946756075, -0.000151176196094362, -0.000206533574886596, -0.000257608154338197, -0.000302456824898826, -0.000339445383884735, -0.000367301005108244, -0.000385145111580360, -0.000392510765617404, -0.000389338959490572, -0.000375960779331289, -0.000353063703221184, -0.000321645514236948, -0.000282958234132596, -0.000238447248218383, -0.000189681915226441, -0.000138290085401831, -0.000085892061029301, -0.000034041343381570, 0.000015827588463025, 0.000062442756567725, 0.000104732554871058, 0.000141846034715806, 0.000173169245803356, 0.000198326327006374, 0.000217172712546861, 0.000229779689874953, 0.000236413452609260, 0.000237501949870309, 0.000233610866318186, 0.000225404773677130, 0.000213614009898736, 0.000198999590569024, 0.000182322037177544, 0.000164310512299333, 0.000145652693573148, 0.000126959389238696, 0.000108759338791293, 0.000091486545323856, 0.000075478577997365, 0.000060975611534136, 0.000048143861498476, 0.000037033583075960, 0.000027648080357536, 0.000019922294330328, 0.000013730623424634, 0.000008939491599758, 0.000007812421315026], 400: # Shape 1.3, 770 taps [ 0.000006365988874769, 0.000003794338487480, 0.000004876278267121, 0.000006131564967683, 0.000007569854655698, 0.000009199819153557, 0.000011019782182642, 0.000013040101237056, 0.000015265995566942, 0.000017696391039940, 0.000020312791765427, 0.000023135950087517, 0.000026132051354026, 0.000029299266022519, 0.000032613010658575, 0.000036050466832082, 0.000039588439426462, 0.000043195256918759, 0.000046833693036583, 0.000050464843382682, 0.000054046630064787, 0.000057526210900478, 0.000060855931076401, 0.000063977534092402, 0.000066834004766232, 0.000069367495918698, 0.000071512066722409, 0.000073206600728293, 0.000074384990732719, 0.000074985154083054, 0.000074941358848070, 0.000074196098488127, 0.000072687036065854, 0.000070364017870395, 0.000067174711830892, 0.000063076338216280, 0.000058031241355323, 0.000052010623717769, 0.000044992453647518, 0.000036966078084084, 0.000027928525061234, 0.000017889642287636, 0.000006870052370296, -0.000005097430373119, -0.000017968467835226, -0.000031683467914261, -0.000046174009079182, -0.000061354520788796, -0.000077131717460578, -0.000093396057473154, -0.000110030073586572, -0.000126901644954483, -0.000143873358110243, -0.000160793959726774, -0.000177509258936783, -0.000193855013323854, -0.000209665383215103, -0.000224769517767120, -0.000238997508310048, -0.000252178063434561, -0.000264145812850823, -0.000274737753978821, -0.000283800555901376, -0.000291188041391623, -0.000296767743750952, -0.000300418295008671, -0.000302037282504393, -0.000301535929224389, -0.000298849141904324, -0.000293929053180242, -0.000286753991998278, -0.000277322604938755, -0.000265661916507038, -0.000251820837747345, -0.000235878209412169, -0.000217935329921142, -0.000198122592158803, -0.000176593305324287, -0.000153527761718214, -0.000129127285942292, -0.000103617728527825, -0.000077242169252941, -0.000050264484742360, -0.000022961141775614, 0.000004376321843836, 0.000031449535456591, 0.000057950921452100, 0.000083573577884305, 0.000108007974814302, 0.000130953051335089, 0.000152112926634605, 0.000171207503556438, 0.000187970143706098, 0.000202157681598790, 0.000213547707697876, 0.000221948537710715, 0.000227196325735486, 0.000229163803316040, 0.000227757838181676, 0.000222926398781727, 0.000214655798042235, 0.000202977177552243, 0.000187962083392261, 0.000169728357656893, 0.000148434669356957, 0.000124285090373991, 0.000097522588191792, 0.000068432637827430, 0.000037334851940437, 0.000004586327504349, -0.000029428168903046, -0.000064294238370152, -0.000099577998322800, -0.000134825630330724, -0.000169573965195115, -0.000203350785393334, -0.000235686105255552, -0.000266113076153881, -0.000294178911934326, -0.000319446762108148, -0.000341506152453346, -0.000359974720676106, -0.000374508618833672, -0.000384803219892303, -0.000390603203520662, -0.000391702472886875, -0.000387952968439801, -0.000379263512998934, -0.000365607622249019, -0.000347020514221526, -0.000323605716996244, -0.000295530392174600, -0.000263029891857937, -0.000226402015568579, -0.000186009246146028, -0.000142271402525828, -0.000095666125277552, -0.000046719850734115, 0.000003993583197103, 0.000055863130913344, 0.000108243891748510, 0.000160468312893279, 0.000211850586288707, 0.000261699269396572, 0.000309322128759128, 0.000354039461924243, 0.000395189349018748, 0.000432140920160531, 0.000464299583558709, 0.000491120046640221, 0.000512110607671310, 0.000526845446928034, 0.000534967981519684, 0.000536201343488612, 0.000530350597696912, 0.000517311013160068, 0.000497068439035188, 0.000469705445435111, 0.000435399334882175, 0.000394425628337960, 0.000347153886365670, 0.000294048338105669, 0.000235661140309264, 0.000172630559665850, 0.000105671355374271, 0.000035570791815593, -0.000036823410279226, -0.000110609450083053, -0.000184845354264341, -0.000258557173028134, -0.000330754528114594, -0.000400439970264790, -0.000466625524492906, -0.000528342888003039, -0.000584659866982658, -0.000634690947746067, -0.000677613119135274, -0.000712675673752122, -0.000739214923907549, -0.000756662495413132, -0.000764558104223763, -0.000762555872583250, -0.000750434429795932, -0.000728100396603541, -0.000695595696462148, -0.000653097503960073, -0.000600922257516729, -0.000539522021491309, -0.000469484695604341, -0.000391526816237233, -0.000306489974421006, -0.000215329834691466, -0.000119109058134576, -0.000018982981184245, 0.000083810915235651, 0.000187970000243908, 0.000292139959571129, 0.000394933986966016, 0.000494948142664746, 0.000590782205985295, 0.000681056090464857, 0.000764431197740454, 0.000839627050452169, 0.000905442225580665, 0.000960769995583447, 0.001004618039369409, 0.001036121906273736, 0.001054562391583931, 0.001059376177251162, 0.001050169688173629, 0.001026726061735900, 0.000989014843850052, 0.000937194466007411, 0.000871617237374737, 0.000792826925935815, 0.000701558421554040, 0.000598730377991698, 0.000485439514972828, 0.000362948081805026, 0.000232673195056634, 0.000096169337651215, -0.000044886850392886, -0.000188718302856941, -0.000333466707544108, -0.000477217660879214, -0.000618022612530573, -0.000753926550301084, -0.000882991568244702, -0.001003325671471952, -0.001113106854174517, -0.001210611462788910, -0.001294237402501427, -0.001362530796885569, -0.001414206728098591, -0.001448172776524704, -0.001463546100508022, -0.001459672417038066, -0.001436138251655395, -0.001392784297634421, -0.001329711615112041, -0.001247288727402393, -0.001146150989584800, -0.001027200706007495, -0.000891599407168167, -0.000740760728594229, -0.000576335492878354, -0.000400197621159931, -0.000214422239224392, -0.000021265147290331, 0.000176865113062629, 0.000377433546776307, 0.000577811529416548, 0.000775307530646278, 0.000967203529925253, 0.001150788527481832, 0.001323396897145278, 0.001482443038707630, 0.001625459660097671, 0.001750131670233381, 0.001854332615855901, 0.001936155690016456, 0.001993946486300650, 0.002026329220986863, 0.002032233882826800, 0.002010916100718580, 0.001961977029179007, 0.001885375282542786, 0.001781438385022068, 0.001650865633292049, 0.001494730107495952, 0.001314471906401099, 0.001111890114781271, 0.000889126269781853, 0.000648646430391355, 0.000393215009447102, 0.000125867561738431, -0.000150124130738416, -0.000431287566747790, -0.000713991806927365, -0.000994489713483095, -0.001268965941124358, -0.001533583756312415, -0.001784536663195940, -0.002018097583665120, -0.002230671541941067, -0.002418844734804261, -0.002579435657364371, -0.002709541359817244, -0.002806584464746950, -0.002868353953987823, -0.002893045404115256, -0.002879294007683593, -0.002826205616681453, -0.002733379783299579, -0.002600929724527880, -0.002429493528198460, -0.002220241603361130, -0.001974874872112559, -0.001695618645272131, -0.001385207220497454, -0.001046863974406666, -0.000684272287342287, -0.000301542320981976, 0.000096831014522634, 0.000506013584333645, 0.000920885468043068, 0.001336097138497067, 0.001746132300635148, 0.002145372272540894, 0.002528165649885475, 0.002888898066467300, 0.003222065542166644, 0.003522346486582096, 0.003784675282650529, 0.004004312987512708, 0.004176917749158860, 0.004298610545483354, 0.004366038868235595, 0.004376434088990949, 0.004327664995106265, 0.004218283602051056, 0.004047565581181025, 0.003815541611827637, 0.003523022274162837, 0.003171612798693589, 0.002763720451889364, 0.002302551278585364, 0.001792098861036779, 0.001237122342212990, 0.000643116381836866, 0.000016270569630469, -0.000636578845765101, -0.001308006968347628, -0.001990065317450888, -0.002674355367539247, -0.003352107995747014, -0.004014269925046706, -0.004651594401548673, -0.005254737118938589, -0.005814354519325696, -0.006321205162109337, -0.006766251436254966, -0.007140762118819473, -0.007436412979114623, -0.007645386018101693, -0.007760464454403432, -0.007775124017275518, -0.007683617984862557, -0.007481056258606499, -0.007163476264301046, -0.006727906019989577, -0.006172417333684170, -0.005496169589494688, -0.004699442443010971, -0.003783657807377434, -0.002751390001364686, -0.001606364515685684, -0.000353444465756940, 0.001001394411574224, 0.002451100972703334, 0.003987597007902468, 0.005601837062643716, 0.007283878572786960, 0.009022962344277727, 0.010807601882596756, 0.012625681525580169, 0.014464561665273282, 0.016311190660485246, 0.018152221825464991, 0.019974134681837181, 0.021763358913199277, 0.023506400111173612, 0.025189965611159389, 0.026801089460580949, 0.028327254981021979, 0.029756513765852269, 0.031077599771363505, 0.032280037413131318, 0.033354242302380432, 0.034291613871121174, 0.035084618575605728, 0.035726863022388727, 0.036213156095256299, 0.036539559528566301, 0.036703426247133436, 0.036703426247133436, 0.036539559528566301, 0.036213156095256299, 0.035726863022388727, 0.035084618575605728, 0.034291613871121174, 0.033354242302380432, 0.032280037413131318, 0.031077599771363505, 0.029756513765852269, 0.028327254981021979, 0.026801089460580949, 0.025189965611159389, 0.023506400111173612, 0.021763358913199277, 0.019974134681837181, 0.018152221825464991, 0.016311190660485246, 0.014464561665273282, 0.012625681525580169, 0.010807601882596756, 0.009022962344277727, 0.007283878572786960, 0.005601837062643716, 0.003987597007902468, 0.002451100972703334, 0.001001394411574224, -0.000353444465756940, -0.001606364515685684, -0.002751390001364686, -0.003783657807377434, -0.004699442443010971, -0.005496169589494688, -0.006172417333684170, -0.006727906019989577, -0.007163476264301046, -0.007481056258606499, -0.007683617984862557, -0.007775124017275518, -0.007760464454403432, -0.007645386018101693, -0.007436412979114623, -0.007140762118819473, -0.006766251436254966, -0.006321205162109337, -0.005814354519325696, -0.005254737118938589, -0.004651594401548673, -0.004014269925046706, -0.003352107995747014, -0.002674355367539247, -0.001990065317450888, -0.001308006968347628, -0.000636578845765101, 0.000016270569630469, 0.000643116381836866, 0.001237122342212990, 0.001792098861036779, 0.002302551278585364, 0.002763720451889364, 0.003171612798693589, 0.003523022274162837, 0.003815541611827637, 0.004047565581181025, 0.004218283602051056, 0.004327664995106265, 0.004376434088990949, 0.004366038868235595, 0.004298610545483354, 0.004176917749158860, 0.004004312987512708, 0.003784675282650529, 0.003522346486582096, 0.003222065542166644, 0.002888898066467300, 0.002528165649885475, 0.002145372272540894, 0.001746132300635148, 0.001336097138497067, 0.000920885468043068, 0.000506013584333645, 0.000096831014522634, -0.000301542320981976, -0.000684272287342287, -0.001046863974406666, -0.001385207220497454, -0.001695618645272131, -0.001974874872112559, -0.002220241603361130, -0.002429493528198460, -0.002600929724527880, -0.002733379783299579, -0.002826205616681453, -0.002879294007683593, -0.002893045404115256, -0.002868353953987823, -0.002806584464746950, -0.002709541359817244, -0.002579435657364371, -0.002418844734804261, -0.002230671541941067, -0.002018097583665120, -0.001784536663195940, -0.001533583756312415, -0.001268965941124358, -0.000994489713483095, -0.000713991806927365, -0.000431287566747790, -0.000150124130738416, 0.000125867561738431, 0.000393215009447102, 0.000648646430391355, 0.000889126269781853, 0.001111890114781271, 0.001314471906401099, 0.001494730107495952, 0.001650865633292049, 0.001781438385022068, 0.001885375282542786, 0.001961977029179007, 0.002010916100718580, 0.002032233882826800, 0.002026329220986863, 0.001993946486300650, 0.001936155690016456, 0.001854332615855901, 0.001750131670233381, 0.001625459660097671, 0.001482443038707630, 0.001323396897145278, 0.001150788527481832, 0.000967203529925253, 0.000775307530646278, 0.000577811529416548, 0.000377433546776307, 0.000176865113062629, -0.000021265147290331, -0.000214422239224392, -0.000400197621159931, -0.000576335492878354, -0.000740760728594229, -0.000891599407168167, -0.001027200706007495, -0.001146150989584800, -0.001247288727402393, -0.001329711615112041, -0.001392784297634421, -0.001436138251655395, -0.001459672417038066, -0.001463546100508022, -0.001448172776524704, -0.001414206728098591, -0.001362530796885569, -0.001294237402501427, -0.001210611462788910, -0.001113106854174517, -0.001003325671471952, -0.000882991568244702, -0.000753926550301084, -0.000618022612530573, -0.000477217660879214, -0.000333466707544108, -0.000188718302856941, -0.000044886850392886, 0.000096169337651215, 0.000232673195056634, 0.000362948081805026, 0.000485439514972828, 0.000598730377991698, 0.000701558421554040, 0.000792826925935815, 0.000871617237374737, 0.000937194466007411, 0.000989014843850052, 0.001026726061735900, 0.001050169688173629, 0.001059376177251162, 0.001054562391583931, 0.001036121906273736, 0.001004618039369409, 0.000960769995583447, 0.000905442225580665, 0.000839627050452169, 0.000764431197740454, 0.000681056090464857, 0.000590782205985295, 0.000494948142664746, 0.000394933986966016, 0.000292139959571129, 0.000187970000243908, 0.000083810915235651, -0.000018982981184245, -0.000119109058134576, -0.000215329834691466, -0.000306489974421006, -0.000391526816237233, -0.000469484695604341, -0.000539522021491309, -0.000600922257516729, -0.000653097503960073, -0.000695595696462148, -0.000728100396603541, -0.000750434429795932, -0.000762555872583250, -0.000764558104223763, -0.000756662495413132, -0.000739214923907549, -0.000712675673752122, -0.000677613119135274, -0.000634690947746067, -0.000584659866982658, -0.000528342888003039, -0.000466625524492906, -0.000400439970264790, -0.000330754528114594, -0.000258557173028134, -0.000184845354264341, -0.000110609450083053, -0.000036823410279226, 0.000035570791815593, 0.000105671355374271, 0.000172630559665850, 0.000235661140309264, 0.000294048338105669, 0.000347153886365670, 0.000394425628337960, 0.000435399334882175, 0.000469705445435111, 0.000497068439035188, 0.000517311013160068, 0.000530350597696912, 0.000536201343488612, 0.000534967981519684, 0.000526845446928034, 0.000512110607671310, 0.000491120046640221, 0.000464299583558709, 0.000432140920160531, 0.000395189349018748, 0.000354039461924243, 0.000309322128759128, 0.000261699269396572, 0.000211850586288707, 0.000160468312893279, 0.000108243891748510, 0.000055863130913344, 0.000003993583197103, -0.000046719850734115, -0.000095666125277552, -0.000142271402525828, -0.000186009246146028, -0.000226402015568579, -0.000263029891857937, -0.000295530392174600, -0.000323605716996244, -0.000347020514221526, -0.000365607622249019, -0.000379263512998934, -0.000387952968439801, -0.000391702472886875, -0.000390603203520662, -0.000384803219892303, -0.000374508618833672, -0.000359974720676106, -0.000341506152453346, -0.000319446762108148, -0.000294178911934326, -0.000266113076153881, -0.000235686105255552, -0.000203350785393334, -0.000169573965195115, -0.000134825630330724, -0.000099577998322800, -0.000064294238370152, -0.000029428168903046, 0.000004586327504349, 0.000037334851940437, 0.000068432637827430, 0.000097522588191792, 0.000124285090373991, 0.000148434669356957, 0.000169728357656893, 0.000187962083392261, 0.000202977177552243, 0.000214655798042235, 0.000222926398781727, 0.000227757838181676, 0.000229163803316040, 0.000227196325735486, 0.000221948537710715, 0.000213547707697876, 0.000202157681598790, 0.000187970143706098, 0.000171207503556438, 0.000152112926634605, 0.000130953051335089, 0.000108007974814302, 0.000083573577884305, 0.000057950921452100, 0.000031449535456591, 0.000004376321843836, -0.000022961141775614, -0.000050264484742360, -0.000077242169252941, -0.000103617728527825, -0.000129127285942292, -0.000153527761718214, -0.000176593305324287, -0.000198122592158803, -0.000217935329921142, -0.000235878209412169, -0.000251820837747345, -0.000265661916507038, -0.000277322604938755, -0.000286753991998278, -0.000293929053180242, -0.000298849141904324, -0.000301535929224389, -0.000302037282504393, -0.000300418295008671, -0.000296767743750952, -0.000291188041391623, -0.000283800555901376, -0.000274737753978821, -0.000264145812850823, -0.000252178063434561, -0.000238997508310048, -0.000224769517767120, -0.000209665383215103, -0.000193855013323854, -0.000177509258936783, -0.000160793959726774, -0.000143873358110243, -0.000126901644954483, -0.000110030073586572, -0.000093396057473154, -0.000077131717460578, -0.000061354520788796, -0.000046174009079182, -0.000031683467914261, -0.000017968467835226, -0.000005097430373119, 0.000006870052370296, 0.000017889642287636, 0.000027928525061234, 0.000036966078084084, 0.000044992453647518, 0.000052010623717769, 0.000058031241355323, 0.000063076338216280, 0.000067174711830892, 0.000070364017870395, 0.000072687036065854, 0.000074196098488127, 0.000074941358848070, 0.000074985154083054, 0.000074384990732719, 0.000073206600728293, 0.000071512066722409, 0.000069367495918698, 0.000066834004766232, 0.000063977534092402, 0.000060855931076401, 0.000057526210900478, 0.000054046630064787, 0.000050464843382682, 0.000046833693036583, 0.000043195256918759, 0.000039588439426462, 0.000036050466832082, 0.000032613010658575, 0.000029299266022519, 0.000026132051354026, 0.000023135950087517, 0.000020312791765427, 0.000017696391039940, 0.000015265995566942, 0.000013040101237056, 0.000011019782182642, 0.000009199819153557, 0.000007569854655698, 0.000006131564967683, 0.000004876278267121, 0.000003794338487480, 0.000006365988874769], } quisk-3.6.11/quisk_widgets.py0000666000175000017500000006640012155355550015572 0ustar jimjim00000000000000# These are Quisk widgets import sys, re import wx, wx.lib.buttons, wx.lib.stattext from types import * # The main script will alter quisk_conf_defaults to include the user's config file. import quisk_conf_defaults as conf def FreqFormatter(freq): # Format the string or integer frequency by adding blanks freq = int(freq) if freq >= 0: t = str(freq) minus = '' else: t = str(-freq) minus = '- ' l = len(t) if l > 9: txt = "%s%s %s %s %s" % (minus, t[0:-9], t[-9:-6], t[-6:-3], t[-3:]) elif l > 6: txt = "%s%s %s %s" % (minus, t[0:-6], t[-6:-3], t[-3:]) elif l > 3: txt = "%s%s %s" % (minus, t[0:-3], t[-3:]) else: txt = minus + t return txt class FrequencyDisplay(wx.lib.stattext.GenStaticText): """Create a frequency display widget.""" def __init__(self, frame, width, height): wx.lib.stattext.GenStaticText.__init__(self, frame, -1, '3', style=wx.ALIGN_CENTER|wx.ST_NO_AUTORESIZE) border = 4 for points in range(30, 6, -1): font = wx.Font(points, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(font) w, h = self.GetTextExtent('333 444 555 Hz') if w < width and h < height - border * 2: break self.SetSizeHints(w, h, w * 5, h) self.height = h self.points = points border = self.border = (height - self.height) / 2 self.height_and_border = h + border * 2 self.SetBackgroundColour(conf.color_freq) self.SetForegroundColour(conf.color_freq_txt) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) # Click on a digit changes the frequency self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.timer = wx.Timer(self) # Holding a digit continuously changes the frequency self.Bind(wx.EVT_TIMER, self.OnTimer) self.repeat_time = 0 # Repeat function is inactive def Clip(self, clip): """Change color to indicate clipping.""" if clip: self.SetBackgroundColour('deep pink') else: self.SetBackgroundColour(conf.color_freq) self.Refresh() def Display(self, freq): """Set the frequency to be displayed.""" txt = FreqFormatter(freq) self.SetLabel('%s Hz' % txt) def OnLeftDown(self, event): # Click on a digit changes the frequency if self.repeat_time: self.timer.Stop() self.repeat_time = 0 mouse_x, mouse_y = event.GetPosition() width, height = self.GetClientSizeTuple() if mouse_y < height / 2: self.increase = True else: self.increase = False text = self.GetLabel() tw, th = self.GetTextExtent(text) edge = (width - tw) / 2 digit = self.GetTextExtent('0')[0] blank = self.GetTextExtent(' ')[0] if mouse_x < edge - digit: return x = width - edge - self.GetTextExtent(" Hz")[0] - mouse_x if x < 0: return #print ('size', width, height, 'mouse', mouse_x, mouse_y, 'digit', digit, 'blank', blank) shift = 0 while x > digit * 3: shift += 1 x -= digit * 3 + blank if x < 0: return self.index = x / digit + shift * 3 # index of digit being changed self.ChangeFreq() self.repeat_time = 300 # first button push self.timer.Start(milliseconds=300, oneShot=True) def OnLeftUp(self, event): self.timer.Stop() self.repeat_time = 0 def ChangeFreq(self): text = self.GetLabel() text = text.replace(' ', '')[:-2] text = text[:len(text)-self.index] + '0' * self.index if self.increase: freq = int(text) + 10 ** self.index else: freq = int(text) - 10 ** self.index if freq <= 0 and self.index > 0: freq = 10 ** (self.index - 1) #print ('X', x, 'N', n, text, 'freq', freq) application.ChangeRxTxFrequency(None, freq) def OnTimer(self, event): if self.repeat_time == 300: # after first push, turn on repeats self.repeat_time = 150 elif self.repeat_time > 20: self.repeat_time -= 5 self.ChangeFreq() self.timer.Start(milliseconds=self.repeat_time, oneShot=True) class SliderBoxH: """A horizontal control with a slider and text with a value. The text must have a %d if display is True.""" def __init__(self, parent, text, init, themin, themax, handler, display, pos, width): self.text = text self.handler = handler self.display = display if display: # Display the slider value t1 = self.text % themin t2 = self.text % themax if len(t1) > len(t2): # set text size to the largest t = t1 else: t = t2 else: t = self.text if pos is None: self.text_ctrl = wx.StaticText(parent, -1, t, style=wx.ST_NO_AUTORESIZE) w2, h2 = self.text_ctrl.GetSize() self.text_ctrl.SetSizeHints(w2, -1, w2) self.slider = wx.Slider(parent, -1, init, themin, themax) else: self.text_ctrl = wx.StaticText(parent, -1, t, pos=pos) w2, h2 = self.text_ctrl.GetSize() self.slider = wx.Slider(parent, -1, init, themin, themax, (pos[0] + w2, pos[1]), (width - w2, h2)) self.slider.Bind(wx.EVT_SCROLL, self.OnScroll) self.OnScroll() def OnScroll(self, event=None): if event: event.Skip() if self.handler: self.handler(event) if self.display: t = self.text % self.slider.GetValue() else: t = self.text self.text_ctrl.SetLabel(t) def GetValue(self): return self.slider.GetValue() def SetValue(self, value): # Set slider visual position; does not call handler self.slider.SetValue(value) self.OnScroll() class SliderBoxHH(SliderBoxH, wx.BoxSizer): """A horizontal control with a slider and text with a value. The text must have a %d if display is True.""" def __init__(self, parent, text, init, themin, themax, handler, display): wx.BoxSizer.__init__(self, wx.HORIZONTAL) SliderBoxH.__init__(self, parent, text, init, themin, themax, handler, display, None, None) #font = wx.Font(10, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) #self.text_ctrl.SetFont(font) self.Add(self.text_ctrl, 0, wx.ALIGN_CENTER) self.Add(self.slider, 1, wx.ALIGN_CENTER) class SliderBoxV(wx.BoxSizer): """A vertical box containing a slider and a text heading""" # Note: A vertical wx slider has the max value at the bottom. This is # reversed for this control. def __init__(self, parent, text, init, themax, handler, display=False): wx.BoxSizer.__init__(self, wx.VERTICAL) self.slider = wx.Slider(parent, -1, init, 0, themax, style=wx.SL_VERTICAL) self.slider.Bind(wx.EVT_SCROLL, handler) sw, sh = self.slider.GetSize() self.text = text self.themax = themax if display: # Display the slider value when it is thumb'd self.text_ctrl = wx.StaticText(parent, -1, str(themax), style=wx.ALIGN_CENTER) w1, h1 = self.text_ctrl.GetSize() # Measure size with max number self.text_ctrl.SetLabel(text) w2, h2 = self.text_ctrl.GetSize() # Measure size with text self.width = max(w1, w2, sw) self.text_ctrl.SetSizeHints(self.width, -1, self.width) self.slider.Bind(wx.EVT_SCROLL_THUMBTRACK, self.Change) self.slider.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.ChangeDone) else: self.text_ctrl = wx.StaticText(parent, -1, text) w2, h2 = self.text_ctrl.GetSize() # Measure size with text self.width = max(w2, sw) self.Add(self.text_ctrl, 0, wx.ALIGN_CENTER) self.Add(self.slider, 1, wx.ALIGN_CENTER) def Change(self, event): event.Skip() self.text_ctrl.SetLabel(str(self.themax - self.slider.GetValue())) def ChangeDone(self, event): event.Skip() self.text_ctrl.SetLabel(self.text) def GetValue(self): return self.themax - self.slider.GetValue() def SetValue(self, value): # Set slider visual position; does not call handler self.slider.SetValue(self.themax - value) class _QuiskText1(wx.lib.stattext.GenStaticText): # Self-drawn text for QuiskText. def __init__(self, parent, size_text, height, style, fixed): wx.lib.stattext.GenStaticText.__init__(self, parent, -1, '', pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.ST_NO_AUTORESIZE|style, name = "QuiskText1") self.fixed = fixed self.size_text = size_text self.pen = wx.Pen(conf.color_btn, 2) self.brush = wx.Brush(conf.color_freq) self.SetSizeHints(-1, height, -1, height) def _MeasureFont(self, dc, width, height): # Set decreasing point size until size_text fits in the space available for points in range(20, 6, -1): if self.fixed: font = wx.Font(points, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) else: font = wx.Font(points, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) dc.SetFont(font) w, h = dc.GetTextExtent(self.size_text) if w < width and h < height: break self.size_text = '' self.SetFont(font) def OnPaint(self, event): dc = wx.PaintDC(self) width, height = self.GetClientSize() if not width or not height: return dc.SetPen(self.pen) dc.SetBrush(self.brush) dc.DrawRectangle(1, 1, width-1, height-1) label = self.GetLabel() if not label: return if self.size_text: self._MeasureFont(dc, width-2, height-2) else: dc.SetFont(self.GetFont()) if self.IsEnabled(): dc.SetTextForeground(self.GetForegroundColour()) else: dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) style = self.GetWindowStyleFlag() w, h = dc.GetTextExtent(label) y = (height - h) / 2 if y < 0: y = 0 if style & wx.ALIGN_RIGHT: x = width - w - 4 elif style & wx.ALIGN_CENTER: x = (width - w - 1)/2 else: x = 3 dc.DrawText(label, x, y) class QuiskText(wx.BoxSizer): # A one-line text display left/right/center justified and vertically centered. # The height of the control is fixed as "height". The width is expanded. # The font is chosen so size_text fits in the client area. def __init__(self, parent, size_text, height, style=0, fixed=False): wx.BoxSizer.__init__(self, wx.HORIZONTAL) self.TextCtrl = _QuiskText1(parent, size_text, height, style, fixed) self.Add(self.TextCtrl, 1, flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) def SetLabel(self, label): self.TextCtrl.SetLabel(label) # Start of our button classes. They are compatible with wxPython GenButton # buttons. Use the usual methods for access: # GetLabel(self), SetLabel(self, label): Get and set the label # Enable(self, flag), Disable(self), IsEnabled(self): Enable / Disable # GetValue(self), SetValue(self, value): Get / Set check button state True / False # SetIndex(self, index): For cycle buttons, set the label from its index class QuiskButtons: """Base class for special buttons.""" button_bezel = 3 # size of button bezel in pixels def InitButtons(self, text): self.SetBezelWidth(self.button_bezel) self.SetBackgroundColour(conf.color_btn) self.SetUseFocusIndicator(False) self.font = wx.Font(conf.button_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) if text: w, h = self.GetTextExtent(text) else: w, h = self.GetTextExtent("OK") self.Disable() # create a size for null text, but Disable() w += self.button_bezel * 2 + self.GetCharWidth() h = h * 12 / 10 h += self.button_bezel * 2 self.SetSizeHints(w, h, w * 6, h, 1, 1) def DrawLabel(self, dc, width, height, dx=0, dy=0): # Override to change Disable text color dc.SetFont(self.GetFont()) label = self.GetLabel() tw, th = dc.GetTextExtent(label) dx = dy = self.labelDelta slabel = re.split('('+unichr(0x25CF)+')', label) # unicode symbol for record: a filled dot for part in slabel: # This code makes the symbol red. Thanks to Christof, DJ4CM. if self.IsEnabled(): if part == unichr(0x25CF): dc.SetTextForeground('red') else: dc.SetTextForeground(conf.color_enable) else: dc.SetTextForeground(conf.color_disable) dc.DrawText(part, (width-tw)/2+dx, (height-th)/2+dy) dx += dc.GetTextExtent(part)[0] def OnKeyDown(self, event): pass def OnKeyUp(self, event): pass class QuiskPushbutton(QuiskButtons, wx.lib.buttons.GenButton): """A plain push button widget.""" def __init__(self, parent, command, text, use_right=False): wx.lib.buttons.GenButton.__init__(self, parent, -1, text) self.command = command self.Bind(wx.EVT_BUTTON, self.OnButton) self.InitButtons(text) self.direction = 1 if use_right: self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) def OnButton(self, event): if self.command: self.command(event) def OnRightDown(self, event): self.direction = -1 self.OnLeftDown(event) def OnRightUp(self, event): self.OnLeftUp(event) self.direction = 1 class QuiskRepeatbutton(QuiskButtons, wx.lib.buttons.GenButton): """A push button that repeats when held down.""" def __init__(self, parent, command, text, up_command=None, use_right=False): wx.lib.buttons.GenButton.__init__(self, parent, -1, text) self.command = command self.up_command = up_command self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.OnTimer) self.Bind(wx.EVT_BUTTON, self.OnButton) self.InitButtons(text) self.repeat_state = 0 # repeater button inactive self.direction = 1 if use_right: self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) def SendCommand(self, command): if command: event = wx.PyEvent() event.SetEventObject(self) command(event) def OnLeftDown(self, event): if self.IsEnabled(): self.shift = event.ShiftDown() self.control = event.ControlDown() self.SendCommand(self.command) self.repeat_state = 1 # first button push self.timer.Start(milliseconds=300, oneShot=True) wx.lib.buttons.GenButton.OnLeftDown(self, event) def OnLeftUp(self, event): if self.IsEnabled(): self.SendCommand(self.up_command) self.repeat_state = 0 self.timer.Stop() wx.lib.buttons.GenButton.OnLeftUp(self, event) def OnRightDown(self, event): if self.IsEnabled(): self.shift = event.ShiftDown() self.control = event.ControlDown() self.direction = -1 self.OnLeftDown(event) def OnRightUp(self, event): if self.IsEnabled(): self.OnLeftUp(event) self.direction = 1 def OnTimer(self, event): if self.repeat_state == 1: # after first push, turn on repeats self.timer.Start(milliseconds=150, oneShot=False) self.repeat_state = 2 if self.repeat_state: # send commands until button is released self.SendCommand(self.command) def OnButton(self, event): pass # button command not used class QuiskCheckbutton(QuiskButtons, wx.lib.buttons.GenToggleButton): """A button that pops up and down, and changes color with each push.""" # Check button; get the checked state with self.GetValue() def __init__(self, parent, command, text, color=None, use_right=False): wx.lib.buttons.GenToggleButton.__init__(self, parent, -1, text) self.InitButtons(text) self.Bind(wx.EVT_BUTTON, self.OnButton) self.button_down = 0 # used for radio buttons self.command = command if color is None: self.color = conf.color_check_btn else: self.color = color self.direction = 1 if use_right: self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) def SetValue(self, value, do_cmd=False): wx.lib.buttons.GenToggleButton.SetValue(self, value) self.button_down = value if value: self.SetBackgroundColour(self.color) else: self.SetBackgroundColour(conf.color_btn) if do_cmd and self.command: event = wx.PyEvent() event.SetEventObject(self) self.command(event) def OnButton(self, event): if self.GetValue(): self.SetBackgroundColour(self.color) else: self.SetBackgroundColour(conf.color_btn) if self.command: self.command(event) def OnRightDown(self, event): self.direction = -1 self.OnLeftDown(event) def OnRightUp(self, event): self.OnLeftUp(event) self.direction = 1 class QFilterButtonWindow(wx.Frame): """Create a window with controls for the button""" def __init__(self, button): self.button = button l = self.valuelist = [] value = 10 incr = 10 for i in range(0, 101): l.append(value) value += incr if value == 100: incr = 20 elif value == 500: incr = 50 elif value == 1000: incr = 100 elif value == 5000: incr = 500 elif value == 10000: incr = 1000 x, y = button.GetPositionTuple() x, y = button.GetParent().ClientToScreenXY(x, y) w, h = button.GetSize() height = h * 10 size = (w, height) if sys.platform == 'win32': pos = (x, y - height) t = 'Filter' else: pos = (x, y - height - h) t = '' wx.Frame.__init__(self, button.GetParent(), -1, t, pos, size, wx.FRAME_TOOL_WINDOW|wx.FRAME_FLOAT_ON_PARENT|wx.CLOSE_BOX|wx.CAPTION|wx.SYSTEM_MENU) self.SetBackgroundColour(conf.color_freq) self.Bind(wx.EVT_CLOSE, self.OnClose) value = int(button.GetLabel()) try: index = 100 - self.valuelist.index(value) except ValueError: index = 0 self.slider = wx.Slider(self, -1, index, 0, 100, (0, 0), (w/2, height), wx.SL_VERTICAL) self.slider.Bind(wx.EVT_SCROLL, self.OnSlider) self.Show() self.slider.SetFocus() def OnSlider(self, event): value = self.slider.GetValue() value = 100 - value value = self.valuelist[value] self.button.SetLabel(str(value)) self.button.Refresh() self.button.SetValue(True, True) application.filterAdjBw1 = value def OnClose(self, event): self.button.adjust = None self.Destroy() class QuiskFilterButton(QuiskCheckbutton): """An adjustable check button for filter width; right-click to adjust.""" def __init__(self, parent, command=None, text='', color=None): if color is None: color = conf.color_adjust_btn QuiskCheckbutton.__init__(self, parent, command, text, color) self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.adjust = None def OnRightDown(self, event): self.OnButton(event) if self.adjust: self.adjust.Destroy() self.adjust = None else: self.adjust = QFilterButtonWindow(self) class QSliderButtonWindow(wx.Frame): """Create a window with controls for the button""" def __init__(self, button): self.button = button x, y = button.GetPositionTuple() x, y = button.GetParent().ClientToScreenXY(x, y) w, h = button.GetSize() height = h * 10 size = (w, height) if sys.platform == 'win32': pos = (x, y - height) else: pos = (x, y - height - h) wx.Frame.__init__(self, button.GetParent(), -1, '', pos, size, wx.FRAME_TOOL_WINDOW|wx.FRAME_FLOAT_ON_PARENT|wx.CLOSE_BOX|wx.CAPTION|wx.SYSTEM_MENU) self.SetBackgroundColour(conf.color_freq) self.Bind(wx.EVT_CLOSE, self.OnClose) self.slider = wx.Slider(self, -1, self.button.slider_value, self.button.slider_min, self.button.slider_max, (0, 0), (w/2, height), wx.SL_VERTICAL) self.slider.Bind(wx.EVT_SCROLL, self.OnSlider) self.Show() self.slider.SetFocus() def OnSlider(self, event): self.button.slider_value = self.slider.GetValue() self.button.SetValue(self.button.GetValue(), True) self.button.SetLabel() def OnClose(self, event): self.button.adjust = None self.Destroy() self.button.SetLabel() class QuiskSliderButton(QuiskCheckbutton): """An adjustable check button; right-click to adjust.""" def __init__(self, parent, command=None, text='', color=None, slider_value=0, slider_min=0, slider_max=1000): if color is None: color = conf.color_adjust_btn self.text = text self.slider_value = slider_value self.slider_min = slider_min self.slider_max = slider_max QuiskCheckbutton.__init__(self, parent, command, text, color) self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.adjust = None def OnRightDown(self, event): self.OnButton(event) if self.adjust: self.adjust.Destroy() self.adjust = None else: self.adjust = QSliderButtonWindow(self) def SetLabel(self, text=None): if text is not None: QuiskCheckbutton.SetLabel(self, text) def SetSlider(self, value): self.slider_value = value class QuiskSpotButton(QuiskSliderButton): def SetLabel(self, text=None): if text is None: if self.adjust: value = self.slider_min + self.slider_max - self.slider_value text = "%.3f" % (value / 1000.) else: text = self.text QuiskCheckbutton.SetLabel(self, text) self.Refresh() class QuiskCycleCheckbutton(QuiskCheckbutton): """A button that cycles through its labels with each push. The button is up for labels[0], down for all other labels. Change to the next label for each push. If you call SetLabel(), the label must be in the list. The self.index is the index of the current label. """ def __init__(self, parent, command, labels, color=None, is_radio=False): self.labels = list(labels) # Be careful if you change this list self.index = 0 # index of selected label 0, 1, ... self.direction = 0 # 1 for up, -1 for down, 0 for no change to index self.is_radio = is_radio # Is this a radio cycle button? if color is None: color = conf.color_cycle_btn QuiskCheckbutton.__init__(self, parent, command, labels[0], color) self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDclick) def SetLabel(self, label, do_cmd=False): self.index = self.labels.index(label) QuiskCheckbutton.SetLabel(self, label) QuiskCheckbutton.SetValue(self, self.index) if do_cmd and self.command: event = wx.PyEvent() event.SetEventObject(self) self.command(event) def SetIndex(self, index, do_cmd=False): self.index = index QuiskCheckbutton.SetLabel(self, self.labels[index]) QuiskCheckbutton.SetValue(self, index) if do_cmd and self.command: event = wx.PyEvent() event.SetEventObject(self) self.command(event) def OnButton(self, event): if not self.is_radio or self.button_down: self.direction = 1 self.index += 1 if self.index >= len(self.labels): self.index = 0 self.SetIndex(self.index) else: self.direction = 0 if self.command: self.command(event) def OnRightDown(self, event): # Move left in the list of labels if not self.is_radio or self.GetValue(): self.index -= 1 if self.index < 0: self.index = len(self.labels) - 1 self.SetIndex(self.index) self.direction = -1 if self.command: self.command(event) def OnLeftDclick(self, event): # Left double-click: Set index zero if not self.is_radio or self.GetValue(): self.index = 0 self.SetIndex(self.index) self.direction = 1 if self.command: self.command(event) class RadioButtonGroup: """This class encapsulates a group of radio buttons. This class is not a button! The "labels" is a list of labels for the toggle buttons. An item of labels can be a list/tuple, and the corresponding button will be a cycle button. """ def __init__(self, parent, command, labels, default): self.command = command self.buttons = [] self.button = None for text in labels: if type(text) in (ListType, TupleType): b = QuiskCycleCheckbutton(parent, self.OnButton, text, is_radio=True) for t in text: if t == default and self.button is None: b.SetLabel(t) self.button = b else: b = QuiskCheckbutton(parent, self.OnButton, text) if text == default and self.button is None: b.SetValue(True) self.button = b self.buttons.append(b) def ReplaceButton(self, index, button): # introduce a specialized button b = self.buttons[index] b.Destroy() self.buttons[index] = button button.command = self.OnButton def SetLabel(self, label, do_cmd=False): self.button = None for b in self.buttons: if self.button is not None: b.SetValue(False) elif isinstance(b, QuiskCycleCheckbutton): try: index = b.labels.index(label) except ValueError: b.SetValue(False) continue else: b.SetIndex(index) self.button = b b.SetValue(True) elif b.GetLabel() == label: b.SetValue(True) self.button = b else: b.SetValue(False) if do_cmd and self.command and self.button: event = wx.PyEvent() event.SetEventObject(self.button) self.command(event) def GetButtons(self): return self.buttons def OnButton(self, event): win = event.GetEventObject() for b in self.buttons: if b is win: self.button = b b.SetValue(True) else: b.SetValue(False) if self.command: self.command(event) def GetLabel(self): if not self.button: return None return self.button.GetLabel() def GetSelectedButton(self): # return the selected button return self.button class FreqSetter(wx.TextCtrl): def __init__(self, parent, x, y, label, fmin, fmax, freq, command): self.pos = (x, y) self.label = label self.fmin = fmin self.fmax = fmax self.command = command self.font = wx.Font(16, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) t = wx.StaticText(parent, -1, label, pos=(x, y)) t.SetFont(self.font) freq_w, freq_h = t.GetTextExtent(" 662 000 000") tw, th = t.GetSizeTuple() x += tw + 20 wx.TextCtrl.__init__(self, parent, size=(freq_w, freq_h), pos=(x, y), style=wx.TE_RIGHT|wx.TE_PROCESS_ENTER) self.SetFont(self.font) self.Bind(wx.EVT_TEXT, self.OnText) self.Bind(wx.EVT_TEXT_ENTER, self.OnEnter) w, h = self.GetSizeTuple() x += w + 1 self.butn = b = wx.SpinButton(parent, size=(freq_h, freq_h), pos=(x, y)) w, h = b.GetSizeTuple() self.end_pos = (x + w, y + h) b.Bind(wx.EVT_SPIN, self.OnSpin) # The spin button frequencies are in kHz b.SetMin(fmin / 1000) b.SetMax(fmax / 1000) self.SetValue(freq) def OnText(self, event): self.SetBackgroundColour('pink') def OnEnter(self, event): text = wx.TextCtrl.GetValue(self) text = text.replace(' ', '') if '-' in text: return try: if '.' in text: freq = int(float(text) * 1000000 + 0.5) else: freq = int(text) except: return self.SetValue(freq) self.command(self) def OnSpin(self, event): freq = self.butn.GetValue() * 1000 self.SetValue(freq) self.command(self) def SetValue(self, freq): if freq < self.fmin: freq = self.fmin elif freq > self.fmax: freq = self.fmax self.butn.SetValue(freq / 1000) txt = FreqFormatter(freq) wx.TextCtrl.SetValue(self, txt) self.SetBackgroundColour(conf.color_entry) def GetValue(self): value = wx.TextCtrl.GetValue(self) value = value.replace(' ', '') try: value = int(value) except: value = 7000 return value quisk-3.6.11/sound_portaudio.c0000666000175000017500000002763512110156270015714 0ustar jimjim00000000000000/* * This modue provides sound access for QUISK using the portaudio library. */ #include #include #include #include #include #include #include "quisk.h" /* The sample rate is in frames per second. Each frame has a number of channels, and each channel has a sample of size sample_bytes. The channels are interleaved: (channel0, channel1), (channel0, channel1), ... */ extern struct sound_conf quisk_sound_state; // Current sound status static float fbuffer[SAMP_BUFFER_SIZE]; // Buffer for float32 samples from sound int quisk_read_portaudio(struct sound_dev * dev, complex * cSamples) { // Read sound samples from the soundcard. // Samples are converted to 32 bits with a range of +/- CLIP32 and placed into cSamples. int i; long avail; int nSamples; complex c; PaError error; float fi, fq; if (!dev->handle) return -1; avail = Pa_GetStreamReadAvailable((PaStream * )dev->handle); dev->dev_latency = avail; if (dev->read_frames == 0) { // non-blocking: read available frames if (avail > SAMP_BUFFER_SIZE / dev->num_channels) // limit read request to buffer size avail = SAMP_BUFFER_SIZE / dev->num_channels; } else { // size of read request avail = dev->read_frames; } error = Pa_ReadStream ((PaStream * )dev->handle, fbuffer, avail); if (error != paNoError) { dev->dev_error++; } nSamples = 0; for (i = 0; avail; i += dev->num_channels, nSamples++, avail--) { fi = fbuffer[i + dev->channel_I]; fq = fbuffer[i + dev->channel_Q]; if (fi >= 1.0 || fi <= -1.0) dev->overrange++; // assume overrange returns max int if (fq >= 1.0 || fq <= -1.0) dev->overrange++; cSamples[nSamples] = (fi + I * fq) * CLIP32; } for (i = 0; i < nSamples; i++) { // DC removal; R.G. Lyons page 553 c = cSamples[i] + dev->dc_remove * 0.95; cSamples[i] = c - dev->dc_remove; dev->dc_remove = c; } return nSamples; } void quisk_play_portaudio(struct sound_dev * playdev, int nSamples, complex * cSamples, int report_latency, double volume) { // play the samples; write them to the portaudio soundcard int i, n, index; long delay; float fi, fq; PaError error; if (!playdev->handle || nSamples <= 0) return; // "delay" is the number of samples left in the play buffer delay = playdev->play_buf_size - Pa_GetStreamWriteAvailable(playdev->handle); //printf ("play available %ld\n", Pa_GetStreamWriteAvailable(playdev->handle)); playdev->dev_latency = delay; if (report_latency) { // Report for main playback device quisk_sound_state.latencyPlay = delay; } //printf ("nSamples %d, delay %ld\n", nSamples, delay); index = 0; #if 0 // Timing is too crude to support this logic if (nSamples + delay > playdev->latency_frames * 9 / 10) { nSamples--; #if DEBUG_IO printf("Remove a sample %s nSamples %4d delay %4d total %4d\n", playdev->name, nSamples, (int)delay, nSamples + (int)delay); #endif } else if(nSamples + delay < playdev->latency_frames * 5 / 10) { cSamples[nSamples] = cSamples[nSamples - 1]; nSamples++; #if DEBUG_IO printf("Add a sample %s nSamples %4d delay %4d total %4d\n", playdev->name, nSamples, (int)delay, nSamples + (int)delay); #endif } #endif if (nSamples + delay > playdev->latency_frames) { // too many samples index = nSamples + delay - playdev->latency_frames; // write only the most recent samples if (index > nSamples) index = nSamples; quisk_sound_state.write_error++; playdev->dev_error++; #if DEBUG_IO printf("Discard %d of %d samples at %d delay\n", index, nSamples, (int)delay); #endif if (nSamples == index) // no samples to play return; } else if (delay < 16) { // Buffer is too empty; fill it back up with zeros. n = playdev->latency_frames * 7 / 10 - nSamples; #if DEBUG_IO printf("Add %d zero samples at %ld delay\n", n, delay); #endif for (i = 0; i < n; i++) cSamples[nSamples++] = 0; } for (i = 0, n = index; n < nSamples; i += playdev->num_channels, n++) { fi = volume * creal(cSamples[n]); fq = volume * cimag(cSamples[n]); fbuffer[i + playdev->channel_I] = fi / CLIP32; fbuffer[i + playdev->channel_Q] = fq / CLIP32; } error = Pa_WriteStream ((PaStream * )playdev->handle, fbuffer, nSamples - index); //printf ("Write %d\n", nSamples - index); if (error == paNoError) ; else if (error == paOutputUnderflowed) { quisk_sound_state.underrun_error++; playdev->dev_underrun++; } else { quisk_sound_state.write_error++; playdev->dev_error++; #if DEBUG_IO printf ("Play error: %s\n", Pa_GetErrorText(error)); #endif } } static void info_portaudio (struct sound_dev * cDev, struct sound_dev * pDev) { // Return information about the device const PaDeviceInfo * info; PaStreamParameters params; int index, rate; if (cDev) index = cDev->portaudio_index; else if (pDev) index = pDev->portaudio_index; else return; info = Pa_GetDeviceInfo(index); if ( ! info) return; params.device = index; params.channelCount = 1; params.sampleFormat = paFloat32; params.suggestedLatency = 0.10; params.hostApiSpecificStreamInfo = NULL; if (cDev) { cDev->chan_min = 1; cDev->chan_max = info->maxInputChannels; cDev->rate_min = cDev->rate_max = 0; cDev->portaudio_latency = info->defaultHighInputLatency; #if DEBUG_IO printf ("Capture latency low %lf, high %lf\n", info->defaultLowInputLatency, info->defaultHighInputLatency); #endif for (rate = 8000; rate <= 384000; rate += 8000) { if (Pa_IsFormatSupported(¶ms, NULL, rate) == paFormatIsSupported) { if (cDev->rate_min == 0) cDev->rate_min = rate; cDev->rate_max = rate; } } } if (pDev) { pDev->chan_min = 1; pDev->chan_max = info->maxOutputChannels; pDev->rate_min = pDev->rate_max = 0; pDev->portaudio_latency = quisk_sound_state.latency_millisecs / 1000.0 * 2.0; if (pDev->portaudio_latency < info->defaultHighOutputLatency) pDev->portaudio_latency = info->defaultHighOutputLatency; #if DEBUG_IO printf ("Play latency low %lf, high %lf\n", info->defaultLowOutputLatency, info->defaultHighOutputLatency); #endif for (rate = 8000; rate <= 384000; rate += 8000) { if (Pa_IsFormatSupported(¶ms, NULL, rate) == paFormatIsSupported) { if (pDev->rate_min == 0) pDev->rate_min = rate; pDev->rate_max = rate; } } } } static int quisk_pa_name2index (struct sound_dev * dev, int is_capture) { // Based on the device name, set the portaudio index, or -1. // Return non-zero for error. Not a portaudio device is not an error. const PaDeviceInfo * pInfo; int i, count; if (strncmp (dev->name, "portaudio", 9)) { dev->portaudio_index = -1; // Name does not start with "portaudio" return 0; // Not a portaudio device, not an error } if ( ! strcmp (dev->name, "portaudiodefault")) { if (is_capture) // Fill in the default device index dev->portaudio_index = Pa_GetDefaultInputDevice(); else dev->portaudio_index = Pa_GetDefaultOutputDevice(); strncpy (dev->msg1, "Using default portaudio device", QUISK_SC_SIZE); return 0; } if ( ! strncmp (dev->name, "portaudio#", 10)) { // Integer index follows "#" dev->portaudio_index = i = atoi(dev->name + 10); pInfo = Pa_GetDeviceInfo(i); if (pInfo) { snprintf (dev->msg1, QUISK_SC_SIZE, "PortAudio device %s", pInfo->name); return 0; } else { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not find portaudio device number %s", dev->name + 10); } return 1; } if ( ! strncmp (dev->name, "portaudio:", 10)) { dev->portaudio_index = -1; count = Pa_GetDeviceCount(); // Search for string in device name for (i = 0; i < count; i++) { pInfo = Pa_GetDeviceInfo(i); if (pInfo && strstr(pInfo->name, dev->name + 10)) { dev->portaudio_index = i; snprintf (dev->msg1, QUISK_SC_SIZE, "PortAudio device %s", pInfo->name); break; } } if (dev->portaudio_index == -1) { // Error snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not find portaudio device named %s", dev->name + 10); return 1; } return 0; } snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Did not recognize portaudio device %s", dev->name); return 1; } static int quisk_open_portaudio (struct sound_dev * cDev, struct sound_dev * pDev) { // Open the portaudio soundcard for capture on cDev and playback on pDev (or NULL). // Return non-zero for error. PaStreamParameters cParams, pParams; PaError error; PaStream * hndl; info_portaudio (cDev, pDev); if (pDev && cDev && pDev->sample_rate != cDev->sample_rate) { strncpy(quisk_sound_state.err_msg, "Capture and Play sample rates must be equal.", QUISK_SC_SIZE); return 1; } cParams.sampleFormat = paFloat32; pParams.sampleFormat = paFloat32; cParams.hostApiSpecificStreamInfo = NULL; pParams.hostApiSpecificStreamInfo = NULL; if (cDev) { cDev->handle = NULL; cParams.device = cDev->portaudio_index; cParams.channelCount = cDev->num_channels; cParams.suggestedLatency = cDev->portaudio_latency; } if (pDev) { pDev->handle = NULL; pParams.device = pDev->portaudio_index; pParams.channelCount = pDev->num_channels; pParams.suggestedLatency = pDev->portaudio_latency; } if (cDev && pDev) { error = Pa_OpenStream (&hndl, &cParams, &pParams, (double)cDev->sample_rate, cDev->read_frames, 0, NULL, NULL); pDev->handle = cDev->handle = (void *)hndl; } else if (cDev) { error = Pa_OpenStream (&hndl, &cParams, NULL, (double)cDev->sample_rate, cDev->read_frames, 0, NULL, NULL); cDev->handle = (void *)hndl; } else if (pDev) { error = Pa_OpenStream (&hndl, NULL, &pParams, (double)pDev->sample_rate, 0, 0, NULL, NULL); pDev->handle = (void *)hndl; } else { error = paNoError; } if (pDev) { pDev->play_buf_size = Pa_GetStreamWriteAvailable(pDev->handle); if (pDev->latency_frames > pDev->play_buf_size) { #if DEBUG_IO printf("Latency frames %d limited to buffer size %d\n", pDev->latency_frames, pDev->play_buf_size); #endif pDev->latency_frames = pDev->play_buf_size; } } #if DEBUG_IO if (pDev) { printf ("play_buf_size %d\n", pDev->play_buf_size); printf ("latency_frames %d\n", pDev->latency_frames); } #endif if (error == paNoError) return 0; strncpy(quisk_sound_state.err_msg, Pa_GetErrorText(error), QUISK_SC_SIZE); return 1; } void quisk_start_sound_portaudio(struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { int index, err, match; struct sound_dev ** pCapt, ** pPlay; Pa_Initialize(); // Set the portaudio index from the name; or set -1. Return on error. pCapt = pCapture; while (*pCapt) { if (quisk_pa_name2index (*pCapt, 1)) return; // Error pCapt++; } pPlay = pPlayback; while (*pPlay) { if (quisk_pa_name2index (*pPlay, 0)) return; pPlay++; } // Open the sound cards. If a capture device equals a playback device, they must be opened jointly. pCapt = pCapture; while (*pCapt) { index = (*pCapt)->portaudio_index; if (index >= 0) { // This is a portaudio device pPlay = pPlayback; match = 0; while (*pPlay) { if ((*pPlay)->portaudio_index == index) { // same device, open both err = quisk_open_portaudio (*pCapt, *pPlay); match = 1; break; } pPlay++; } if ( ! match) err = quisk_open_portaudio (*pCapt, NULL); // no matching device if (err) return; // error } pCapt++; } strncpy (quisk_sound_state.msg1, (*pCapture)->msg1, QUISK_SC_SIZE); // Primary capture device // Open remaining portaudio devices pPlay = pPlayback; while (*pPlay) { if ((*pPlay)->portaudio_index >= 0 && ! (*pPlay)->handle) { err = quisk_open_portaudio (NULL, *pPlay); if (err) return; // error } pPlay++; } if ( ! quisk_sound_state.msg1[0]) // Primary playback device strncpy (quisk_sound_state.msg1, (*pPlayback)->msg1, QUISK_SC_SIZE); pCapt = pCapture; while (*pCapt) { if ((*pCapt)->handle) Pa_StartStream((PaStream * )(*pCapt)->handle); pCapt++; } pPlay = pPlayback; while (*pPlay) { if ((*pPlay)->handle && Pa_IsStreamStopped((PaStream * )(*pPlay)->handle)) Pa_StartStream((PaStream * )(*pPlay)->handle); pPlay++; } } void quisk_close_sound_portaudio(void) { Pa_Terminate(); } quisk-3.6.11/quisk_hardware_model.py0000666000175000017500000001125412125356340017071 0ustar jimjim00000000000000# Please do not change this hardware control module for Quisk. # It is a basic module providing almost no features. You should # still use it a a base class for your own hardware modules. # If you want to use a hardware module different from the default # module quisk_hardware_model, then specify it in your quisk_conf.py: # import quisk_hardware_myhardware as quisk_hardware # or if it is in the n2adr (or other) package: # from n2adr import quisk_hardware # A custom hardware module should subclass this module; start it with: # from quisk_hardware_model import Hardware as BaseHardware # class Hardware(BaseHardware): # def __init__(self, app, conf): # BaseHardware.__init__(self, app, conf) # ### your module starts here # Alternatively, you can define a class named "Hardware" in your config file, # and that class will be used instead of a hardware file. This is recommended # only for simple hardware needs. The class should start the same as above. class Hardware: def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.rf_gain_labels = () # Do not add the Rf Gain button self.correct_smeter = conf.correct_smeter # Default correction for S-meter self.use_sidetone = 0 # Don't show the sidetone volume control def open(self): # Called once to open the Hardware # Return an informative message for the config screen t = "Capture from sound card %s." % self.conf.name_of_sound_capt return t def close(self): # Called once to close the Hardware pass def ChangeFrequency(self, tune, vfo, source='', band='', event=None): # Change and return the tuning and VFO frequency in Hertz. The VFO frequency is the # frequency in the center of the display; that is, the RF frequency corresponding to an # audio frequency of zero Hertz. The tuning frequency is the RF frequency indicated by # the tuning line on the display, and is equivalent to the transmit frequency. The quisk # receive frequency is the tuning frequency plus the RIT (receive incremental tuning). # If your hardware will not change to the requested frequencies, return different # frequencies. # The source is a string indicating the source of the change: # BtnBand A band button # BtnUpDown The band Up/Down buttons # FreqEntry The user entered a frequency in the box # MouseBtn1 Left mouse button press # MouseBtn3 Right mouse button press # MouseMotion The user is dragging with the left button # MouseWheel The mouse wheel up/down # NewDecim The decimation changed # For "BtnBand", the string band is in the band argument. # For the mouse events, the handler event is in the event argument. return tune, vfo def ReturnFrequency(self): # Return the current tuning and VFO frequency. If neither have changed, # you can return (None, None). This is called at about 10 Hz by the main. # return (tune, vfo) # return changed frequencies return None, None # frequencies have not changed def ReturnVfoFloat(self): # Return the accurate VFO frequency as a floating point number. # You can return None to indicate that the integer VFO frequency is valid. return None def ChangeMode(self, mode): # Change the tx/rx mode # mode is a string: "USB", "AM", etc. pass def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. pass def OnBtnFDX(self, is_fdx): # Status of FDX button, 0 or 1 pass def HeartBeat(self): # Called at about 10 Hz by the main pass # The "VarDecim" methods are used to change the hardware decimation rate. # If VarDecimGetChoices() returns any False value, no other methods are called. def VarDecimGetChoices(self): # Return a list/tuple of strings for the decimation control. return False # Return a False value for no decimation changes possible. def VarDecimGetLabel(self): # Return a text label for the decimation control. return '' def VarDecimGetIndex(self): # Return the index 0, 1, ... of the current decimation. return 0 # This is called before open() to initialize the control. def VarDecimSet(self, index=None): # Called when the control is operated. # Change the decimation here, and return the sample rate. The index is 0, 1, 2, .... # Called with index == None before open() to set the initial sample rate. # Note: The last used value is available as self.application.vardecim_set if # the persistent state option is True. If the value is unavailable for # any reason, self.application.vardecim_set is None. return 48000 quisk-3.6.11/import_quisk_api.c0000666000175000017500000000531011724440624016050 0ustar jimjim00000000000000/* This module uses the Python CObject or Capsule interface to import pointers to functions and variables defined in the _quisk Python extension module. These functions and variables can then be used in another extension module. This is an alternative to linking the other extension module to _quisk with the C linker. This interface is used by the SDR-IQ extension module, and you can use that as a model. This feature exists because of Maitland Bottoms, AA4HS, who requested the feature and provided patches. To use this interface in your own extension module, first modify your setup.py or makefile so that you are not linking in symbols from the _quisk module. Add import_quisk_api.c to your source files. Then add this define before including quisk.h: #define IMPORT_QUISK_API #include "quisk.h" Add this code after Py_InitModule() in your module init function (PyMODINIT_FUNC): // Import pointers to functions and variables from module _quisk if (import_quisk_api()) { printf("Failure to import pointers from _quisk\n"); return; //Error } Use this new function to set your Start/Stop/Read functions (if used): quisk_sample_source(&quisk_start_sdriq, &quisk_stop_sdriq, &quisk_read_sdriq); Change references to quisk_sound_state to use the pointer pt_quisk_sound_state everywhere. For example, replace this: quisk_sound_state.read_error++; with this: pt_quisk_sound_state->read_error++; */ #include void ** Quisk_API; // array of pointers to functions and variables from module _quisk struct sound_conf * pt_quisk_sound_state; // pointer to quisk_sound_state #if ( (PY_VERSION_HEX < 0x02070000) || ((PY_VERSION_HEX >= 0x03000000) && (PY_VERSION_HEX < 0x03010000)) ) // Old Python interface using CObject int import_quisk_api(void) { PyObject *c_api_object; PyObject *module; module = PyImport_ImportModule("_quisk"); if (module == NULL) { printf("Failure 1 to import Quisk_API\n"); return -1; } c_api_object = PyObject_GetAttrString(module, "QUISK_C_API"); if (c_api_object == NULL) { Py_DECREF(module); printf("Failure 2 to import Quisk_API\n"); return -1; } if (PyCObject_Check(c_api_object)) { Quisk_API = (void **)PyCObject_AsVoidPtr(c_api_object); } else { printf("Failure 3 to import Quisk_API\n"); Py_DECREF(c_api_object); Py_DECREF(module); return -1; } Py_DECREF(c_api_object); Py_DECREF(module); pt_quisk_sound_state = (struct sound_conf *)Quisk_API[0]; return 0; } #else // New Python interface using Capsule int import_quisk_api(void) { Quisk_API = (void **)PyCapsule_Import("_quisk.QUISK_C_API", 0); if (Quisk_API == NULL) { printf("Failure to import Quisk_API\n"); return -1; } pt_quisk_sound_state = (struct sound_conf *)Quisk_API[0]; return 0; } #endif quisk-3.6.11/quisk.py0000666000175000017500000042115212160323512014030 0ustar jimjim00000000000000#! /usr/bin/python # All QUISK software is Copyright (C) 2006-2011 by James C. Ahlstrom. # This free software is licensed for use under the GNU General Public # License (GPL), see http://www.opensource.org. # Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!! """The main program for Quisk, a software defined radio. Usage: python quisk.py [-c | --config config_file_path] This can also be installed as a package and run as quisk.main(). """ from __future__ import print_function # Change to the directory of quisk.py. This is necessary to import Quisk packages # and to load other extension modules that link against _quisk.so. It also helps to # find ./__init__.py and ./help.html. import sys, os os.chdir(os.path.normpath(os.path.dirname(__file__))) if sys.path[0] != "'.'": # Make sure the current working directory is on path sys.path.insert(0, '.') import wxversion # Thanks to Mario, DH5YM wxversion.ensureMinimal('2.8') import wx, wx.html, wx.lib.buttons, wx.lib.stattext, wx.lib.colourdb, wx.grid, wx.richtext import math, cmath, time, traceback, string import threading, pickle, webbrowser if sys.version_info[0] == 3: # Python3 from xmlrpc.client import ServerProxy else: # Python version 2.x from xmlrpclib import ServerProxy import _quisk as QS from types import * from quisk_widgets import * from filters import Filters import dxcluster # Fldigi XML-RPC control opens a local socket. If socket.setdefaulttimeout() is not # called, the timeout on Linux is zero (1 msec) and on Windows is 2 seconds. So we # call it to insure consistent behavior. import socket socket.setdefaulttimeout(0.005) # Command line parsing: be able to specify the config file. from optparse import OptionParser parser = OptionParser() parser.add_option('-c', '--config', dest='config_file_path', help='Specify the configuration file path') parser.add_option('', '--config2', dest='config_file_path2', default='', help='Specify a second configuration file to read after the first') argv_options = parser.parse_args()[0] ConfigPath = argv_options.config_file_path # Get config file path ConfigPath2 = argv_options.config_file_path2 if not ConfigPath: # Use default path if sys.platform == 'win32': path = os.getenv('HOMEDRIVE', '') + os.getenv('HOMEPATH', '') for dir in ("Documents", "My Documents", "Eigene Dateien", "Documenti", "Mine Dokumenter"): ConfigPath = os.path.join(path, dir) if os.path.isdir(ConfigPath): break else: ConfigPath = os.path.join(path, "My Documents") ConfigPath = os.path.join(ConfigPath, "quisk_conf.py") if not os.path.isfile(ConfigPath): # See if the user has a config file try: import shutil # Try to create an initial default config file shutil.copyfile('quisk_conf_win.py', ConfigPath) except: pass else: ConfigPath = os.path.expanduser('~/.quisk_conf.py') # These FFT sizes have multiple small factors, and are prefered for efficiency: fftPreferedSizes = (416, 448, 480, 512, 576, 640, 672, 704, 768, 800, 832, 864, 896, 960, 1024, 1056, 1120, 1152, 1248, 1280, 1344, 1408, 1440, 1536, 1568, 1600, 1664, 1728, 1760, 1792, 1920, 2016, 2048, 2080, 2112, 2240, 2304, 2400, 2464, 2496, 2560, 2592, 2688, 2816, 2880, 2912) def round(x): # round float to nearest integer if x >= 0: return int(x + 0.5) else: return - int(-x + 0.5) def str2freq (freq): if '.' in freq: freq = int(float(freq) * 1E6 + 0.1) else: freq = int(freq) return freq class Timer: """Debug: measure and print times every ptime seconds. Call with msg == '' to start timer, then with a msg to record the time. """ def __init__(self, ptime = 1.0): self.ptime = ptime # frequency to print in seconds self.time0 = 0 # time zero; measure from this time self.time_print = 0 # last time data was printed self.timers = {} # one timer for each msg self.names = [] # ordered list of msg self.heading = 1 # print heading on first use def __call__(self, msg): tm = time.time() if msg: if not self.time0: # Not recording data return if msg in self.timers: count, average, highest = self.timers[msg] else: self.names.append(msg) count = 0 average = highest = 0.0 count += 1 delta = tm - self.time0 average += delta if highest < delta: highest = delta self.timers[msg] = (count, average, highest) if tm - self.time_print > self.ptime: # time to print results self.time0 = 0 # end data recording, wait for reset self.time_print = tm if self.heading: self.heading = 0 print ("count, msg, avg, max (msec)") print("%4d" % count, end=' ') for msg in self.names: # keep names in order count, average, highest = self.timers[msg] if not count: continue average /= count print(" %s %7.3f %7.3f" % (msg, average * 1e3, highest * 1e3), end=' ') self.timers[msg] = (0, 0.0, 0.0) print() else: # reset the time to zero self.time0 = tm # Start timer if not self.time_print: self.time_print = tm ## T = Timer() # Make a timer instance class HamlibHandler: """This class is created for each connection to the server. It services requests from each client""" SingleLetters = { # convert single-letter commands to long commands '_':'info', 'f':'freq', 'i':'split_freq', 'm':'mode', 's':'split_vfo', 't':'ptt', 'v':'vfo', } # I don't understand the need for dump_state, nor what it means. # A possible response to the "dump_state" request: dump1 = """ 2 2 2 150000.000000 1500000000.000000 0x1ff -1 -1 0x10000003 0x3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x1ff 1 0x1ff 0 0 0 0x1e 2400 0x2 500 0x1 8000 0x1 2400 0x20 15000 0x20 8000 0x40 230000 0 0 9990 9990 10000 0 10 10 20 30 0x3effffff 0x3effffff 0x7fffffff 0x7fffffff 0x7fffffff 0x7fffffff """ # Another possible response to the "dump_state" request: dump2 = """ 0 2 2 150000.000000 30000000.000000 0x900af -1 -1 0x10 000003 0x3 0 0 0 0 0 0 0 150000.000000 30000000.000000 0x900af -1 -1 0x10 000003 0x3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x0 0x0 0x0 0x0 0x0 0 """ def __init__(self, app, sock, address): self.app = app # Reference back to the "hardware" self.sock = sock sock.settimeout(0.0) self.address = address self.received = '' h = self.Handlers = {} h[''] = self.ErrProtocol h['dump_state'] = self.DumpState h['get_freq'] = self.GetFreq h['set_freq'] = self.SetFreq h['get_info'] = self.GetInfo h['get_mode'] = self.GetMode h['set_mode'] = self.SetMode h['get_vfo'] = self.GetVfo h['get_ptt'] = self.GetPtt h['set_ptt'] = self.SetPtt h['get_split_freq'] = self.GetSplitFreq h['set_split_freq'] = self.SetSplitFreq h['get_split_vfo'] = self.GetSplitVfo h['set_split_vfo'] = self.SetSplitVfo def Send(self, text): """Send text back to the client.""" try: self.sock.sendall(text) except socket.error: self.sock.close() self.sock = None def Reply(self, *args): # args is name, value, name, value, ..., int """Create a string reply of name, value pairs, and an ending integer code.""" if self.extended: # Use extended format t = "%s:" % self.cmd # Extended format echoes the command and parameters for param in self.params: t = "%s %s" % (t, param) t += self.extended for i in range(0, len(args) - 1, 2): t = "%s%s: %s%c" % (t, args[i], args[i+1], self.extended) t += "RPRT %d\n" % args[-1] elif len(args) > 1: # Use simple format t = '' for i in range(1, len(args) - 1, 2): t = "%s%s\n" % (t, args[i]) else: # No names; just the required integer code t = "RPRT %d\n" % args[0] # print 'Reply', t self.Send(t) def ErrParam(self): # Invalid parameter self.Reply(-1) def UnImplemented(self): # Command not implemented self.Reply(-4) def ErrProtocol(self): # Protocol error self.Reply(-8) def Process(self): """This is the main processing loop, and is called frequently. It reads and satisfies requests.""" if not self.sock: return 0 try: # Read any data from the socket text = self.sock.recv(1024) except socket.timeout: # This does not work pass except socket.error: # Nothing to read pass else: # We got some characters self.received += text if '\n' in self.received: # A complete command ending with newline is available cmd, self.received = self.received.split('\n', 1) # Split off the command, save any further characters else: return 1 cmd = cmd.strip() # Here is our command # print 'Get', cmd if not cmd: # ??? Indicates a closed connection? # print 'empty command' self.sock.close() self.sock = None return 0 # Parse the command and call the appropriate handler if cmd[0] == '+': # rigctld Extended Response Protocol self.extended = '\n' cmd = cmd[1:].strip() elif cmd[0] in ';|,': # rigctld Extended Response Protocol self.extended = cmd[0] cmd = cmd[1:].strip() else: self.extended = None if cmd[0:1] == '\\': # long form command starting with backslash args = cmd[1:].split() self.cmd = args[0] self.params = args[1:] self.Handlers.get(self.cmd, self.UnImplemented)() else: # single-letter command self.params = cmd[1:].strip() cmd = cmd[0:1] if cmd in 'Qq': # Quit command return 0 try: t = self.SingleLetters[cmd.lower()] except KeyError: self.UnImplemented() else: if cmd in string.uppercase: self.cmd = 'set_' + t else: self.cmd = 'get_' + t self.Handlers.get(self.cmd, self.UnImplemented)() return 1 # These are the handlers for each request def DumpState(self): self.Send(self.dump2) def GetFreq(self): self.Reply('Frequency', self.app.rxFreq + self.app.VFO, 0) def SetFreq(self): try: freq = float(self.params) self.Reply(0) except: self.ErrParam() else: freq = int(freq + 0.5) self.app.ChangeRxTxFrequency(freq, None) def GetSplitFreq(self): self.Reply('TX Frequency', self.app.txFreq + self.app.VFO, 0) def SetSplitFreq(self): try: freq = float(self.params) self.Reply(0) except: self.ErrParam() else: freq = int(freq + 0.5) self.app.ChangeRxTxFrequency(None, freq) def GetSplitVfo(self): # I am not sure if "VFO" is a suitable response if self.app.split_rxtx: self.Reply('Split', 1, 'TX VFO', 'VFO', 0) else: self.Reply('Split', 0, 'TX VFO', 'VFO', 0) def SetSplitVfo(self): # Currently (Aug 2012) hamlib fails to send the "split" parameter, so this fails try: split, vfo = self.params.split() split = int(split) self.Reply(0) except: # traceback.print_exc() self.ErrParam() else: self.app.splitButton.SetValue(split, True) def GetInfo(self): self.Reply("Info", self.app.main_frame.GetTitle(), 0) def GetMode(self): mode = self.app.mode if mode == 'CWU': mode = 'CW' elif mode == 'CWL': # Is this what CWR means? mode = 'CWR' elif mode[0:4] == 'DGT-': mode = 'USB' self.Reply('Mode', mode, 'Passband', self.app.filter_bandwidth, 0) def SetMode(self): try: mode, bw = self.params.split() bw = int(float(bw) + 0.5) except: self.ErrParam() return if mode in ('USB', 'LSB', 'AM', 'FM'): self.Reply(0) elif mode[0:4] == 'DGT-': self.Reply(0) elif mode == 'CW': mode = 'CWU' self.Reply(0) elif mode == 'CWR': mode = 'CWL' self.Reply(0) else: self.ErrParam() return self.app.OnBtnMode(None, mode) # Set mode if bw <= 0: # use default bandwidth return # Choose button closest to requested bandwidth buttons = self.app.filterButns.GetButtons() Lab = buttons[0].GetLabel() diff = abs(int(Lab) - bw) for i in range(1, len(buttons) - 1): label = buttons[i].GetLabel() df = abs(int(label) - bw) if df < diff: Lab = label diff = df self.app.OnBtnFilter(None, int(Lab)) def GetVfo(self): self.Reply('VFO', "VFO", 0) # The type of VFO we have def GetPtt(self): if QS.is_key_down(): self.Reply('PTT', 1, 0) else: self.Reply('PTT', 0, 0) def SetPtt(self): if not self.app.pttButton: self.UnImplemented() return try: ptt = int(self.params) self.Reply(0) except: self.ErrParam() else: self.app.pttButton.SetValue(ptt, True) class SoundThread(threading.Thread): """Create a second (non-GUI) thread to read, process and play sound.""" def __init__(self): self.do_init = 1 threading.Thread.__init__(self) self.doQuit = threading.Event() self.doQuit.clear() def run(self): """Read, process, play sound; then notify the GUI thread to check for FFT data.""" if self.do_init: # Open sound using this thread self.do_init = 0 QS.start_sound() wx.CallAfter(application.PostStartup) while not self.doQuit.isSet(): QS.read_sound() wx.CallAfter(application.OnReadSound) QS.close_sound() def stop(self): """Set a flag to indicate that the sound thread should end.""" self.doQuit.set() class ConfigScreen(wx.Panel): """Display a notebook with status and configuration data""" def __init__(self, parent, width, fft_size): self.y_scale = 0 self.y_zero = 0 wx.Panel.__init__(self, parent) self.notebook = notebook = wx.Notebook(self) notebook.SetBackgroundColour(conf.color_graph) self.SetBackgroundColour(conf.color_config2) font = wx.Font(conf.config_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) notebook.SetFont(font) notebook.SetForegroundColour(conf.color_notebook_txt) sizer = wx.BoxSizer() sizer.Add(notebook, 1, wx.EXPAND) self.SetSizer(sizer) # create the page windows self.status = ConfigStatus(notebook, width, fft_size) notebook.AddPage(self.status, "Status") self.config = ConfigConfig(notebook, width) notebook.AddPage(self.config, "Config") self.sound = ConfigSound(notebook, width) notebook.AddPage(self.sound, "Sound") self.favorites = ConfigFavorites(notebook, width) notebook.AddPage(self.favorites, "Favorites") def ChangeYscale(self, y_scale): pass def ChangeYzero(self, y_zero): pass def OnIdle(self, event): pass def SetTxFreq(self, tx_freq, rx_freq): pass def OnGraphData(self, data=None): self.status.OnGraphData(data) def InitBitmap(self): # Initial construction of bitmap self.status.InitBitmap() class ConfigStatus(wx.Panel): """Display the status screen.""" def __init__(self, parent, width, fft_size): wx.Panel.__init__(self, parent) self.Bind(wx.EVT_PAINT, self.OnPaint) self.width = width self.fft_size = fft_size self.interupts = 0 self.read_error = -1 self.write_error = -1 self.underrun_error = -1 self.fft_error = -1 self.latencyCapt = -1 self.latencyPlay = -1 self.y_scale = 0 self.y_zero = 0 self.rate_min = -1 self.rate_max = -1 self.chan_min = -1 self.chan_max = -1 self.mic_max_display = 0 self.err_msg = "No response" self.msg1 = "" self.font = wx.Font(conf.status_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) charx = self.charx = self.GetCharWidth() chary = self.chary = self.GetCharHeight() self.dy = chary # line spacing self.rjustify1 = (0, 1, 0) self.tabstops1 = [0] * 3 self.tabstops1[0] = x = charx self.tabstops1[1] = x = x + self.GetTextExtent("FFT number of errors 1234567890")[0] self.tabstops1[2] = x = x + self.GetTextExtent("XXXX")[0] self.rjustify2 = (0, 0, 1, 1, 1) self.tabstops2 = [] def MakeTabstops(self): luse = lname = 0 for use, name, rate, latency, errors in QS.sound_errors(): w, h = self.GetTextExtent(use) luse = max(luse, w) w, h = self.GetTextExtent(name) lname = max(lname, w) if luse == 0: return charx = self.charx self.tabstops2 = [0] * 5 self.tabstops2[0] = x = charx self.tabstops2[1] = x = x + luse + charx * 6 self.tabstops2[2] = x = x + lname + self.GetTextExtent("Sample rateXXXXXX")[0] self.tabstops2[3] = x = x + charx * 12 self.tabstops2[4] = x = x + charx * 12 def OnPaint(self, event): # Make and blit variable data self.MakeBitmap() dc = wx.PaintDC(self) dc.Blit(0, 0, self.mem_width, self.mem_height, self.mem_dc, 0, 0) def MakeRow2(self, *args): for col in range(len(args)): t = args[col] if t is None: continue t = str(t) x = self.tabstops[col] if self.rjustify[col]: w, h = self.mem_dc.GetTextExtent(t) x -= w if "Error" in t and t != "Errors": self.mem_dc.SetTextForeground('Red') self.mem_dc.DrawText(t, x, self.mem_y) self.mem_dc.SetTextForeground(conf.color_graphlabels) else: self.mem_dc.DrawText(t, x, self.mem_y) self.mem_y += self.dy def InitBitmap(self): # Initial construction of bitmap self.mem_height = application.screen_height self.mem_width = application.screen_width self.bitmap = wx.EmptyBitmap(self.mem_width, self.mem_height) self.mem_dc = wx.MemoryDC() self.mem_rect = wx.Rect(0, 0, self.mem_width, self.mem_height) self.mem_dc.SelectObject(self.bitmap) br = wx.Brush(conf.color_graph) self.mem_dc.SetBackground(br) self.mem_dc.SetFont(self.font) self.mem_dc.SetTextForeground(conf.color_graphlabels) self.mem_dc.Clear() def MakeBitmap(self): self.mem_dc.Clear() self.mem_y = self.charx self.tabstops = self.tabstops1 self.rjustify = self.rjustify1 if conf.config_file_exists: cfile = "Configuration file: %s" % conf.config_file_path else: cfile = "Error: Configuration file not found %s" % conf.config_file_path if conf.microphone_name: level = "%3.0f" % self.mic_max_display else: level = "None" if self.err_msg: err_msg = self.err_msg else: err_msg = None self.MakeRow2("Sample interrupts", self.interupts, cfile) self.MakeRow2("Microphone level dB", level, application.config_text) self.MakeRow2("FFT number of points", self.fft_size, err_msg) if conf.dxClHost: # connection to dx cluster nSpots = len(application.dxCluster.dxSpots) if nSpots > 0: msg = str(nSpots) + ' DX spot' + ('' if nSpots==1 else 's') + ' received from ' + application.dxCluster.getHost() else: msg = "No DX Cluster data from %s" % conf.dxClHost self.MakeRow2("FFT number of errors", self.fft_error, msg) else: self.MakeRow2("FFT number of errors", self.fft_error) self.mem_y += self.dy if not self.tabstops2: return self.tabstops = self.tabstops2 self.rjustify = self.rjustify2 self.font.SetUnderlined(True) self.mem_dc.SetFont(self.font) self.MakeRow2("Device", "Name", "Sample rate", "Latency", "Errors") self.font.SetUnderlined(False) self.mem_dc.SetFont(self.font) self.mem_y += self.dy * 3 / 10 if conf.use_sdriq: self.MakeRow2("Capture radio samples", "SDR-IQ", application.sample_rate, self.latencyCapt, self.read_error) elif conf.use_rx_udp: self.MakeRow2("Capture radio samples", "UDP", application.sample_rate, self.latencyCapt, self.read_error) for use, name, rate, latency, errors in QS.sound_errors(): self.MakeRow2(use, name, rate, latency, errors) def OnGraphData(self, data=None): if not self.tabstops2: # Must wait for sound to start self.MakeTabstops() (self.rate_min, self.rate_max, sample_rate, self.chan_min, self.chan_max, self.msg1, self.unused, self.err_msg, self.read_error, self.write_error, self.underrun_error, self.latencyCapt, self.latencyPlay, self.interupts, self.fft_error, self.mic_max_display, self.data_poll_usec ) = QS.get_state() self.mic_max_display = 20.0 * math.log10((self.mic_max_display + 1) / 32767.0) self.RefreshRect(self.mem_rect) class ConfigConfig(wx.Panel): def __init__(self, parent, width): wx.Panel.__init__(self, parent) self.width = width self.SetBackgroundColour(conf.color_graph) self.font = wx.Font(conf.config_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) self.charx = charx = self.GetCharWidth() self.chary = chary = self.GetCharHeight() self.dy = self.chary self.rx_phase = None self.text_audio = "Record audio to WAV file " self.text_samples = "Record samples to WAV file " # Make controls tab0 = charx * 4 # Receive phase rx = wx.StaticText(self, -1, "Adjust receive amplitude and phase") tx = wx.StaticText(self, -1, "Adjust transmit amplitude and phase") x1, y1 = tx.GetSizeTuple() self.rx_phase = ctrl = wx.Button(self, -1, "Rx Phase...") self.Bind(wx.EVT_BUTTON, self.OnBtnPhase, ctrl) if not conf.name_of_sound_capt: ctrl.Enable(0) x2, y2 = ctrl.GetSizeTuple() tab1 = tab0 + x1 + charx * 2 tab2 = tab1 + x2 tab3 = tab2 + charx * 8 self.y = y2 + self.chary self.dy = y2 * 12 / 10 self.offset = (y2 - y1) / 2 rx.SetPosition((tab0, self.y)) ctrl.SetPosition((tab1, self.y - self.offset)) # File for recording speaker audio b = wx.Button(self, -1, "File...", pos=(tab3, self.y - self.offset)) self.Bind(wx.EVT_BUTTON, self.OnBtnFileAudio, b) x3, y3 = b.GetSizeTuple() tab4 = tab3 + x3 + charx self.static_audio = wx.StaticText(self, -1, self.text_audio + 'none', pos=(tab4, self.y)) self.y += self.dy # Transmit phase self.tx_phase = ctrl = wx.Button(self, -1, "Tx Phase...") self.Bind(wx.EVT_BUTTON, self.OnBtnPhase, ctrl) if not conf.name_of_mic_play: ctrl.Enable(0) tx.SetPosition((tab0, self.y)) ctrl.SetPosition((tab1, self.y - self.offset)) # File for recording samples b = wx.Button(self, -1, "File...", pos=(tab3, self.y - self.offset)) self.Bind(wx.EVT_BUTTON, self.OnBtnFileSamples, b) self.static_samples = wx.StaticText(self, -1, self.text_samples + 'none', pos=(tab4, self.y)) self.y += self.dy # Choice (combo) box for decimation lst = Hardware.VarDecimGetChoices() if lst: txt = Hardware.VarDecimGetLabel() index = Hardware.VarDecimGetIndex() else: txt = "Variable decimation" lst = ["None"] index = 0 t = wx.StaticText(self, -1, txt) ctrl = wx.Choice(self, -1, choices=lst, size=(x2, y2)) if lst: self.Bind(wx.EVT_CHOICE, application.OnBtnDecimation, ctrl) ctrl.SetSelection(index) t.SetPosition((tab0, self.y)) ctrl.SetPosition((tab1, self.y - self.offset)) self.y += self.dy # Transmit level controls if hasattr(Hardware, "SetTxLevel"): SliderBoxH(self, "Tx level %d%% ", 100, 0, 100, self.OnTxLevel, True, (tab0, self.y), tab2-tab0) level = conf.digital_tx_level SliderBoxH(self, "Digital Tx level %d%% ", level, 0, level, self.OnDigitalTxLevel, True, (tab3, self.y), tab2-tab0) self.y += self.dy def OnTxLevel(self, event): application.tx_level = event.GetEventObject().GetValue() Hardware.SetTxLevel() def OnDigitalTxLevel(self, event): application.digital_tx_level = event.GetEventObject().GetValue() Hardware.SetTxLevel() def OnBtnPhase(self, event): btn = event.GetEventObject() if btn.GetLabel()[0:2] == 'Tx': rx_tx = 'tx' else: rx_tx = 'rx' application.screenBtnGroup.SetLabel('Graph', do_cmd=True) if application.w_phase: application.w_phase.Raise() else: application.w_phase = QAdjustPhase(self, self.width, rx_tx) def OnBtnFileAudio(self, event): dlg = wx.FileDialog(self, 'Choose WAV file', style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT, wildcard="Wave files (*.wav)|*.wav") if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() if path[-4:].lower() != '.wav': path = path + '.wav' QS.set_file_record(0, path) application.btn_file_record.Enable() else: path = 'none' QS.set_file_record(0, '') self.static_audio.SetLabel(self.text_audio + path) dlg.Destroy() def OnBtnFileSamples(self, event): dlg = wx.FileDialog(self, 'Choose WAV file', style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT, wildcard="Wave files (*.wav)|*.wav") if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() if path[-4:].lower() != '.wav': path = path + '.wav' QS.set_file_record(1, path) application.btn_file_record.Enable() else: path = 'none' QS.set_file_record(1, '') self.static_samples.SetLabel(self.text_samples + path) dlg.Destroy() class ConfigSound(wx.Panel): """Display the available sound devices.""" def __init__(self, parent, width): wx.Panel.__init__(self, parent) self.Bind(wx.EVT_PAINT, self.OnPaint) self.width = width self.dev_capt, self.dev_play = QS.sound_devices() self.SetBackgroundColour(conf.color_graph) self.font = wx.Font(conf.config_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) self.charx = self.GetCharWidth() self.chary = self.GetCharHeight() self.dy = self.chary def OnPaint(self, event): dc = wx.PaintDC(self) dc.SetFont(self.font) dc.SetTextForeground(conf.color_graphlabels) x0 = self.charx self.y = self.chary / 3 dc.DrawText("Available devices for capture:", x0, self.y) self.y += self.dy for name in self.dev_capt: dc.DrawText(' ' + name, x0, self.y) self.y += self.dy dc.DrawText("Available devices for playback:", x0, self.y) self.y += self.dy for name in self.dev_play: dc.DrawText(' ' + name, x0, self.y) self.y += self.dy class ConfigFavorites(wx.grid.Grid): def __init__(self, parent, width): wx.grid.Grid.__init__(self, parent) self.changed = False self.SetBackgroundColour(conf.color_graph) font = wx.Font(conf.favorites_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_BOLD, face=conf.quisk_typeface) self.SetFont(font) self.SetLabelFont(font) font = wx.Font(conf.favorites_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetDefaultCellFont(font) self.SetDefaultRowSize(self.GetCharHeight()+3) self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.OnRightClickLabel) self.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnChange) self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_DCLICK, self.OnLeftDClick) self.CreateGrid(0, 4) self.EnableDragRowSize(False) w = self.GetTextExtent(' 999 ')[0] self.SetRowLabelSize(w) self.SetColLabelValue(0, 'Name') self.SetColLabelValue(1, 'Frequency') self.SetColLabelValue(2, 'Mode') self.SetColLabelValue(3, 'Description') w = self.GetTextExtent("xFrequencyx")[0] self.SetColSize(0, w * 3 / 2) self.SetColSize(1, w) self.SetColSize(2, w / 2) self.SetColSize(3, width - w * 3 - self.GetRowLabelSize() - 20) if conf.favorites_file_path: self.init_path = conf.favorites_file_path else: self.init_path = os.path.join(os.path.dirname(ConfigPath), 'quisk_favorites.txt') self.ReadIn() if self.GetNumberRows() < 1: self.AppendRows() # Make a popup menu self.popupmenu = wx.Menu() item = self.popupmenu.Append(-1, 'Tune to') self.Bind(wx.EVT_MENU, self.OnPopupTuneto, item) self.popupmenu.AppendSeparator() item = self.popupmenu.Append(-1, 'Append') self.Bind(wx.EVT_MENU, self.OnPopupAppend, item) item = self.popupmenu.Append(-1, 'Insert') self.Bind(wx.EVT_MENU, self.OnPopupInsert, item) item = self.popupmenu.Append(-1, 'Delete') self.Bind(wx.EVT_MENU, self.OnPopupDelete, item) self.popupmenu.AppendSeparator() item = self.popupmenu.Append(-1, 'Move Up') self.Bind(wx.EVT_MENU, self.OnPopupMoveUp, item) item = self.popupmenu.Append(-1, 'Move Down') self.Bind(wx.EVT_MENU, self.OnPopupMoveDown, item) # Make a timer self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.OnTimer) def ReadIn(self): try: fp = open(self.init_path, 'rb') lines = fp.readlines() fp.close() except: lines = ("my net|7210000|LSB|My net 2030 UTC every Thursday", "10m FM 1|29.620|FM|Fm local 10 meter repeater") for row in range(len(lines)): self.AppendRows() fields = lines[row].split('|') for col in range(len(fields)): self.SetCellValue(row, col, fields[col].strip()) def WriteOut(self): self.changed = False try: fp = open(self.init_path, 'wb') except: return for row in range(self.GetNumberRows()): t = self.GetCellValue(row, 0) for col in range(1, self.GetNumberCols()): cell = self.GetCellValue(row, col) cell = cell.replace('|', ';') t = "%s | %s" % (t, cell) t = t + '\r\n' fp.write(t) fp.close() def AddNewFavorite(self): self.InsertRows(0) self.SetCellValue(0, 0, 'New station'); self.SetCellValue(0, 1, str(application.rxFreq + application.VFO)) self.SetCellValue(0, 2, application.mode); self.OnChange() def OnRightClickLabel(self, event): event.Skip() self.menurow = event.GetRow() if self.menurow >= 0: pos = event.GetPosition() self.PopupMenu(self.popupmenu, pos) def OnLeftDClick(self, event): # Thanks to Christof, DJ4CM self.menurow = event.GetRow() self.OnPopupTuneto(event) def OnPopupAppend(self, event): self.InsertRows(self.menurow + 1) self.OnChange() def OnPopupInsert(self, event): self.InsertRows(self.menurow) self.OnChange() def OnPopupDelete(self, event): self.DeleteRows(self.menurow) if self.GetNumberRows() < 1: self.AppendRows() self.OnChange() def OnPopupMoveUp(self, event): row = self.menurow if row < 1: return for i in range(4): c = self.GetCellValue(row - 1, i) self.SetCellValue(row - 1, i, self.GetCellValue(row, i)) self.SetCellValue(row, i, c) def OnPopupMoveDown(self, event): row = self.menurow if row == self.GetNumberRows() - 1: return for i in range(4): c = self.GetCellValue(row + 1, i) self.SetCellValue(row + 1, i, self.GetCellValue(row, i)) self.SetCellValue(row, i, c) def OnPopupTuneto(self, event): freq = self.GetCellValue(self.menurow, 1) if not freq: return try: freq = str2freq (freq) except ValueError: print('Bad frequency') return if self.changed: if self.timer.IsRunning(): self.timer.Stop() self.WriteOut() application.ChangeRxTxFrequency(None, freq) mode = self.GetCellValue(self.menurow, 2) mode = mode.upper() application.OnBtnMode(None, mode) application.screenBtnGroup.SetLabel(conf.default_screen, do_cmd=True) def OnChange(self, event=None): self.changed = True if self.timer.IsRunning(): self.timer.Stop() self.timer.Start(5000, oneShot=True) def OnTimer(self, event): if self.changed: self.WriteOut() class GraphDisplay(wx.Window): """Display the FFT graph within the graph screen.""" def __init__(self, parent, x, y, graph_width, height, chary): wx.Window.__init__(self, parent, pos = (x, y), size = (graph_width, height), style = wx.NO_BORDER) self.parent = parent self.chary = chary self.graph_width = graph_width self.line = [(0, 0), (1,1)] # initial fake graph data self.SetBackgroundColour(conf.color_graph) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, parent.OnLeftDown) self.Bind(wx.EVT_RIGHT_DOWN, parent.OnRightDown) self.Bind(wx.EVT_LEFT_UP, parent.OnLeftUp) self.Bind(wx.EVT_MOTION, parent.OnMotion) self.Bind(wx.EVT_MOUSEWHEEL, parent.OnWheel) self.tune_tx = graph_width / 2 # Current X position of the Tx tuning line self.tune_rx = 0 # Current X position of Rx tuning line or zero self.scale = 20 # pixels per 10 dB self.peak_hold = 9999 # time constant for holding peak value self.height = 10 self.y_min = 1000 self.y_max = 0 self.max_height = application.screen_height self.tuningPenTx = wx.Pen(conf.color_txline, 1) self.tuningPenRx = wx.Pen(conf.color_rxline, 1) self.backgroundPen = wx.Pen(self.GetBackgroundColour(), 1) self.backgroundBrush = wx.Brush(self.GetBackgroundColour()) self.horizPen = wx.Pen(conf.color_gl, 1, wx.SOLID) if sys.platform == 'win32': self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter) # This code displays the filter bandwidth on the graph screen. It is based on code # provided by Terry Fox, WB4JFI. Thanks Terry! self.fltr_disp_size = 1 self.fltr_disp_tune = 0 bitmap = wx.EmptyBitmap(graph_width, self.max_height) self.fltr_disp_tx_dc = wx.MemoryDC() self.fltr_disp_tx_dc.SelectObject(bitmap) br = wx.Brush(conf.color_bandwidth, wx.SOLID) self.fltr_disp_tx_dc.SetBackground(br) self.fltr_disp_tx_dc.SetPen(self.tuningPenTx) self.fltr_disp_tx_dc.DrawLine(0, 0, 0, self.max_height) bitmap = wx.EmptyBitmap(graph_width, self.max_height) self.fltr_disp_rx_dc = wx.MemoryDC() self.fltr_disp_rx_dc.SelectObject(bitmap) br = wx.Brush(conf.color_bandwidth, wx.SOLID) self.fltr_disp_rx_dc.SetBackground(br) self.fltr_disp_rx_dc.SetPen(self.tuningPenRx) self.fltr_disp_rx_dc.DrawLine(0, 0, 0, self.max_height) def OnEnter(self, event): if not application.w_phase: self.SetFocus() # Set focus so we get mouse wheel events def OnPaint(self, event): #print 'GraphDisplay', self.GetUpdateRegion().GetBox() dc = wx.PaintDC(self) # Blit the tuning line and filter display to the screen dc.Blit(self.tune_tx - self.fltr_disp_tune, 0, self.fltr_disp_size, self.max_height, self.fltr_disp_tx_dc, 0, 0) if self.tune_rx: dc.Blit(self.tune_rx - self.fltr_disp_tune, 0, self.fltr_disp_size, self.max_height, self.fltr_disp_rx_dc, 0, 0) dc.SetPen(wx.Pen(conf.color_graphline, 1)) dc.DrawLines(self.line) dc.SetPen(self.horizPen) for y in self.parent.y_ticks: dc.DrawLine(0, y, self.graph_width, y) # y line def SetHeight(self, height): self.height = height self.SetSize((self.graph_width, height)) def OnGraphData(self, data): x = 0 for y in data: # y is in dB, -130 to 0 y = self.zeroDB - int(y * self.scale / 10.0 + 0.5) try: y0 = self.line[x][1] except IndexError: self.line.append([x, y]) else: if y > y0: y = min(y, y0 + self.peak_hold) self.line[x] = [x, y] x = x + 1 self.Refresh() def XXOnGraphData(self, data): line = [] x = 0 y_min = 1000 y_max = 0 for y in data: # y is in dB, -130 to 0 y = self.zeroDB - int(y * self.scale / 10.0 + 0.5) if y > y_max: y_max = y if y < y_min: y_min = y line.append((x, y)) x = x + 1 ymax = max(y_max, self.y_max) ymin = min(y_min, self.y_min) rect = wx.Rect(0, ymin, 1000, ymax - ymin) self.y_min = y_min self.y_max = y_max self.line = line self.Refresh() #rect=rect) def UpdateFilterDisplay(self, size, tune): # WB4JFI ADD - Update filter display self.fltr_disp_size = size self.fltr_disp_tune = tune self.fltr_disp_tx_dc.Clear() self.fltr_disp_tx_dc.DrawLine(tune, 0, tune, self.max_height) self.fltr_disp_rx_dc.Clear() self.fltr_disp_rx_dc.DrawLine(tune, 0, tune, self.max_height) def SetTuningLine(self, tune_tx, tune_rx): dc = wx.ClientDC(self) dc.SetPen(self.backgroundPen) dc.SetBrush(self.backgroundBrush) sz = self.fltr_disp_size xa = self.tune_tx - self.fltr_disp_tune dc.DrawRectangle(xa, 0, sz, self.max_height) xb = xa + sz if self.tune_rx: x = self.tune_rx - self.fltr_disp_tune dc.DrawRectangle(x, 0, sz, self.max_height) xa = min(xa, x) xb = max(xb, x + sz) x = tune_tx - self.fltr_disp_tune dc.Blit(x, 0, sz, self.max_height, self.fltr_disp_tx_dc, 0, 0) xa = min(xa, x) xb = max(xb, x + sz) if tune_rx: x = tune_rx - self.fltr_disp_tune dc.Blit(x, 0, sz, self.max_height, self.fltr_disp_rx_dc, 0, 0) xa = min(xa, x) xb = max(xb, x + sz) dc.SetPen(wx.Pen(conf.color_graphticks,1)) dc.DrawLines(self.line[xa:xb]) dc.SetPen(self.horizPen) for y in self.parent.y_ticks: dc.DrawLine(xa, y, xb, y) # y line self.tune_tx = tune_tx self.tune_rx = tune_rx class GraphScreen(wx.Window): """Display the graph screen X and Y axis, and create a graph display.""" def __init__(self, parent, data_width, graph_width, in_splitter=0): wx.Window.__init__(self, parent, pos = (0, 0)) self.in_splitter = in_splitter # Are we in the top of a splitter window? if in_splitter: self.y_scale = conf.waterfall_graph_y_scale self.y_zero = conf.waterfall_graph_y_zero else: self.y_scale = conf.graph_y_scale self.y_zero = conf.graph_y_zero self.y_ticks = [] self.VFO = 0 self.mouse_x = 0 self.WheelMod = conf.mouse_wheelmod # Round frequency when using mouse wheel self.txFreq = 0 self.sample_rate = application.sample_rate self.zoom = 1.0 self.zoom_deltaf = 0 self.data_width = data_width self.graph_width = graph_width self.doResize = False self.pen_tick = wx.Pen(conf.color_graphticks, 1) self.pen_label = wx.Pen(conf.color_graphlabels, 1) self.font = wx.Font(conf.graph_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) w = self.GetCharWidth() * 14 / 10 h = self.GetCharHeight() self.charx = w self.chary = h self.tick = max(2, h * 3 / 10) self.originX = w * 5 self.offsetY = h + self.tick self.width = self.originX + self.graph_width + self.tick + self.charx * 2 self.height = application.screen_height * 3 / 10 self.x0 = self.originX + self.graph_width / 2 # center of graph self.tuningX = self.x0 self.originY = 10 self.zeroDB = 10 # y location of zero dB; may be above the top of the graph self.scale = 10 self.SetSize((self.width, self.height)) self.SetSizeHints(self.width, 1, self.width) self.SetBackgroundColour(conf.color_graph) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMotion) self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel) self.MakeDisplay() def MakeDisplay(self): self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary) self.display.zeroDB = self.zeroDB def OnPaint(self, event): dc = wx.PaintDC(self) dc.SetFont(self.font) dc.SetTextForeground(conf.color_graphlabels) if self.in_splitter: self.MakeYTicks(dc) else: self.MakeYTicks(dc) self.MakeXTicks(dc) def OnIdle(self, event): if self.doResize: self.ResizeGraph() def OnSize(self, event): self.doResize = True event.Skip() def ResizeGraph(self): """Change the height of the graph. Changing the width interactively is not allowed because the FFT size is fixed. Call after changing the zero or scale to recalculate the X and Y axis marks. """ w, h = self.GetClientSize() if self.in_splitter: # Splitter window has no X axis scale self.height = h self.originY = h else: self.height = h - self.chary # Leave space for X scale self.originY = self.height - self.offsetY self.MakeYScale() self.display.SetHeight(self.originY) self.display.scale = self.scale self.doResize = False self.Refresh() def ChangeYscale(self, y_scale): self.y_scale = y_scale self.doResize = True def ChangeYzero(self, y_zero): self.y_zero = y_zero self.doResize = True def ChangeZoom(self, zoom, deltaf): self.zoom = zoom self.zoom_deltaf = deltaf self.doResize = True def MakeYScale(self): chary = self.chary scale = (self.originY - chary) * 10 / (self.y_scale + 20) # Number of pixels per 10 dB scale = max(1, scale) q = (self.originY - chary ) / scale / 2 zeroDB = chary + q * scale - self.y_zero * scale / 10 if zeroDB > chary: zeroDB = chary self.scale = scale self.zeroDB = zeroDB self.display.zeroDB = self.zeroDB QS.record_graph(self.originX, self.zeroDB, self.scale) def MakeYTicks(self, dc): chary = self.chary x1 = self.originX - self.tick * 3 # left of tick mark x2 = self.originX - 1 # x location of y axis x3 = self.originX + self.graph_width # end of graph data dc.SetPen(self.pen_tick) dc.DrawLine(x2, 0, x2, self.originY + 1) # y axis y = self.zeroDB del self.y_ticks[:] y_old = y for i in range(0, -99999, -10): if y >= chary / 2: dc.SetPen(self.pen_tick) dc.DrawLine(x1, y, x2, y) # y tick self.y_ticks.append(y) t = repr(i) w, h = dc.GetTextExtent(t) # draw text on Y axis if y - y_old > h: if y + h / 2 <= self.originY: dc.DrawText(repr(i), x1 - w, y - h / 2) elif h < self.scale: dc.DrawText(repr(i), x1 - w, self.originY - h) y_old = y y = y + self.scale if y >= self.originY - 3: break def MakeXTicks(self, dc): sample_rate = int(self.sample_rate * self.zoom) VFO = self.VFO + self.zoom_deltaf originY = self.originY x3 = self.originX + self.graph_width # end of fft data charx , z = dc.GetTextExtent('-30000XX') tick0 = self.tick tick1 = tick0 * 2 tick2 = tick0 * 3 # Draw the X axis dc.SetPen(self.pen_tick) dc.DrawLine(self.originX, originY, x3, originY) # Draw the band plan colors below the X axis x = self.originX f = float(x - self.x0) * sample_rate / self.data_width c = None y = originY + 1 for freq, color in conf.BandPlan: freq -= VFO if f < freq: xend = int(self.x0 + float(freq) * self.data_width / sample_rate + 0.5) if c is not None: dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(wx.Brush(c)) dc.DrawRectangle(x, y, min(x3, xend) - x, tick0) # x axis if xend >= x3: break x = xend f = freq c = color stick = 1000 # small tick in Hertz mtick = 5000 # medium tick ltick = 10000 # large tick # check the width of the frequency label versus frequency span df = charx * sample_rate / self.data_width if df < 1000: tfreq = 1000 # tick frequency for labels elif df < 5000: tfreq = 5000 # tick frequency for labels elif df < 10000: tfreq = 10000 elif df < 20000: tfreq = 20000 elif df < 50000: tfreq = 50000 stick = 5000 mtick = 10000 ltick = 50000 else: tfreq = 100000 stick = 5000 mtick = 10000 ltick = 50000 # Draw the X axis ticks and frequency in kHz dc.SetPen(self.pen_tick) freq1 = VFO - sample_rate / 2 freq1 = (freq1 / stick) * stick freq2 = freq1 + sample_rate + stick + 1 y_end = 0 for f in range (freq1, freq2, stick): x = self.x0 + int(float(f - VFO) / sample_rate * self.data_width) if self.originX <= x <= x3: if f % ltick is 0: # large tick dc.DrawLine(x, originY, x, originY + tick2) elif f % mtick is 0: # medium tick dc.DrawLine(x, originY, x, originY + tick1) else: # small tick dc.DrawLine(x, originY, x, originY + tick0) if f % tfreq is 0: # place frequency label t = str(f/1000) w, h = dc.GetTextExtent(t) dc.DrawText(t, x - w / 2, originY + tick2) y_end = originY + tick2 + h if y_end: # mark the center of the display dc.DrawLine(self.x0, y_end, self.x0, application.screen_height) def OnGraphData(self, data): i1 = (self.data_width - self.graph_width) / 2 i2 = i1 + self.graph_width self.display.OnGraphData(data[i1:i2]) def SetVFO(self, vfo): self.VFO = vfo self.doResize = True def SetTxFreq(self, tx_freq, rx_freq): sample_rate = int(self.sample_rate * self.zoom) self.txFreq = tx_freq tx_x = self.x0 + int(float(tx_freq - self.zoom_deltaf) / sample_rate * self.data_width) self.tuningX = tx_x rx_x = self.x0 + int(float(rx_freq - self.zoom_deltaf) / sample_rate * self.data_width) if abs(tx_x - rx_x) < 2: # Do not display Rx line for small frequency offset self.display.SetTuningLine(tx_x - self.originX, 0) else: self.display.SetTuningLine(tx_x - self.originX, rx_x - self.originX) def GetMousePosition(self, event): """For mouse clicks in our display, translate to our screen coordinates.""" mouse_x, mouse_y = event.GetPositionTuple() win = event.GetEventObject() if win is not self: x, y = win.GetPositionTuple() mouse_x += x mouse_y += y return mouse_x, mouse_y def FreqRound(self, tune, vfo): if conf.freq_spacing: freq = tune + vfo n = int(freq) - conf.freq_base if n >= 0: n = (n + conf.freq_spacing / 2) / conf.freq_spacing else: n = - ( - n + conf.freq_spacing / 2) / conf.freq_spacing freq = conf.freq_base + n * conf.freq_spacing return freq - vfo else: return tune def OnRightDown(self, event): sample_rate = int(self.sample_rate * self.zoom) VFO = self.VFO + self.zoom_deltaf mouse_x, mouse_y = self.GetMousePosition(event) freq = float(mouse_x - self.x0) * sample_rate / self.data_width freq = int(freq) if VFO > 0: vfo = VFO + freq - self.zoom_deltaf if sample_rate > 40000: vfo = (vfo + 5000) / 10000 * 10000 # round to even number elif sample_rate > 5000: vfo = (vfo + 500) / 1000 * 1000 else: vfo = (vfo + 50) / 100 * 100 tune = freq + VFO - vfo tune = self.FreqRound(tune, vfo) self.ChangeHwFrequency(tune, vfo, 'MouseBtn3', event) def OnLeftDown(self, event): sample_rate = int(self.sample_rate * self.zoom) mouse_x, mouse_y = self.GetMousePosition(event) self.mouse_x = mouse_x x = mouse_x - self.originX if self.display.tune_rx and abs(x - self.display.tune_tx) > abs(x - self.display.tune_rx): self.mouse_is_rx = True else: self.mouse_is_rx = False if mouse_y < self.originY: # click above X axis freq = float(mouse_x - self.x0) * sample_rate / self.data_width + self.zoom_deltaf freq = int(freq) if self.mouse_is_rx: application.rxFreq = freq application.screen.SetTxFreq(self.txFreq, freq) QS.set_tune(freq + application.ritFreq, self.txFreq) else: freq = self.FreqRound(freq, self.VFO) self.ChangeHwFrequency(freq, self.VFO, 'MouseBtn1', event) self.CaptureMouse() def OnLeftUp(self, event): if self.HasCapture(): self.ReleaseMouse() freq = self.FreqRound(self.txFreq, self.VFO) if freq != self.txFreq: self.ChangeHwFrequency(freq, self.VFO, 'MouseMotion', event) def OnMotion(self, event): sample_rate = int(self.sample_rate * self.zoom) if event.Dragging() and event.LeftIsDown(): mouse_x, mouse_y = self.GetMousePosition(event) if conf.mouse_tune_method: # Mouse motion changes the VFO frequency x = (mouse_x - self.mouse_x) # Thanks to VK6JBL self.mouse_x = mouse_x freq = x * sample_rate / self.data_width freq = int(freq) self.ChangeHwFrequency(self.txFreq, self.VFO - freq, 'MouseMotion', event) else: # Mouse motion changes the tuning frequency # Frequency changes more rapidly for higher mouse Y position speed = max(10, self.originY - mouse_y) / float(self.originY) x = (mouse_x - self.mouse_x) self.mouse_x = mouse_x freq = speed * x * sample_rate / self.data_width freq = int(freq) if self.mouse_is_rx: # Mouse motion changes the receive frequency application.rxFreq += freq application.screen.SetTxFreq(self.txFreq, application.rxFreq) QS.set_tune(application.rxFreq + application.ritFreq, self.txFreq) else: # Mouse motion changes the transmit frequency self.ChangeHwFrequency(self.txFreq + freq, self.VFO, 'MouseMotion', event) def OnWheel(self, event): if conf.freq_spacing: wm = conf.freq_spacing else: wm = self.WheelMod # Round frequency when using mouse wheel mouse_x, mouse_y = self.GetMousePosition(event) x = mouse_x - self.originX if self.display.tune_rx and abs(x - self.display.tune_tx) > abs(x - self.display.tune_rx): freq = application.rxFreq + self.VFO + wm * event.GetWheelRotation() / event.GetWheelDelta() if conf.freq_spacing: freq = self.FreqRound(freq, 0) elif freq >= 0: freq = freq / wm * wm else: # freq can be negative when the VFO is zero freq = - (- freq / wm * wm) tune = freq - self.VFO application.rxFreq = tune application.screen.SetTxFreq(self.txFreq, tune) QS.set_tune(tune + application.ritFreq, self.txFreq) else: freq = self.txFreq + self.VFO + wm * event.GetWheelRotation() / event.GetWheelDelta() if conf.freq_spacing: freq = self.FreqRound(freq, 0) elif freq >= 0: freq = freq / wm * wm else: # freq can be negative when the VFO is zero freq = - (- freq / wm * wm) tune = freq - self.VFO self.ChangeHwFrequency(tune, self.VFO, 'MouseWheel', event) def ChangeHwFrequency(self, tune, vfo, source, event): application.ChangeHwFrequency(tune, vfo, source, event) def PeakHold(self, name): if name == 'GraphP1': self.display.peak_hold = int(self.display.scale * conf.graph_peak_hold_1) elif name == 'GraphP2': self.display.peak_hold = int(self.display.scale * conf.graph_peak_hold_2) else: self.display.peak_hold = 9999 if self.display.peak_hold < 1: self.display.peak_hold = 1 class StationScreen(wx.Window): # This code was contributed by Christof, DJ4CM. Many Thanks!! """Create a window below the graph X axis to display interesting frequencies.""" def __init__(self, parent, width, lines): self.lineMargin = 2 self.lines = lines self.mouse_x = 0 graph = self.graph = application.graph height = lines * (graph.GetCharHeight() + self.lineMargin) # The height may be zero wx.Window.__init__(self, parent, size=(graph.width, height), style = wx.NO_BORDER) self.font = wx.Font(conf.graph_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) self.SetBackgroundColour(conf.color_graph) self.width = application.screen_width self.Bind(wx.EVT_PAINT, self.OnPaint) if lines: self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_MOTION, self.OnMotion) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) # handle station info self.stationWindow = wx.PopupWindow (parent) self.stationInfo = wx.richtext.RichTextCtrl(self.stationWindow) self.stationInfo.SetFont(wx.Font(conf.status_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface)) self.stationWindow.Hide(); self.firstStationInRange = None self.lastStationX = 0 self.nrStationInRange = 0 self.tunedStation = 0 def OnPaint(self, event): dc = wx.PaintDC(self) if not self.lines: return dc.SetFont(self.font) graph = self.graph dc.SetTextForeground(conf.color_graphlabels) dc.SetPen(graph.pen_tick) originX = graph.originX originY = graph.originY endX = originX + graph.graph_width # end of fft data sample_rate = int(graph.sample_rate * graph.zoom) VFO = graph.VFO + graph.zoom_deltaf hl = self.GetCharHeight() y = 0 for i in range (self.lines): dc.DrawLine(originX, y, endX, y) y += hl + self.lineMargin # create a sorted list of favorites in the frequency range freq1 = VFO - sample_rate / 2 freq2 = VFO + sample_rate / 2 self.stationList = [] fav = application.config_screen.favorites for row in range (fav.GetNumberRows()): fav_f = fav.GetCellValue(row, 1) if fav_f: try: fav_f = str2freq(fav_f) if freq1 < fav_f < freq2: self.stationList.append((fav_f, conf.Xsym_stat_fav, fav.GetCellValue(row, 0), fav.GetCellValue(row, 2), fav.GetCellValue(row, 3))) except ValueError: pass # add memory stations for mem_f, mem_band, mem_vfo, mem_txfreq, mem_mode in application.memoryState: if freq1 < mem_f < freq2: self.stationList.append((mem_f, conf.Xsym_stat_mem, '', mem_mode, '')) #add dx spots if application.dxCluster: for entry in application.dxCluster.dxSpots: if freq1 < entry.getFreq() < freq2: for i in range (0, entry.getLen()): descr = entry.getSpotter(i) + '\t' + entry.getTime(i) + '\t' + entry.getLocation(i) + '\n' + entry.getComment(i) if i < entry.getLen()-1: descr += '\n' self.stationList.append((entry.freq, conf.Xsym_stat_dx, entry.dx, '', descr)) # draw stations on graph self.stationList.sort(cmp=None, key=None, reverse=False) lastX = [] line = 0 for i in range (0, self.lines): lastX.append(graph.width) for statFreq, symbol, statName, statMode, statDscr in reversed (self.stationList): ws = dc.GetTextExtent(symbol)[0] statX = graph.x0 + int(float(statFreq - VFO) / sample_rate * graph.data_width) w, h = dc.GetTextExtent(statName) # shorten name until it fits into remaining space maxLen = 25 tName = statName while (w > lastX[line] - statX - ws - 4) and maxLen > 0: maxLen -= 1 tName = statName[:maxLen] + '..' w, h = dc.GetTextExtent(tName) dc.DrawLine(statX, line * (hl+self.lineMargin), statX, line * (hl+self.lineMargin) + 4) dc.DrawText(symbol + ' ' + tName, statX - ws/2, line * (hl+self.lineMargin) + self.lineMargin/2+1) lastX[line] = statX line = (line+1)%self.lines def OnLeftDown(self, event): if self.firstStationInRange != None: # tune to station if self.tunedStation >= self.nrStationInRange: self.tunedStation = 0 freq, symbol, name, mode, dscr = self.stationList[self.firstStationInRange+self.tunedStation] self.tunedStation += 1 if mode != '': # information about mode available mode = mode.upper() application.OnBtnMode(None, mode) application.ChangeRxTxFrequency(None, freq) def OnMotion(self, event): mouse_x, mouse_y = event.GetPositionTuple() x = (mouse_x - self.mouse_x) application.isTuning = False # show detailed station info if abs(self.lastStationX - mouse_x) > 30: self.firstStationInRange = None found = False graph = self.graph sample_rate = int(graph.sample_rate * graph.zoom) VFO = graph.VFO + graph.zoom_deltaf if abs(x) > 5: # ignore small mouse moves for index in range (0, len(self.stationList)): statFreq, symbol, statName, statMode, statDscr = self.stationList[index] statX = graph.x0 + int(float(statFreq - VFO) / sample_rate * graph.data_width) if abs(mouse_x-statX) < 10: self.lastStationX = mouse_x if found == False: self.firstStationInRange = index self.nrStationInRange = 0 self.stationInfo.Clear() found = True self.nrStationInRange += 1 attr = self.stationInfo.GetBasicStyle() attr.SetFlags(wx.TEXT_ATTR_TABS) attr.SetTabs((40, 400, 700)) self.stationInfo.SetBasicStyle(attr) self.stationInfo.BeginSymbolBullet(symbol, 0, 40) self.stationInfo.BeginBold() self.stationInfo.WriteText(statName + '\t') self.stationInfo.EndBold() self.stationInfo.WriteText (str(statFreq) + ' Hz\t' + statMode) self.stationInfo.Newline() self.stationInfo.EndSymbolBullet() self.stationInfo.BeginLeftIndent(40) if len(statDscr) > 0: self.stationInfo.WriteText(statDscr) self.stationInfo.Newline() self.stationInfo.EndLeftIndent() self.mouse_x = mouse_x if self.firstStationInRange != None: line = self.stationInfo.GetVisibleLineForCaretPosition(self.stationInfo.GetCaretPosition()) cy = line.GetAbsolutePosition()[1] self.stationWindow.SetClientSize((340, cy+2)) self.stationInfo.SetClientSize((340, cy+2)) # convert coordinates to screen sx, sy = self.ClientToScreenXY(mouse_x, mouse_y) w, h = self.stationInfo.GetClientSize() self.stationWindow.Move((sx - w * sx/graph.width, sy - h - 4)) if not self.stationWindow.IsShown(): self.stationWindow.Show() else: self.stationWindow.Hide() def OnLeaveWindow(self, event): self.stationWindow.Hide() class WaterfallDisplay(wx.Window): """Create a waterfall display within the waterfall screen.""" def __init__(self, parent, x, y, graph_width, height, margin): wx.Window.__init__(self, parent, pos = (x, y), size = (graph_width, height), style = wx.NO_BORDER) self.parent = parent self.graph_width = graph_width self.margin = margin self.height = 10 self.zoom = 1.0 self.zoom_deltaf = 0 self.rf_gain = 0 # Keep waterfall colors constant for variable RF gain self.sample_rate = application.sample_rate self.SetBackgroundColour('Black') self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, parent.OnLeftDown) self.Bind(wx.EVT_RIGHT_DOWN, parent.OnRightDown) self.Bind(wx.EVT_LEFT_UP, parent.OnLeftUp) self.Bind(wx.EVT_MOTION, parent.OnMotion) self.Bind(wx.EVT_MOUSEWHEEL, parent.OnWheel) self.tune_tx = graph_width / 2 # Current X position of the Tx tuning line self.tune_rx = 0 # Current X position of Rx tuning line or zero self.tuningPen = wx.Pen('White', 3) self.marginPen = wx.Pen(conf.color_graph, 1) # Size of top faster scroll region is (top_key + 2) * (top_key - 1) / 2 self.top_key = 8 self.top_size = (self.top_key + 2) * (self.top_key - 1) / 2 # Make the palette pal2 = conf.waterfallPalette red = [] green = [] blue = [] n = 0 for i in range(256): if i > pal2[n+1][0]: n = n + 1 red.append((i - pal2[n][0]) * (pal2[n+1][1] - pal2[n][1]) // (pal2[n+1][0] - pal2[n][0]) + pal2[n][1]) green.append((i - pal2[n][0]) * (pal2[n+1][2] - pal2[n][2]) // (pal2[n+1][0] - pal2[n][0]) + pal2[n][2]) blue.append((i - pal2[n][0]) * (pal2[n+1][3] - pal2[n][3]) // (pal2[n+1][0] - pal2[n][0]) + pal2[n][3]) self.red = red self.green = green self.blue = blue bmp = wx.EmptyBitmap(0, 0) bmp.x_origin = 0 self.bitmaps = [bmp] * application.screen_height if sys.platform == 'win32': self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter) def OnEnter(self, event): if not application.w_phase: self.SetFocus() # Set focus so we get mouse wheel events def OnPaint(self, event): sample_rate = int(self.sample_rate * self.zoom) dc = wx.BufferedPaintDC(self) dc.SetTextForeground(conf.color_graphlabels) dc.SetBackground(wx.Brush('Black')) dc.Clear() y = 0 dc.SetPen(self.marginPen) x_origin = int(float(self.VFO) / sample_rate * self.data_width + 0.5) for i in range(0, self.margin): dc.DrawLine(0, y, self.graph_width, y) y += 1 index = 0 if conf.waterfall_scroll_mode: # Draw the first few lines multiple times for i in range(self.top_key, 1, -1): b = self.bitmaps[index] x = b.x_origin - x_origin for j in range(0, i): dc.DrawBitmap(b, x, y) y += 1 index += 1 while y < self.height: b = self.bitmaps[index] x = b.x_origin - x_origin dc.DrawBitmap(b, x, y) y += 1 index += 1 dc.SetPen(self.tuningPen) dc.SetLogicalFunction(wx.XOR) dc.DrawLine(self.tune_tx, 0, self.tune_tx, self.height) if self.tune_rx: dc.DrawLine(self.tune_rx, 0, self.tune_rx, self.height) def SetHeight(self, height): self.height = height self.SetSize((self.graph_width, height)) def OnGraphData(self, data, y_zero, y_scale): sample_rate = int(self.sample_rate * self.zoom) #T('graph start') row = '' # Make a new row of pixels for a one-line image gain = self.rf_gain for x in data: # x is -130 to 0, or so (dB) l = int((x - gain + y_zero / 3 + 100) * y_scale / 10) l = max(l, 0) l = min(l, 255) row = row + "%c%c%c" % (chr(self.red[l]), chr(self.green[l]), chr(self.blue[l])) #T('graph string') bmp = wx.BitmapFromBuffer(len(row) / 3, 1, row) bmp.x_origin = int(float(self.VFO) / sample_rate * self.data_width + 0.5) self.bitmaps.insert(0, bmp) del self.bitmaps[-1] #self.ScrollWindow(0, 1, None) #self.Refresh(False, (0, 0, self.graph_width, self.top_size + self.margin)) self.Refresh(False) #T('graph end') def SetTuningLine(self, tune_tx, tune_rx): dc = wx.ClientDC(self) dc.SetPen(self.tuningPen) dc.SetLogicalFunction(wx.XOR) dc.DrawLine(self.tune_tx, 0, self.tune_tx, self.height) if self.tune_rx: dc.DrawLine(self.tune_rx, 0, self.tune_rx, self.height) dc.DrawLine(tune_tx, 0, tune_tx, self.height) if tune_rx: dc.DrawLine(tune_rx, 0, tune_rx, self.height) self.tune_tx = tune_tx self.tune_rx = tune_rx def ChangeZoom(self, zoom, deltaf): self.zoom = zoom self.zoom_deltaf = deltaf class WaterfallScreen(wx.SplitterWindow): """Create a splitter window with a graph screen and a waterfall screen""" def __init__(self, frame, width, data_width, graph_width): self.y_scale = conf.waterfall_y_scale self.y_zero = conf.waterfall_y_zero wx.SplitterWindow.__init__(self, frame) self.SetSizeHints(width, -1, width) self.SetMinimumPaneSize(1) self.SetSize((width, conf.waterfall_graph_size + 100)) # be able to set sash size self.pane1 = GraphScreen(self, data_width, graph_width, 1) self.pane2 = WaterfallPane(self, data_width, graph_width) self.SplitHorizontally(self.pane1, self.pane2, conf.waterfall_graph_size) def OnIdle(self, event): self.pane1.OnIdle(event) self.pane2.OnIdle(event) def SetTxFreq(self, tx_freq, rx_freq): self.pane1.SetTxFreq(tx_freq, rx_freq) self.pane2.SetTxFreq(tx_freq, rx_freq) def SetVFO(self, vfo): self.pane1.SetVFO(vfo) self.pane2.SetVFO(vfo) def ChangeYscale(self, y_scale): # Test if the shift key is down if wx.GetKeyState(wx.WXK_SHIFT): # Set graph screen self.pane1.ChangeYscale(y_scale) else: # Set waterfall screen self.y_scale = y_scale self.pane2.ChangeYscale(y_scale) def ChangeYzero(self, y_zero): # Test if the shift key is down if wx.GetKeyState(wx.WXK_SHIFT): # Set graph screen self.pane1.ChangeYzero(y_zero) else: # Set waterfall screen self.y_zero = y_zero self.pane2.ChangeYzero(y_zero) def OnGraphData(self, data): self.pane1.OnGraphData(data) self.pane2.OnGraphData(data) def ChangeRfGain(self, gain): # Set the correction for RF gain self.pane2.display.rf_gain = gain class WaterfallPane(GraphScreen): """Create a waterfall screen with an X axis and a waterfall display.""" def __init__(self, frame, data_width, graph_width): GraphScreen.__init__(self, frame, data_width, graph_width) self.y_scale = conf.waterfall_y_scale self.y_zero = conf.waterfall_y_zero self.oldVFO = self.VFO def MakeDisplay(self): self.display = WaterfallDisplay(self, self.originX, 0, self.graph_width, 5, self.chary) self.display.VFO = self.VFO self.display.data_width = self.data_width def SetVFO(self, vfo): GraphScreen.SetVFO(self, vfo) self.display.VFO = vfo if self.oldVFO != vfo: self.oldVFO = vfo self.Refresh() def MakeYTicks(self, dc): pass def ChangeYscale(self, y_scale): self.y_scale = y_scale def ChangeYzero(self, y_zero): self.y_zero = y_zero def OnGraphData(self, data): i1 = (self.data_width - self.graph_width) / 2 i2 = i1 + self.graph_width self.display.OnGraphData(data[i1:i2], self.y_zero, self.y_scale) class ScopeScreen(wx.Window): """Create an oscilloscope screen (mostly used for debug).""" def __init__(self, parent, width, data_width, graph_width): wx.Window.__init__(self, parent, pos = (0, 0), size=(width, -1), style = wx.NO_BORDER) self.SetBackgroundColour(conf.color_graph) self.font = wx.Font(conf.config_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.horizPen = wx.Pen(conf.color_gl, 1, wx.SOLID) self.y_scale = conf.scope_y_scale self.y_zero = conf.scope_y_zero self.running = 1 self.doResize = False self.width = width self.height = 100 self.originY = self.height / 2 self.data_width = data_width self.graph_width = graph_width w = self.charx = self.GetCharWidth() h = self.chary = self.GetCharHeight() tick = max(2, h * 3 / 10) self.originX = w * 3 self.width = self.originX + self.graph_width + tick + self.charx * 2 self.line = [(0,0), (1,1)] # initial fake graph data self.fpout = None #open("jim96.txt", "w") def OnIdle(self, event): if self.doResize: self.ResizeGraph() def OnSize(self, event): self.doResize = True event.Skip() def ResizeGraph(self, event=None): # Change the height of the graph. Changing the width interactively is not allowed. w, h = self.GetClientSize() self.height = h self.originY = h / 2 self.doResize = False self.Refresh() def OnPaint(self, event): dc = wx.PaintDC(self) dc.SetFont(self.font) dc.SetTextForeground(conf.color_graphlabels) self.MakeYTicks(dc) self.MakeXTicks(dc) self.MakeText(dc) dc.SetPen(wx.Pen(conf.color_graphline, 1)) dc.DrawLines(self.line) def MakeYTicks(self, dc): chary = self.chary originX = self.originX x3 = self.x3 = originX + self.graph_width # end of graph data dc.SetPen(wx.Pen(conf.color_graphticks,1)) dc.DrawLine(originX, 0, originX, self.originY * 3) # y axis # Find the size of the Y scale markings themax = 2.5e9 * 10.0 ** - ((160 - self.y_scale) / 50.0) # value at top of screen themax = int(themax) l = [] for j in (5, 6, 7, 8): for i in (1, 2, 5): l.append(i * 10 ** j) for yvalue in l: n = themax / yvalue + 1 # Number of lines ypixels = self.height / n if n < 20: break dc.SetPen(self.horizPen) for i in range(1, 1000): y = self.originY - ypixels * i if y < chary: break # Above axis dc.DrawLine(originX, y, x3, y) # y line # Below axis y = self.originY + ypixels * i dc.DrawLine(originX, y, x3, y) # y line self.yscale = float(ypixels) / yvalue self.yvalue = yvalue def MakeXTicks(self, dc): originY = self.originY x3 = self.x3 # Draw the X axis dc.SetPen(wx.Pen(conf.color_graphticks,1)) dc.DrawLine(self.originX, originY, x3, originY) # Find the size of the X scale markings in microseconds for i in (20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000): xscale = i # X scale in microseconds if application.sample_rate * xscale * 0.000001 > self.width / 30: break # Draw the X lines dc.SetPen(self.horizPen) for i in range(1, 999): x = int(self.originX + application.sample_rate * xscale * 0.000001 * i + 0.5) if x > x3: break dc.DrawLine(x, 0, x, self.height) # x line self.xscale = xscale def MakeText(self, dc): if self.running: t = " RUN" else: t = " STOP" if self.xscale >= 1000: t = "%s X: %d millisec/div" % (t, self.xscale / 1000) else: t = "%s X: %d microsec/div" % (t, self.xscale) t = "%s Y: %.0E/div" % (t, self.yvalue) dc.DrawText(t, self.originX, self.height - self.chary) def OnGraphData(self, data): if not self.running: if self.fpout: for cpx in data: re = int(cpx.real) im = int(cpx.imag) ab = int(abs(cpx)) ph = math.atan2(im, re) * 360. / (2.0 * math.pi) self.fpout.write("%12d %12d %12d %12.1d\n" % (re, im, ab, ph)) return # Preserve data on screen line = [] x = self.originX ymax = self.height for cpx in data: # cpx is complex raw samples +/- 0 to 2**31-1 y = cpx.real #y = abs(cpx) y = self.originY - int(y * self.yscale + 0.5) if y > ymax: y = ymax elif y < 0: y = 0 line.append((x, y)) x = x + 1 self.line = line self.Refresh() def ChangeYscale(self, y_scale): self.y_scale = y_scale self.doResize = True def ChangeYzero(self, y_zero): self.y_zero = y_zero def SetTxFreq(self, tx_freq, rx_freq): pass class FilterScreen(GraphScreen): """Create a graph of the receive filter response.""" def __init__(self, parent, data_width, graph_width): GraphScreen.__init__(self, parent, data_width, graph_width) self.y_scale = conf.filter_y_scale self.y_zero = conf.filter_y_zero self.VFO = 0 self.txFreq = 0 self.data = [] self.sample_rate = QS.get_filter_rate() def NewFilter(self): self.sample_rate = QS.get_filter_rate() self.data = QS.get_filter() #self.data = QS.get_tx_filter() self.doResize = True def OnGraphData(self, data): GraphScreen.OnGraphData(self, self.data) def ChangeHwFrequency(self, tune, vfo, source, event): GraphScreen.SetTxFreq(self, tune, tune) application.freqDisplay.Display(tune) def SetTxFreq(self, tx_freq, rx_freq): pass class HelpScreen(wx.html.HtmlWindow): """Create the screen for the Help button.""" def __init__(self, parent, width, height): wx.html.HtmlWindow.__init__(self, parent, -1, size=(width, height)) self.y_scale = 0 self.y_zero = 0 if "gtk2" in wx.PlatformInfo: self.SetStandardFonts() self.SetFonts("", "", [10, 12, 14, 16, 18, 20, 22]) # read in text from file help.html in the directory of this module self.LoadFile('help.html') def OnGraphData(self, data): pass def ChangeYscale(self, y_scale): pass def ChangeYzero(self, y_zero): pass def OnIdle(self, event): pass def SetTxFreq(self, tx_freq, rx_freq): pass def OnLinkClicked(self, link): webbrowser.open(link.GetHref(), new=2) class QMainFrame(wx.Frame): """Create the main top-level window.""" def __init__(self, width, height): fp = open('__init__.py') # Read in the title title = fp.readline().strip()[1:] fp.close() wx.Frame.__init__(self, None, -1, title, wx.DefaultPosition, (width, height), wx.DEFAULT_FRAME_STYLE, 'MainFrame') self.SetBackgroundColour(conf.color_bg) self.Bind(wx.EVT_CLOSE, self.OnBtnClose) def OnBtnClose(self, event): application.OnBtnClose(event) self.Destroy() ## Note: The new amplitude/phase adjustments have ideas provided by Andrew Nilsson, VK6JBL class QAdjustPhase(wx.Frame): """Create a window with amplitude and phase adjustment controls""" f_ampl = "Amplitude adjustment %.6f" f_phase = "Phase adjustment degrees %.6f" def __init__(self, parent, width, rx_tx): self.rx_tx = rx_tx # Must be "rx" or "tx" if rx_tx == 'tx': self.is_tx = 1 t = "Adjust Sound Card Transmit Amplitude and Phase" else: self.is_tx = 0 t = "Adjust Sound Card Receive Amplitude and Phase" wx.Frame.__init__(self, application.main_frame, -1, t, pos=(50, 100), style=wx.CAPTION) panel = wx.Panel(self) self.MakeControls(panel, width) self.Show() def MakeControls(self, panel, width): # Make controls for phase/amplitude adjustment self.old_amplitude, self.old_phase = application.GetAmplPhase(self.is_tx) self.new_amplitude, self.new_phase = self.old_amplitude, self.old_phase sl_max = width * 4 / 10 # maximum +/- value for slider self.ampl_scale = float(conf.rx_max_amplitude_correct) / sl_max self.phase_scale = float(conf.rx_max_phase_correct) / sl_max font = wx.Font(conf.default_font_size, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) chary = self.GetCharHeight() y = chary * 3 / 10 # Print available data points if "panadapter" in conf.bandAmplPhase: self.band = "panadapter" else: self.band = application.lastBand app_vfo = (application.VFO + 500) / 1000 ap = application.bandAmplPhase if self.band not in ap: ap[self.band] = {} if self.rx_tx not in ap[self.band]: ap[self.band][self.rx_tx] = [] lst = ap[self.band][self.rx_tx] freq_in_list = False if lst: t = "Band %s: VFO" % self.band for l in lst: vfo = (l[0] + 500) / 1000 if vfo == app_vfo: freq_in_list = True t = t + (" %d" % vfo) else: t = "Band %s: No data." % self.band txt = wx.StaticText(panel, -1, t, pos=(0, y)) txt.SetFont(font) y += txt.GetSizeTuple()[1] self.t_ampl = wx.StaticText(panel, -1, self.f_ampl % self.old_amplitude, pos=(0, y)) self.t_ampl.SetFont(font) y += self.t_ampl.GetSizeTuple()[1] self.ampl1 = wx.Slider(panel, -1, 0, -sl_max, sl_max, pos=(0, y), size=(width, -1)) y += self.ampl1.GetSizeTuple()[1] self.ampl2 = wx.Slider(panel, -1, 0, -sl_max, sl_max, pos=(0, y), size=(width, -1)) y += self.ampl2.GetSizeTuple()[1] self.PosAmpl(self.old_amplitude) self.t_phase = wx.StaticText(panel, -1, self.f_phase % self.old_phase, pos=(0, y)) self.t_phase.SetFont(font) y += self.t_phase.GetSizeTuple()[1] self.phase1 = wx.Slider(panel, -1, 0, -sl_max, sl_max, pos=(0, y), size=(width, -1)) y += self.phase1.GetSizeTuple()[1] self.phase2 = wx.Slider(panel, -1, 0, -sl_max, sl_max, pos=(0, y), size=(width, -1)) y += self.phase2.GetSizeTuple()[1] sv = QuiskPushbutton(panel, self.OnBtnSave, 'Save %d' % app_vfo) ds = QuiskPushbutton(panel, self.OnBtnDiscard, 'Destroy %d' % app_vfo) cn = QuiskPushbutton(panel, self.OnBtnCancel, 'Cancel') w, h = ds.GetSizeTuple() sv.SetSize((w, h)) cn.SetSize((w, h)) y += h / 4 x = (width - w * 3) / 4 sv.SetPosition((x, y)) ds.SetPosition((x*2 + w, y)) cn.SetPosition((x*3 + w*2, y)) sv.SetBackgroundColour('light blue') ds.SetBackgroundColour('light blue') cn.SetBackgroundColour('light blue') if not freq_in_list: ds.Disable() y += h y += h / 4 self.ampl1.SetBackgroundColour('aquamarine') self.ampl2.SetBackgroundColour('orange') self.phase1.SetBackgroundColour('aquamarine') self.phase2.SetBackgroundColour('orange') self.PosPhase(self.old_phase) self.SetClientSizeWH(width, y) self.ampl1.Bind(wx.EVT_SCROLL, self.OnChange) self.ampl2.Bind(wx.EVT_SCROLL, self.OnAmpl2) self.phase1.Bind(wx.EVT_SCROLL, self.OnChange) self.phase2.Bind(wx.EVT_SCROLL, self.OnPhase2) def PosAmpl(self, ampl): # set pos1, pos2 for amplitude pos2 = round(ampl / self.ampl_scale) remain = ampl - pos2 * self.ampl_scale pos1 = round(remain / self.ampl_scale * 50.0) self.ampl1.SetValue(pos1) self.ampl2.SetValue(pos2) def PosPhase(self, phase): # set pos1, pos2 for phase pos2 = round(phase / self.phase_scale) remain = phase - pos2 * self.phase_scale pos1 = round(remain / self.phase_scale * 50.0) self.phase1.SetValue(pos1) self.phase2.SetValue(pos2) def OnChange(self, event): ampl = self.ampl_scale * self.ampl1.GetValue() / 50.0 + self.ampl_scale * self.ampl2.GetValue() if abs(ampl) < self.ampl_scale * 3.0 / 50.0: ampl = 0.0 self.t_ampl.SetLabel(self.f_ampl % ampl) phase = self.phase_scale * self.phase1.GetValue() / 50.0 + self.phase_scale * self.phase2.GetValue() if abs(phase) < self.phase_scale * 3.0 / 50.0: phase = 0.0 self.t_phase.SetLabel(self.f_phase % phase) QS.set_ampl_phase(ampl, phase, self.is_tx) self.new_amplitude, self.new_phase = ampl, phase def OnAmpl2(self, event): # re-center the fine slider when the coarse slider is adjusted ampl = self.ampl_scale * self.ampl1.GetValue() / 50.0 + self.ampl_scale * self.ampl2.GetValue() self.PosAmpl(ampl) self.OnChange(event) def OnPhase2(self, event): # re-center the fine slider when the coarse slider is adjusted phase = self.phase_scale * self.phase1.GetValue() / 50.0 + self.phase_scale * self.phase2.GetValue() self.PosPhase(phase) self.OnChange(event) def DeleteEqual(self): # Remove entry with the same VFO ap = application.bandAmplPhase lst = ap[self.band][self.rx_tx] vfo = (application.VFO + 500) / 1000 for i in range(len(lst)-1, -1, -1): if (lst[i][0] + 500) / 1000 == vfo: del lst[i] def OnBtnSave(self, event): data = (application.VFO, application.rxFreq, self.new_amplitude, self.new_phase) self.DeleteEqual() ap = application.bandAmplPhase lst = ap[self.band][self.rx_tx] lst.append(data) lst.sort() application.w_phase = None self.Destroy() def OnBtnDiscard(self, event): self.DeleteEqual() self.OnBtnCancel() def OnBtnCancel(self, event=None): QS.set_ampl_phase(self.old_amplitude, self.old_phase, self.is_tx) application.w_phase = None self.Destroy() class Spacer(wx.Window): """Create a bar between the graph screen and the controls""" def __init__(self, parent): wx.Window.__init__(self, parent, pos = (0, 0), size=(-1, 6), style = wx.NO_BORDER) self.Bind(wx.EVT_PAINT, self.OnPaint) r, g, b = parent.GetBackgroundColour().Get() dark = (r * 7 / 10, g * 7 / 10, b * 7 / 10) light = (r + (255 - r) * 5 / 10, g + (255 - g) * 5 / 10, b + (255 - b) * 5 / 10) self.dark_pen = wx.Pen(dark, 1, wx.SOLID) self.light_pen = wx.Pen(light, 1, wx.SOLID) self.width = application.screen_width def OnPaint(self, event): dc = wx.PaintDC(self) w = self.width dc.SetPen(self.dark_pen) dc.DrawLine(0, 0, w, 0) dc.DrawLine(0, 1, w, 1) dc.DrawLine(0, 2, w, 2) dc.SetPen(self.light_pen) dc.DrawLine(0, 3, w, 3) dc.DrawLine(0, 4, w, 4) dc.DrawLine(0, 5, w, 5) class App(wx.App): """Class representing the application.""" StateNames = [ # Names of state attributes to save and restore 'bandState', 'bandAmplPhase', 'lastBand', 'VFO', 'txFreq', 'mode', 'vardecim_set', 'filterAdjBw1', 'levelAGC', 'volumeAudio', 'levelSpot', 'levelSquelch'] def __init__(self): global application application = self self.init_path = None self.bottom_widgets = None self.dxCluster = None if sys.stdout.isatty(): wx.App.__init__(self, redirect=False) else: wx.App.__init__(self, redirect=True) def QuiskText(self, *args, **kw): # Make our text control available to widget files return QuiskText(*args, **kw) def QuiskPushbutton(self, *args, **kw): # Make our buttons available to widget files return QuiskPushbutton(*args, **kw) def QuiskRepeatbutton(self, *args, **kw): return QuiskRepeatbutton(*args, **kw) def QuiskCheckbutton(self, *args, **kw): return QuiskCheckbutton(*args, **kw) def QuiskCycleCheckbutton(self, *args, **kw): return QuiskCycleCheckbutton(*args, **kw) def RadioButtonGroup(self, *args, **kw): return RadioButtonGroup(*args, **kw) def OnInit(self): """Perform most initialization of the app here (called by wxPython on startup).""" wx.lib.colourdb.updateColourDB() # Add additional color names import quisk_widgets # quisk_widgets needs the application object quisk_widgets.application = self del quisk_widgets global conf # conf is the module for all configuration data import quisk_conf_defaults as conf setattr(conf, 'config_file_path', ConfigPath) if os.path.isfile(ConfigPath): # See if the user has a config file setattr(conf, 'config_file_exists', True) d = {} d.update(conf.__dict__) # make items from conf available exec(compile(open(ConfigPath).read(), ConfigPath, 'exec'), d) # execute the user's config file if os.path.isfile(ConfigPath2): # See if the user has a second config file exec(compile(open(ConfigPath2).read(), ConfigPath2, 'exec'), d) # execute the user's second config file for k, v in d.items(): # add user's config items to conf if k[0] != '_': # omit items starting with '_' setattr(conf, k, v) else: setattr(conf, 'config_file_exists', False) # Choose whether to use Unicode or text symbols for k in ('sym_stat_mem', 'sym_stat_fav', 'sym_stat_dx', 'btn_text_range_dn', 'btn_text_range_up', 'btn_text_play', 'btn_text_rec', 'btn_text_file_rec', 'btn_text_fav_add', 'btn_text_fav_recall', 'btn_text_mem_add', 'btn_text_mem_next', 'btn_text_mem_del'): if conf.use_unicode_symbols: setattr(conf, 'X' + k, getattr(conf, 'U' + k)) else: setattr(conf, 'X' + k, getattr(conf, 'T' + k)) if conf.invertSpectrum: QS.invert_spectrum(1) self.bandState = {} # for key band, the current (self.VFO, self.txFreq, self.mode) self.bandState.update(conf.bandState) self.memoryState = [] # a list of (freq, band, self.VFO, self.txFreq, self.mode) self.bandAmplPhase = conf.bandAmplPhase # Open hardware file global Hardware if hasattr(conf, "Hardware"): # Hardware defined in config file Hardware = conf.Hardware(self, conf) else: Hardware = conf.quisk_hardware.Hardware(self, conf) self.Hardware = Hardware # Initialization - may be over-written by persistent state self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow self.smeter_db_count = 0 # average the S-meter self.smeter_db_sum = 0 self.smeter_db = 0 self.smeter_sunits = -87.0 self.smeter_frequency = False # use s-meter display for frequency measurement self.timer = time.time() # A seconds clock self.heart_time0 = self.timer # timer to call HeartBeat at intervals self.save_time0 = self.timer self.smeter_db_time0 = self.timer self.smeter_sunits_time0 = self.timer self.band_up_down = 0 # Are band Up/Down buttons in use? self.lastBand = 'Audio' self.filterAdjBw1 = 1000 self.levelAGC = 200 # AGC level control, 0 to 1000 self.use_AGC = 1 # AGC is in use self.levelSquelch = 500 # FM squelch level, 0 to 1000 self.use_squelch = 1 # squelch is in use self.levelSpot = 500 # Spot level control, 10 to 1000 self.volumeAudio = 300 # audio volume self.VFO = 0 # frequency of the VFO self.ritFreq = 0 # receive incremental tuning frequency offset self.txFreq = 0 # Transmit frequency as +/- sample_rate/2 self.rxFreq = 0 # Receive frequency as +/- sample_rate/2 self.tx_level = 100 # initially 100% self.digital_tx_level = conf.digital_tx_level # Quisk control by Hamlib through rig 2 self.hamlib_clients = [] # list of TCP connections to handle if conf.hamlib_port: try: self.hamlib_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.hamlib_socket.bind(('localhost', conf.hamlib_port)) self.hamlib_socket.settimeout(0.0) self.hamlib_socket.listen(0) # listen for TCP connections from multiple clients except: self.hamlib_socket = None # traceback.print_exc() else: self.hamlib_socket = None # Quisk control by fldigi self.fldigi_new_freq = None self.fldigi_freq = None if conf.digital_xmlrpc_url: self.fldigi_server = ServerProxy(conf.digital_xmlrpc_url) else: self.fldigi_server = None self.fldigi_rxtx = 'rx' self.fldigi_timer = 0 self.oldRxFreq = 0 # Last value of self.rxFreq self.screen = None self.audio_volume = 0.0 # Set output volume, 0.0 to 1.0 self.sidetone_volume = 0 self.sound_error = 0 self.sound_thread = None self.mode = conf.default_mode self.color_list = None self.color_index = 0 self.vardecim_set = None self.w_phase = None self.zoom = 1.0 self.filter_bandwidth = 1000 self.zoom_deltaf = 0 self.zooming = False self.split_rxtx = False # Are we in split Rx/Tx mode? self.savedState = {} self.pttButton = None self.tmp_playing = False # get the screen size - thanks to Lucian Langa x, y, self.screen_width, self.screen_height = wx.Display().GetGeometry() self.Bind(wx.EVT_IDLE, self.OnIdle) self.Bind(wx.EVT_QUERY_END_SESSION, self.OnEndSession) # Restore persistent program state if conf.persistent_state: self.init_path = os.path.join(os.path.dirname(ConfigPath), '.quisk_init.pkl') try: fp = open(self.init_path, "rb") d = pickle.load(fp) fp.close() for k, v in d.items(): if k in self.StateNames: self.savedState[k] = v if k == 'bandState': self.bandState.update(v) else: setattr(self, k, v) except: pass #traceback.print_exc() for k, (vfo, tune, mode) in self.bandState.items(): # Historical: fix bad frequencies try: f1, f2 = conf.BandEdge[k] if not f1 <= vfo + tune <= f2: self.bandState[k] = conf.bandState[k] except KeyError: pass if self.bandAmplPhase and type(self.bandAmplPhase.values()[0]) is not DictType: print("""Old sound card amplitude and phase corrections must be re-entered (sorry). The new code supports multiple corrections per band.""") self.bandAmplPhase = {} if Hardware.VarDecimGetChoices(): # Hardware can change the decimation. self.sample_rate = Hardware.VarDecimSet() # Get the sample rate. self.vardecim_set = self.sample_rate else: # Use the sample rate from the config file. self.sample_rate = conf.sample_rate if not hasattr(conf, 'playback_rate'): if conf.use_sdriq or conf.use_rx_udp: conf.playback_rate = 48000 else: conf.playback_rate = conf.sample_rate # Find the data width from a list of prefered sizes; it is the width of returned graph data. # The graph_width is the width of data_width that is displayed. width = self.screen_width * conf.graph_width percent = conf.display_fraction # display central fraction of total width percent = int(percent * 100.0 + 0.4) width = width * 100 / percent for x in fftPreferedSizes: if x > width: self.data_width = x break else: self.data_width = fftPreferedSizes[-1] self.graph_width = self.data_width * percent / 100 if self.graph_width % 2 == 1: # Both data_width and graph_width are even numbers self.graph_width += 1 # The FFT size times the average_count controls the graph refresh rate factor = float(self.sample_rate) / conf.graph_refresh / self.data_width ifactor = int(factor + 0.5) if conf.fft_size_multiplier >= ifactor: # Use large FFT and average count 1 fft_mult = ifactor average_count = 1 elif conf.fft_size_multiplier > 0: # Specified fft_size_multiplier fft_mult = conf.fft_size_multiplier average_count = int(factor / fft_mult + 0.5) if average_count < 1: average_count = 1 else: # Calculate the split between fft size and average if self.sample_rate <= 240000: maxfft = 8000 # Maximum fft size else: maxfft = 15000 fft1 = maxfft / self.data_width if fft1 >= ifactor: fft_mult = ifactor average_count = 1 else: av1 = int(factor / fft1 + 0.5) if av1 < 1: av1 = 1 err1 = factor / (fft1 * av1) av2 = av1 + 1 fft2 = int(factor / av2 + 0.5) err2 = factor / (fft2 * av2) if 0.9 < err1 < 1.1 or abs(1.0 - err1) <= abs(1.0 - err2): fft_mult = fft1 average_count = av1 else: fft_mult = fft2 average_count = av2 self.fft_size = self.data_width * fft_mult # print 'data, graph,fft', self.data_width, self.graph_width, self.fft_size self.width = self.screen_width * 8 / 10 self.height = self.screen_height * 5 / 10 self.main_frame = frame = QMainFrame(self.width, self.height) self.SetTopWindow(frame) # Record the basic application parameters if sys.platform == 'win32': h = self.main_frame.GetHandle() else: h = 0 QS.record_app(self, conf, self.data_width, self.fft_size, average_count, self.sample_rate, h) #print 'FFT size %d, FFT mult %d, average_count %d' % ( # self.fft_size, self.fft_size / self.data_width, average_count) #print 'Refresh %.2f Hz' % (float(self.sample_rate) / self.fft_size / average_count) QS.record_graph(0, 0, 1.0) # Make all the screens and hide all but one self.graph = GraphScreen(frame, self.data_width, self.graph_width) self.screen = self.graph width = self.graph.width button_width = width # calculate the final button width self.config_screen = ConfigScreen(frame, width, self.fft_size) self.config_screen.Hide() self.waterfall = WaterfallScreen(frame, width, self.data_width, self.graph_width) self.waterfall.Hide() self.scope = ScopeScreen(frame, width, self.data_width, self.graph_width) self.scope.Hide() self.filter_screen = FilterScreen(frame, self.data_width, self.graph_width) self.filter_screen.Hide() self.help_screen = HelpScreen(frame, width, self.screen_height / 10) self.help_screen.Hide() self.station_screen = StationScreen(frame, width, conf.station_display_lines) self.station_screen.Hide() # Make a vertical box to hold all the screens and the bottom box vertBox = self.vertBox = wx.BoxSizer(wx.VERTICAL) frame.SetSizer(vertBox) # Add the screens vertBox.Add(self.config_screen, 1, wx.EXPAND) vertBox.Add(self.graph, 1) vertBox.Add(self.waterfall, 1) vertBox.Add(self.scope, 1) vertBox.Add(self.filter_screen, 1) vertBox.Add(self.help_screen, 1) vertBox.Add(self.station_screen) # Add the spacer vertBox.Add(Spacer(frame), 0, wx.EXPAND) # Add the bottom box hBoxA = wx.BoxSizer(wx.HORIZONTAL) vertBox.Add(hBoxA, 0, wx.EXPAND) vertBox.AddSpacer(5) # Thanks to Christof, DJ4CM # End of vertical box. Add items to the horizontal box. # Add two sliders on the left margin = 3 self.sliderVol = SliderBoxV(frame, 'Vol', self.volumeAudio, 1000, self.ChangeVolume) button_width -= self.sliderVol.width + margin * 2 self.ChangeVolume() # set initial volume level hBoxA.Add(self.sliderVol, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, margin) if Hardware.use_sidetone: self.sliderSto = SliderBoxV(frame, 'STo', 300, 1000, self.ChangeSidetone) button_width -= self.sliderSto.width + margin * 2 self.ChangeSidetone() hBoxA.Add(self.sliderSto, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, margin) # Add the sizer for the middle gap = 2 gbs = wx.GridBagSizer(gap, gap) self.gbs = gbs button_width -= gap * 15 hBoxA.Add(gbs, 1, wx.EXPAND, 0) gbs.SetEmptyCellSize((5, 5)) button_width -= 5 # Add three sliders on the right self.sliderYs = SliderBoxV(frame, 'Ys', 0, 160, self.ChangeYscale, True) button_width -= self.sliderYs.width + margin * 2 hBoxA.Add(self.sliderYs, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, margin) self.sliderYz = SliderBoxV(frame, 'Yz', 0, 160, self.ChangeYzero, True) button_width -= self.sliderYz.width + margin * 2 hBoxA.Add(self.sliderYz, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, margin) self.sliderZo = SliderBoxV(frame, 'Zo', 0, 1000, self.OnChangeZoom) button_width -= self.sliderZo.width + margin * 2 hBoxA.Add(self.sliderZo, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, margin) self.sliderZo.SetValue(0) button_width /= 13 # This is our final button size bw = button_width button_width, button_height = self.MakeButtons(frame, gbs, button_width, gap) ww = self.graph.width self.main_frame.SetSizeHints(ww, 100) if button_width > bw: # The button width was increased ww += (button_width - bw) * 12 self.main_frame.SetClientSizeWH(ww, self.screen_height * 5 / 10) self.MakeTopRow(frame, gbs, button_width, button_height) self.button_width = button_width self.button_height = button_height if conf.quisk_widgets: self.bottom_widgets = conf.quisk_widgets.BottomWidgets(self, Hardware, conf, frame, gbs, vertBox) if QS.open_key(conf.key_method): print('open_key failed for name "%s"' % conf.key_method) if hasattr(conf, 'mixer_settings'): for dev, numid, value in conf.mixer_settings: err_msg = QS.mixer_set(dev, numid, value) if err_msg: print("Mixer", err_msg) # Open the hardware. This must be called before open_sound(). self.config_text = Hardware.open() if not self.config_text: self.config_text = "Missing config_text" if conf.use_rx_udp: self.add_version = True # Add firmware version to config text else: self.add_version = False QS.capt_channels (conf.channel_i, conf.channel_q) QS.play_channels (conf.channel_i, conf.channel_q) QS.micplay_channels (conf.mic_play_chan_I, conf.mic_play_chan_Q) # Note: Subsequent calls to set channels must not name a higher channel number. # Normally, these calls are only used to reverse the channels. QS.open_sound(conf.name_of_sound_capt, conf.name_of_sound_play, self.sample_rate, conf.data_poll_usec, conf.latency_millisecs, conf.microphone_name, conf.tx_ip, conf.tx_audio_port, conf.mic_sample_rate, conf.mic_channel_I, conf.mic_channel_Q, conf.mic_out_volume, conf.name_of_mic_play, conf.mic_playback_rate) tune, vfo = Hardware.ReturnFrequency() # Request initial frequency if tune is None or vfo is None: # Set last-used frequency self.bandBtnGroup.SetLabel(self.lastBand, do_cmd=True) else: # Set requested frequency self.BandFromFreq(tune) self.ChangeDisplayFrequency(tune - vfo, vfo) # Record filter rate for the filter screen self.filter_screen.sample_rate = QS.get_filter_rate() #if info[8]: # error message # self.sound_error = 1 # self.config_screen.err_msg = info[8] # print info[8] self.config_screen.InitBitmap() if self.sound_error: self.screenBtnGroup.SetLabel('Config', do_cmd=True) frame.Show() else: self.screenBtnGroup.SetLabel(conf.default_screen, do_cmd=True) frame.Show() self.Yield() self.sound_thread = SoundThread() self.sound_thread.start() if conf.dxClHost: # create DX Cluster and register listener for change notification self.dxCluster = dxcluster.DxCluster() self.dxCluster.setListener(self.OnDxClChange) self.dxCluster.start() return True def OnDxClChange(self): self.station_screen.Refresh() def OnIdle(self, event): if self.screen: self.screen.OnIdle(event) def OnEndSession(self, event): event.Skip() self.OnBtnClose(event) def OnBtnClose(self, event): QS.set_file_record(3, '') # Turn off file recording time.sleep(0.1) if self.sound_thread: self.sound_thread.stop() for i in range(0, 20): if threading.activeCount() == 1: break time.sleep(0.1) def OnExit(self): if self.dxCluster: self.dxCluster.stop() QS.close_rx_udp() Hardware.close() self.SaveState() def CheckState(self): # check whether state has changed changed = False if self.init_path: # save current program state for n in self.StateNames: try: if getattr(self, n) != self.savedState[n]: changed = True break except: changed = True break return changed def SaveState(self): if self.init_path: # save current program state d = {} for n in self.StateNames: d[n] = v = getattr(self, n) self.savedState[n] = v try: fp = open(self.init_path, "wb") pickle.dump(d, fp) fp.close() except: pass #traceback.print_exc() def MakeTopRow(self, frame, gbs, button_width, button_height): # Down button b_down = QuiskRepeatbutton(frame, self.OnBtnDownBand, conf.Xbtn_text_range_dn, self.OnBtnUpDnBandDone, use_right=True) gbs.Add(b_down, (0, 8), flag=wx.ALIGN_CENTER) # Up button b_up = QuiskRepeatbutton(frame, self.OnBtnUpBand, conf.Xbtn_text_range_up, self.OnBtnUpDnBandDone, use_right=True) gbs.Add(b_up, (0, 9), flag=wx.ALIGN_CENTER) # Memory buttons b = QuiskPushbutton(frame, self.OnBtnMemSave, conf.Xbtn_text_mem_add) gbs.Add(b, (0, 11), flag=wx.ALIGN_CENTER) b = self.memNextButton = QuiskPushbutton(frame, self.OnBtnMemNext, conf.Xbtn_text_mem_next) b.Enable(False) self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClickMemory, b) gbs.Add(b, (0, 12), flag=wx.ALIGN_CENTER) b = self.memDeleteButton = QuiskPushbutton(frame, self.OnBtnMemDelete, conf.Xbtn_text_mem_del) b.Enable(False) gbs.Add(b, (0, 13), flag=wx.ALIGN_CENTER) # Favorites buttons b = self.StationNewButton = QuiskPushbutton(frame, self.OnBtnFavoritesNew, conf.Xbtn_text_fav_add) gbs.Add(b, (0, 15), flag=wx.ALIGN_CENTER) b = self.StationNewButton = QuiskPushbutton(frame, self.OnBtnFavoritesShow, conf.Xbtn_text_fav_recall) gbs.Add(b, (0, 16), flag=wx.ALIGN_CENTER) # RIT button self.ritButton = QuiskCheckbutton(frame, self.OnBtnRit, "RIT") gbs.Add(self.ritButton, (0, 17), flag=wx.ALIGN_CENTER) # RIT slider self.ritScale = SliderBoxHH(frame, '%d ', self.ritFreq, -2000, 2000, self.OnRitScale, True) gbs.Add(self.ritScale, (0, 18), (1, 5), flag=wx.EXPAND) # Frequency display bw, bh = b_down.GetMinSize() self.freqDisplay = FrequencyDisplay(frame, 99999, bh * 15 / 10) self.freqDisplay.Display(self.txFreq + self.VFO) gbs.Add(self.freqDisplay, (0, 0), (1, 6), flag=wx.EXPAND | wx.TOP | wx.BOTTOM, border=self.freqDisplay.border) # Frequency entry e = wx.TextCtrl(frame, -1, '', size=(10, bh), style=wx.TE_PROCESS_ENTER) font = wx.Font(10, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) e.SetFont(font) e.SetBackgroundColour(conf.color_entry) e.SetForegroundColour(conf.color_entry_txt) szr = wx.BoxSizer(wx.HORIZONTAL) # add control to box sizer for centering szr.Add(e, 1, flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) gbs.Add(szr, (0, 6), (1, 2), flag = wx.EXPAND|wx.LEFT|wx.RIGHT, border=5) frame.Bind(wx.EVT_TEXT_ENTER, self.FreqEntry, source=e) # S-meter self.smeter = QuiskText(frame, ' S9+23 -166.00 dB ', bh, wx.ALIGN_LEFT, True) gbs.Add(self.smeter, (0, 23), (1, 4), flag=wx.EXPAND) self.smeter.TextCtrl.Bind(wx.EVT_RIGHT_DOWN, self.OnSmeterRightDown) self.smeter.TextCtrl.SetBackgroundColour(conf.color_freq) self.smeter.TextCtrl.SetForegroundColour(conf.color_freq_txt) # Make a popup menu for the s-meter self.smeter_menu = wx.Menu() item = self.smeter_menu.Append(-1, 'S-meter') self.Bind(wx.EVT_MENU, self.OnSmeterMeter, item) item = self.smeter_menu.Append(-1, 'Frequency 2') self.Bind(wx.EVT_MENU, self.OnSmeterFrequencyA, item) item = self.smeter_menu.Append(-1, 'Frequency 10') self.Bind(wx.EVT_MENU, self.OnSmeterFrequencyB, item) # Make a popup menu for the memory buttons self.memory_menu = wx.Menu() def OnSmeterRightDown(self, event): pos = event.GetPosition() self.smeter.TextCtrl.PopupMenu(self.smeter_menu, pos) def OnSmeterMeter(self, event): self.smeter_frequency = False QS.measure_frequency(0) def OnSmeterFrequencyA(self, event): self.smeter_frequency = True QS.measure_frequency(2) def OnSmeterFrequencyB(self, event): self.smeter_frequency = True QS.measure_frequency(10) def MakeButtons(self, frame, gbs, button_width, gap): # There are fourteen columns, a small gap column, and then twelve more columns ### Left bank of buttons in fourteen columns flag = wx.EXPAND self.bandBtnGroup = RadioButtonGroup(frame, self.OnBtnBand, conf.bandLabels, None) band_buttons = self.bandBtnGroup.buttons col = 0 for b in band_buttons[0:14]: gbs.Add(b, (1, col), flag=flag) col += 1 for i in range(col, 14): b = QuiskCheckbutton(frame, None, text='') gbs.Add(b, (1, i), flag=flag) # Receive button row: Mute, AGC left_row2 = [] b = QuiskCheckbutton(frame, self.OnBtnMute, text='Mute') left_row2.append(b) self.BtnAGC = QuiskSliderButton(frame, self.OnBtnAGC, 'AGC') # AGC and Squelch left_row2.append(self.BtnAGC) b = QuiskCycleCheckbutton(frame, self.OnBtnNB, ('NB', 'NB 1', 'NB 2', 'NB 3')) left_row2.append(b) b = QuiskCheckbutton(frame, self.OnBtnAutoNotch, text='Notch') left_row2.append(b) try: labels = Hardware.rf_gain_labels except: labels = () if labels: b = self.BtnRfGain = QuiskCycleCheckbutton(frame, Hardware.OnButtonRfGain, labels) else: b = QuiskCheckbutton(frame, None, text='RfGain') b.Enable(False) self.BtnRfGain = None left_row2.append(b) try: labels = Hardware.antenna_labels except: labels = () if labels: b = QuiskCycleCheckbutton(frame, Hardware.OnButtonAntenna, labels) else: b = QuiskCheckbutton(frame, None, text='Ant 1') b.Enable(False) left_row2.append(b) if 0: # Display a color chooser b = QuiskRepeatbutton(frame, self.OnBtnColor, 'Color', use_right=True) else: b = QuiskCheckbutton(frame, self.OnBtnTest1, 'Test 1', color=conf.color_test) left_row2.append(b) # Transmit button row: Spot left_row3=[] b = QuiskSpotButton(frame, self.OnBtnSpot, 'Spot', slider_value=self.levelSpot, color=conf.color_test, slider_min=10, slider_max=1000) if not hasattr(Hardware, 'OnSpot'): b.Enable(False) left_row3.append(b) b = self.splitButton = QuiskCheckbutton(frame, self.OnBtnSplit, "Split") if conf.mouse_tune_method: # Mouse motion changes the VFO frequency b.Enable(False) left_row3.append(b) b = QuiskCheckbutton(frame, self.OnBtnFDX, 'FDX', color=conf.color_test) if not conf.add_fdx_button: b.Enable(False) left_row3.append(b) if hasattr(Hardware, 'OnButtonPTT'): b = QuiskCheckbutton(frame, Hardware.OnButtonPTT, 'PTT', color='red') self.pttButton = b else: b = QuiskCheckbutton(frame, None, 'PTT') b.Enable(False) left_row3.append(b) # Record and Playback buttons b = self.btnTmpRecord = QuiskCheckbutton(frame, self.OnBtnTmpRecord, text=conf.Xbtn_text_rec) left_row3.append(b) b = self.btnTmpPlay = QuiskCheckbutton(frame, self.OnBtnTmpPlay, text=conf.Xbtn_text_play) b.Enable(0) left_row3.append(b) self.btn_file_record = QuiskCheckbutton(frame, self.OnBtnFileRecord, conf.Xbtn_text_file_rec) self.btn_file_record.Enable(0) left_row3.append(self.btn_file_record) b = QuiskCheckbutton(frame, None, text='') left_row3.append(b) ### Right bank of buttons labels = [('CWL', 'CWU'), ('LSB', 'USB'), 'AM', 'FM', ('DGT-U', 'DGT-L', 'DGT-IQ')] if conf.add_imd_button: labels.append(('IMD', 'IMD -3dB', 'IMD -6dB')) elif conf.add_extern_demod: labels.append(conf.add_extern_demod) else: labels.append('') self.modeButns = RadioButtonGroup(frame, self.OnBtnMode, labels, None) right_row1 = self.modeButns.GetButtons()[:] if conf.add_imd_button: right_row1[-1].color = conf.color_test labels = ('0', '0', '0', '0', '0', '0') self.filterButns = RadioButtonGroup(frame, self.OnBtnFilter, labels, None) b = QuiskFilterButton(frame, text=str(self.filterAdjBw1)) self.filterButns.ReplaceButton(5, b) right_row2 = self.filterButns.GetButtons() labels = (('Graph', 'GraphP1', 'GraphP2'), 'WFall', ('Scope', 'Scope'), 'Config', 'RX Filter', 'Help') self.screenBtnGroup = RadioButtonGroup(frame, self.OnBtnScreen, labels, conf.default_screen) right_row3 = self.screenBtnGroup.GetButtons() col = 0 for b in left_row2: gbs.Add(b, (2, col), (1, 2), flag=flag) col += 2 col = 0 for b in left_row3: if col in (8, 9): # single column gbs.Add(b, (3, col), flag=flag) col += 1 else: # double column gbs.Add(b, (3, col), (1, 2), flag=flag) col += 2 col = 15 for i in range(0, 6): gbs.Add(right_row1[i], (1, col), (1, 2), flag=flag) gbs.Add(right_row2[i], (2, col), (1, 2), flag=flag) gbs.Add(right_row3[i], (3, col), (1, 2), flag=flag) col += 2 if 1: for i in range(14): gbs.AddGrowableCol(i,1) for i in range(15, 27): gbs.AddGrowableCol(i,1) w, height = right_row1[0].GetMinSize() return button_width, height def MeasureFrequency(self): vfo = Hardware.ReturnVfoFloat() if vfo is None: vfo = self.VFO t = '%11.2f' % (QS.measure_frequency(-1) + vfo) t = ' ' + t[0:2] + ' ' + t[2:5] + ' ' + t[5:] + ' Hz' self.smeter.SetLabel(t) def NewSmeter(self): #avg_seconds = 5.0 # seconds for S-meter average avg_seconds = 1.0 self.smeter_db_count += 1 # count for average x = QS.get_smeter() self.smeter_db_sum += x # sum for average if self.timer - self.smeter_db_time0 > avg_seconds: # average time reached self.smeter_db = self.smeter_db_sum / self.smeter_db_count self.smeter_db_count = self.smeter_db_sum = 0 self.smeter_db_time0 = self.timer if self.smeter_sunits < x: # S-meter moves to peak value self.smeter_sunits = x else: # S-meter decays at this time constant self.smeter_sunits -= (self.smeter_sunits - x) * (self.timer - self.smeter_sunits_time0) self.smeter_sunits_time0 = self.timer s = self.smeter_sunits / 6.0 # change to S units; 6db per S unit s += Hardware.correct_smeter # S-meter correction for the gain, band, etc. if s < 0: s = 0 if s >= 9.5: s = (s - 9.0) * 6 t = " S9+%2.0f %7.2f dB" % (s, self.smeter_db) else: t = " S%.0f %7.2f dB" % (s, self.smeter_db) self.smeter.SetLabel(t) def MakeFilterButtons(self, args): # Change the filter selections depending on the mode: CW, SSB, etc. # Do not change the adjustable filter buttons. buttons = self.filterButns.GetButtons() for i in range(0, len(buttons) - 1): buttons[i].SetLabel(str(args[i])) buttons[i].Refresh() def MakeFilterCoef(self, rate, N, bw, center): """Make an I/Q filter with rectangular passband.""" lowpass = bw * 24000 / rate / 2 if lowpass in Filters: filtD = Filters[lowpass] #print "Custom filter rate %d bandwidth %d" % (rate, bw) else: #print "Window filter rate %d bandwidth %d" % (rate, bw) if N is None: shape = 1.5 # Shape factor at 88 dB trans = (bw / 2.0 / rate) * (shape - 1.0) # 88 dB atten N = int(4.0 / trans) if N > 1000: N = 1000 N = (N / 2) * 2 + 1 K = bw * N / rate filtD = [] pi = math.pi sin = math.sin cos = math.cos for k in range(-N/2, N/2 + 1): # Make a lowpass filter if k == 0: z = float(K) / N else: z = 1.0 / N * sin(pi * k * K / N) / sin(pi * k / N) # Apply a windowing function if 1: # Blackman window w = 0.42 + 0.5 * cos(2. * pi * k / N) + 0.08 * cos(4. * pi * k / N) elif 0: # Hamming w = 0.54 + 0.46 * cos(2. * pi * k / N) elif 0: # Hanning w = 0.5 + 0.5 * cos(2. * pi * k / N) else: w = 1 z *= w filtD.append(z) if center: # Make a bandpass filter by tuning the low pass filter to new center frequency. # Make two quadrature filters. filtI = [] filtQ = [] tune = -1j * 2.0 * math.pi * center / rate; NN = len(filtD) D = (NN - 1.0) / 2.0; for i in range(NN): z = 2.0 * cmath.exp(tune * (i - D)) * filtD[i] filtI.append(z.real) filtQ.append(z.imag) return filtI, filtQ return filtD, filtD def UpdateFilterDisplay(self): # Note: Filter bandwidths are ripple bandwidths with a shape factor of 1.2. # Also, SSB filters start at 300 Hz. if not conf.filter_display: size = 1 tune = 0 elif self.mode in ('AM', 'FM', 'CWL', 'CWU', 'DGT-IQ'): size = int(self.filter_bandwidth / self.zoom / self.sample_rate * self.data_width + 0.5) tune = size / 2 elif self.mode in ('LSB', 'DGT-L'): size = int((self.filter_bandwidth + 300) / self.zoom / self.sample_rate * self.data_width + 0.5) tune = size - 1 else: size = int((self.filter_bandwidth + 300) / self.zoom / self.sample_rate * self.data_width + 0.5) tune = 0 if size < 2: size = 1 tune = 0 self.graph.display.UpdateFilterDisplay(size, tune) self.waterfall.pane1.display.UpdateFilterDisplay(size, tune) def OnBtnFilter(self, event, bw=None): if event is None: # called by application self.filterButns.SetLabel(str(bw)) else: # called by button btn = event.GetEventObject() bw = int(btn.GetLabel()) mode = self.mode if mode in ("CWL", "CWU"): bw = min(bw, 2500) center = max(conf.cwTone, bw/2) elif mode in ('LSB', 'USB'): bw = min(bw, 5000) center = 300 + bw / 2 elif mode == 'AM': bw = min(bw, 21000) center = 0 elif mode == 'FM': bw = min(bw, 21000) center = 0 elif mode in ('DGT-U', 'DGT-L'): bw = min(bw, 21000) center = 300 + bw / 2 elif mode == 'DGT-IQ': bw = min(bw, 21000) center = 0 else: bw = min(bw, 5000) center = 300 + bw / 2 self.filter_bandwidth = bw self.UpdateFilterDisplay() frate = QS.get_filter_rate() filtI, filtQ = self.MakeFilterCoef(frate, None, bw, center) QS.set_filters(filtI, filtQ, bw) if self.screen is self.filter_screen: self.screen.NewFilter() def OnBtnScreen(self, event, name=None): if event is not None: win = event.GetEventObject() name = win.GetLabel() self.screen.Hide() self.station_screen.Hide() if name == 'Config': self.screen = self.config_screen elif name[0:5] == 'Graph': self.screen = self.graph self.screen.SetTxFreq(self.txFreq, self.rxFreq) self.freqDisplay.Display(self.VFO + self.txFreq) self.screen.PeakHold(name) self.station_screen.Show() elif name == 'WFall': self.screen = self.waterfall self.screen.SetTxFreq(self.txFreq, self.rxFreq) self.freqDisplay.Display(self.VFO + self.txFreq) sash = self.screen.GetSashPosition() self.station_screen.Show() elif name == 'Scope': if win.direction: # Another push on the same button self.scope.running = 1 - self.scope.running # Toggle run state else: # Initial push of button self.scope.running = 1 self.screen = self.scope elif name == 'RX Filter': self.screen = self.filter_screen self.freqDisplay.Display(self.screen.txFreq) self.screen.NewFilter() elif name == 'Help': self.screen = self.help_screen self.screen.Show() self.vertBox.Layout() # This destroys the initialized sash position! self.sliderYs.SetValue(self.screen.y_scale) self.sliderYz.SetValue(self.screen.y_zero) if name == 'WFall': self.screen.SetSashPosition(sash) def OnBtnFileRecord(self, event): if event.GetEventObject().GetValue(): QS.set_file_record(2, '') else: QS.set_file_record(3, '') def ChangeYscale(self, event): self.screen.ChangeYscale(self.sliderYs.GetValue()) def ChangeYzero(self, event): self.screen.ChangeYzero(self.sliderYz.GetValue()) def OnChangeZoom(self, event): x = self.sliderZo.GetValue() if x < 50: self.zoom = 1.0 # change back to not-zoomed mode self.zoom_deltaf = 0 self.zooming = False else: a = 1000.0 * self.sample_rate / (self.sample_rate - 2500.0) self.zoom = 1.0 - x / a if not self.zooming: self.zoom_deltaf = self.txFreq # set deltaf when zoom mode starts self.zooming = True zoom = self.zoom deltaf = self.zoom_deltaf self.graph.ChangeZoom(zoom, deltaf) self.waterfall.pane1.ChangeZoom(zoom, deltaf) self.waterfall.pane2.ChangeZoom(zoom, deltaf) self.waterfall.pane2.display.ChangeZoom(zoom, deltaf) self.screen.SetTxFreq(self.txFreq, self.rxFreq) self.UpdateFilterDisplay() self.station_screen.Refresh() def OnBtnMute(self, event): btn = event.GetEventObject() if btn.GetValue(): QS.set_volume(0) else: QS.set_volume(self.audio_volume) def OnBtnDecimation(self, event): i = event.GetSelection() rate = Hardware.VarDecimSet(i) self.vardecim_set = rate if rate != self.sample_rate: self.sample_rate = rate self.graph.sample_rate = rate self.waterfall.pane1.sample_rate = rate self.waterfall.pane2.sample_rate = rate self.waterfall.pane2.display.sample_rate = rate average_count = float(rate) / conf.graph_refresh / self.fft_size average_count = int(average_count + 0.5) average_count = max (1, average_count) QS.change_rate(rate, average_count) tune = self.txFreq vfo = self.VFO self.txFreq = self.VFO = -1 # demand change self.ChangeHwFrequency(tune, vfo, 'NewDecim') self.UpdateFilterDisplay() def ChangeVolume(self, event=None): # Caution: event can be None value = self.sliderVol.GetValue() self.volumeAudio = 1000 - value # Simulate log taper pot x = (10.0 ** (float(value) * 0.003000434077) - 1) / 1000.0 self.audio_volume = x # audio_volume is 0 to 1.000 QS.set_volume(x) def ChangeSidetone(self, event=None): # Caution: event can be None value = self.sliderSto.GetValue() self.sidetone_volume = value QS.set_sidetone(value, self.ritFreq, conf.keyupDelay) def OnRitScale(self, event=None): # Called when the RIT slider is moved # Caution: event can be None if self.ritButton.GetValue(): value = self.ritScale.GetValue() value = int(value) self.ritFreq = value QS.set_tune(self.rxFreq + self.ritFreq, self.txFreq) QS.set_sidetone(self.sidetone_volume, self.ritFreq, conf.keyupDelay) def OnBtnSplit(self, event): # Called when the Split check button is pressed self.split_rxtx = self.splitButton.GetValue() if self.split_rxtx: QS.set_split_rxtx(conf.split_rxtx) self.rxFreq = self.oldRxFreq d = self.sample_rate * 49 / 100 # Move rxFreq on-screen if self.rxFreq < -d: self.rxFreq = -d elif self.rxFreq > d: self.rxFreq = d else: QS.set_split_rxtx(0) self.oldRxFreq = self.rxFreq self.rxFreq = self.txFreq self.screen.SetTxFreq(self.txFreq, self.rxFreq) QS.set_tune(self.rxFreq + self.ritFreq, self.txFreq) def OnBtnRit(self, event=None): # Called when the RIT check button is pressed # Caution: event can be None if self.ritButton.GetValue(): self.ritFreq = self.ritScale.GetValue() else: self.ritFreq = 0 QS.set_tune(self.rxFreq + self.ritFreq, self.txFreq) QS.set_sidetone(self.sidetone_volume, self.ritFreq, conf.keyupDelay) def SetRit(self, freq): if freq: self.ritButton.SetValue(1) else: self.ritButton.SetValue(0) self.ritScale.SetValue(freq) self.OnBtnRit() def OnBtnFDX(self, event): btn = event.GetEventObject() if btn.GetValue(): QS.set_fdx(1) if hasattr(Hardware, 'OnBtnFDX'): Hardware.OnBtnFDX(1) else: QS.set_fdx(0) if hasattr(Hardware, 'OnBtnFDX'): Hardware.OnBtnFDX(0) def OnBtnSpot(self, event): btn = event.GetEventObject() self.levelSpot = btn.slider_value if btn.GetValue(): value = btn.slider_min + btn.slider_max - btn.slider_value # slider values are backwards in Wx else: value = 0 QS.set_spot_level(value) Hardware.OnSpot(value) def OnBtnTmpRecord(self, event): btn = event.GetEventObject() if btn.GetValue(): self.btnTmpPlay.Enable(0) QS.set_record_state(0) else: self.btnTmpPlay.Enable(1) QS.set_record_state(1) def OnBtnTmpPlay(self, event): btn = event.GetEventObject() if btn.GetValue(): if QS.is_key_down() and conf.mic_sample_rate != conf.playback_rate: self.btnTmpPlay.SetValue(False, False) else: self.btnTmpRecord.Enable(0) QS.set_record_state(2) self.tmp_playing = True else: self.btnTmpRecord.Enable(1) QS.set_record_state(3) self.tmp_playing = False def OnBtnTest1(self, event): btn = event.GetEventObject() if btn.GetValue(): QS.add_tone(10000) else: QS.add_tone(0) def OnBtnTest2(self, event): return def OnBtnColor(self, event): if not self.color_list: clist = wx.lib.colourdb.getColourInfoList() self.color_list = [(0, clist[0][0])] self.color_index = 0 for i in range(1, len(clist)): if self.color_list[-1][1].replace(' ', '') != clist[i][0].replace(' ', ''): #if 'BLUE' in clist[i][0]: self.color_list.append((i, clist[i][0])) btn = event.GetEventObject() if btn.shift: del self.color_list[self.color_index] else: self.color_index += btn.direction if self.color_index >= len(self.color_list): self.color_index = 0 elif self.color_index < 0: self.color_index = len(self.color_list) -1 color = self.color_list[self.color_index][1] print(self.color_index, color) self.main_frame.SetBackgroundColour(color) self.main_frame.Refresh() self.screen.Refresh() btn.SetBackgroundColour(color) btn.Refresh() def OnBtnAGC(self, event): # This is a combined AGC and Squelch button btn = event.GetEventObject() if self.mode == 'FM': # This is a Squelch button self.levelSquelch = btn.slider_value if btn.GetValue(): self.use_squelch = 1 value = 1000 - btn.slider_value # slider values are backwards in Wx QS.set_squelch(value / 12.0 - 120.0) else: self.use_squelch = 0 QS.set_squelch(-999.0) else: # This is an AGC button self.levelAGC = btn.slider_value value = 1000 - btn.slider_value # slider values are backwards in Wx # Simulate log taper pot. Volume is 0 to 1.000. x = (10.0 ** (float(value) * 0.003000434077) - 1) / 1000.0 if btn.GetValue(): self.use_AGC = 1 QS.set_agc(1, x, conf.agc_release_time) else: self.use_AGC = 0 QS.set_agc(0, x, conf.agc_release_time) def OnBtnAutoNotch(self, event): if event.GetEventObject().GetValue(): QS.set_auto_notch(1) else: QS.set_auto_notch(0) def OnBtnNB(self, event): index = event.GetEventObject().index QS.set_noise_blanker(index) def FreqEntry(self, event): freq = event.GetString() if not freq: return try: freq = str2freq (freq) except ValueError: win = event.GetEventObject() win.Clear() win.AppendText("Error") else: tune = freq % 10000 vfo = freq - tune self.BandFromFreq(freq) self.ChangeHwFrequency(tune, vfo, 'FreqEntry') def ChangeHwFrequency(self, tune, vfo, source='', band='', event=None): """Change the VFO and tuning frequencies, and notify the hardware. tune: the new tuning frequency in +- sample_rate/2; vfo: the new vfo frequency in Hertz; this is the RF frequency at zero Hz audio source: a string indicating the source or widget requesting the change; band: if source is "BtnBand", the band requested; event: for a widget, the event (used to access control/shift key state). Try to update the hardware by calling Hardware.ChangeFrequency(). The hardware will reply with the updated frequencies which may be different from those requested; use and display the returned tune and vfo. """ tune, vfo = Hardware.ChangeFrequency(vfo + tune, vfo, source, band, event) self.ChangeDisplayFrequency(tune - vfo, vfo) def ChangeDisplayFrequency(self, tune, vfo): 'Change the frequency displayed by Quisk' change = 0 if tune != self.txFreq: change = 1 self.txFreq = tune if not self.split_rxtx: self.rxFreq = self.txFreq self.screen.SetTxFreq(self.txFreq, self.rxFreq) QS.set_tune(self.rxFreq + self.ritFreq, self.txFreq) if vfo != self.VFO: change = 1 self.VFO = vfo self.graph.SetVFO(vfo) self.waterfall.SetVFO(vfo) self.station_screen.Refresh() if self.w_phase: # Phase adjustment screen can not change its VFO self.w_phase.Destroy() self.w_phase = None ampl, phase = self.GetAmplPhase(0) QS.set_ampl_phase(ampl, phase, 0) ampl, phase = self.GetAmplPhase(1) QS.set_ampl_phase(ampl, phase, 1) if change: self.freqDisplay.Display(self.txFreq + self.VFO) self.fldigi_new_freq = self.txFreq + self.VFO return change def ChangeRxTxFrequency(self, rx_freq=None, tx_freq=None): if not self.split_rxtx and not tx_freq: tx_freq = rx_freq if tx_freq: tune = tx_freq - self.VFO d = self.sample_rate * 45 / 100 if -d <= tune <= d: # Frequency is on-screen vfo = self.VFO else: # Change the VFO vfo = (tx_freq / 5000) * 5000 - 5000 tune = tx_freq - vfo self.BandFromFreq(tx_freq) self.ChangeHwFrequency(tune, vfo, 'FreqEntry') if rx_freq and self.split_rxtx: # Frequency must be on-screen tune = rx_freq - self.VFO self.rxFreq = tune self.screen.SetTxFreq(self.txFreq, tune) QS.set_tune(tune + self.ritFreq, self.txFreq) def OnBtnMode(self, event, mode=None): if event is None: # called by application self.modeButns.SetLabel(mode) else: # called by button mode = self.modeButns.GetLabel() Hardware.ChangeMode(mode) self.mode = mode if mode == 'CWL': QS.set_rx_mode(0) self.SetRit(conf.cwTone) self.MakeFilterButtons(conf.FilterBwCW) self.OnBtnFilter(None, conf.FilterBwCW[3]) elif mode == 'CWU': QS.set_rx_mode(1) self.SetRit(-conf.cwTone) self.MakeFilterButtons(conf.FilterBwCW) self.OnBtnFilter(None, conf.FilterBwCW[3]) elif mode == 'LSB': QS.set_rx_mode(2) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwSSB) self.OnBtnFilter(None, conf.FilterBwSSB[3]) elif mode == 'USB': QS.set_rx_mode(3) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwSSB) self.OnBtnFilter(None, conf.FilterBwSSB[3]) elif mode == 'AM': QS.set_rx_mode(4) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwAM) self.OnBtnFilter(None, conf.FilterBwAM[3]) elif mode == 'FM': QS.set_rx_mode(5) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwFM) self.OnBtnFilter(None, conf.FilterBwFM[3]) elif mode[0:4] == 'DGT-': if mode == 'DGT-U': QS.set_rx_mode(7) elif mode == 'DGT-L': QS.set_rx_mode(8) elif mode == 'DGT-IQ': QS.set_rx_mode(9) else: QS.set_rx_mode(7) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwDGT) self.OnBtnFilter(None, conf.FilterBwDGT[1]) elif mode[0:3] == 'IMD': QS.set_rx_mode(10 + self.modeButns.GetSelectedButton().index) # 10, 11, 12 self.SetRit(0) self.MakeFilterButtons(conf.FilterBwIMD) self.OnBtnFilter(None, conf.FilterBwIMD[3]) elif mode == conf.add_extern_demod: # External demodulation QS.set_rx_mode(6) self.SetRit(0) self.MakeFilterButtons(conf.FilterBwEXT) self.OnBtnFilter(None, conf.FilterBwEXT[3]) if mode == 'FM': self.BtnAGC.SetLabel('Sqlch') self.BtnAGC.SetSlider(self.levelSquelch) self.BtnAGC.SetValue(self.use_squelch, True) else: self.BtnAGC.SetLabel('AGC') self.BtnAGC.SetSlider(self.levelAGC) self.BtnAGC.SetValue(self.use_AGC, True) def MakeMemPopMenu(self): self.memory_menu.Destroy() self.memory_menu = wx.Menu() for data in self.memoryState: txt = FreqFormatter(data[0]) item = self.memory_menu.Append(-1, txt) self.Bind(wx.EVT_MENU, self.OnPopupMemNext, item) def OnPopupMemNext(self, event): frq = self.memory_menu.GetLabel(event.GetId()) frq = frq.replace(' ','') frq = int(frq) for freq, band, vfo, txfreq, mode in self.memoryState: if freq == frq: break else: return if band == self.lastBand: # leave band unchanged self.OnBtnMode(None, mode) self.ChangeHwFrequency(txfreq, vfo, 'FreqEntry') else: # change to new band self.bandState[band] = (vfo, txfreq, mode) self.bandBtnGroup.SetLabel(band, do_cmd=True) def OnBtnMemSave(self, event): frq = self.VFO + self.txFreq for i in range(len(self.memoryState)): data = self.memoryState[i] if data[0] == frq: self.memoryState[i] = (self.VFO + self.txFreq, self.lastBand, self.VFO, self.txFreq, self.mode) return self.memoryState.append((self.VFO + self.txFreq, self.lastBand, self.VFO, self.txFreq, self.mode)) self.memoryState.sort() self.memNextButton.Enable(True) self.memDeleteButton.Enable(True) self.MakeMemPopMenu() self.station_screen.Refresh() def OnBtnMemNext(self, event): frq = self.VFO + self.txFreq for freq, band, vfo, txfreq, mode in self.memoryState: if freq > frq: break else: freq, band, vfo, txfreq, mode = self.memoryState[0] if band == self.lastBand: # leave band unchanged self.OnBtnMode(None, mode) self.ChangeHwFrequency(txfreq, vfo, 'FreqEntry') else: # change to new band self.bandState[band] = (vfo, txfreq, mode) self.bandBtnGroup.SetLabel(band, do_cmd=True) def OnBtnMemDelete(self, event): frq = self.VFO + self.txFreq for i in range(len(self.memoryState)): data = self.memoryState[i] if data[0] == frq: del self.memoryState[i] break self.memNextButton.Enable(bool(self.memoryState)) self.memDeleteButton.Enable(bool(self.memoryState)) self.MakeMemPopMenu() self.station_screen.Refresh() def OnRightClickMemory(self, event): event.Skip() pos = event.GetPosition() self.memNextButton.PopupMenu(self.memory_menu, pos) def OnBtnFavoritesShow(self, event): self.screenBtnGroup.SetLabel(None, None) self.screen.Hide() self.screen = self.config_screen self.config_screen.notebook.SetSelection(3) self.screen.Show() self.vertBox.Layout() # This destroys the initialized sash position! self.sliderYs.SetValue(self.screen.y_scale) self.sliderYz.SetValue(self.screen.y_zero) def OnBtnFavoritesNew(self, event): self.config_screen.favorites.AddNewFavorite(); self.OnBtnFavoritesShow(event) def OnBtnBand(self, event): band = self.lastBand # former band in use try: f1, f2 = conf.BandEdge[band] if f1 <= self.VFO + self.txFreq <= f2: self.bandState[band] = (self.VFO, self.txFreq, self.mode) except KeyError: pass btn = event.GetEventObject() band = btn.GetLabel() # new band self.lastBand = band try: vfo, tune, mode = self.bandState[band] except KeyError: vfo, tune, mode = (0, 0, 'LSB') if band == '60': if self.mode in ('CWL', 'CWU'): freq60 = [] for f in conf.freq60: freq60.append(f + 1500) else: freq60 = conf.freq60 freq = vfo + tune if btn.direction: vfo = self.VFO if 5100000 < vfo < 5600000: if btn.direction > 0: # Move up for f in freq60: if f > vfo + self.txFreq: freq = f break else: freq = freq60[0] else: # move down l = list(freq60) l.reverse() for f in l: if f < vfo + self.txFreq: freq = f break else: freq = freq60[-1] half = self.sample_rate / 2 * self.graph_width / self.data_width while freq - vfo <= -half + 1000: vfo -= 10000 while freq - vfo >= +half - 5000: vfo += 10000 tune = freq - vfo elif band == 'Time': vfo, tune, mode = conf.bandTime[btn.index] self.OnBtnMode(None, mode) self.txFreq = self.VFO = -1 # demand change self.ChangeHwFrequency(tune, vfo, 'BtnBand', band=band) Hardware.ChangeBand(band) def BandFromFreq(self, frequency): # Change to a new band based on the frequency try: f1, f2 = conf.BandEdge[self.lastBand] if f1 <= frequency <= f2: return # We are within the current band except KeyError: f1 = f2 = -1 # Frequency is not within the current band. Save the current band data. if f1 <= self.VFO + self.txFreq <= f2: self.bandState[self.lastBand] = (self.VFO, self.txFreq, self.mode) # Change to the correct band based on frequency. for band, (f1, f2) in conf.BandEdge.items(): if f1 <= frequency <= f2: self.lastBand = band self.bandBtnGroup.SetLabel(band, do_cmd=False) try: vfo, tune, mode = self.bandState[band] except KeyError: vfo, tune, mode = (0, 0, 'LSB') self.OnBtnMode(None, mode) Hardware.ChangeBand(band) break def OnBtnUpDnBandDelta(self, event, is_band_down): sample_rate = int(self.sample_rate * self.zoom) oldvfo = self.VFO btn = event.GetEventObject() if btn.direction > 0: # left button was used, move a bit d = int(sample_rate / 9) else: # right button was used, move to edge d = int(sample_rate * 45 / 100) if is_band_down: d = -d vfo = self.VFO + d if sample_rate > 40000: vfo = (vfo + 5000) / 10000 * 10000 # round to even number delta = 10000 elif sample_rate > 5000: vfo = (vfo + 500) / 1000 * 1000 delta = 1000 else: vfo = (vfo + 50) / 100 * 100 delta = 100 if oldvfo == vfo: if is_band_down: d = -delta else: d = delta else: d = vfo - oldvfo self.VFO += d self.txFreq -= d self.rxFreq -= d # Set the display but do not change the hardware self.graph.SetVFO(self.VFO) self.waterfall.SetVFO(self.VFO) self.station_screen.Refresh() self.screen.SetTxFreq(self.txFreq, self.rxFreq) self.freqDisplay.Display(self.txFreq + self.VFO) def OnBtnDownBand(self, event): self.band_up_down = 1 self.OnBtnUpDnBandDelta(event, True) def OnBtnUpBand(self, event): self.band_up_down = 1 self.OnBtnUpDnBandDelta(event, False) def OnBtnUpDnBandDone(self, event): self.band_up_down = 0 tune = self.txFreq vfo = self.VFO self.txFreq = self.VFO = 0 # Force an update self.ChangeHwFrequency(tune, vfo, 'BtnUpDown') def GetAmplPhase(self, is_tx): if "panadapter" in conf.bandAmplPhase: band = "panadapter" else: band = self.lastBand try: if is_tx: lst = self.bandAmplPhase[band]["tx"] else: lst = self.bandAmplPhase[band]["rx"] except KeyError: return (0.0, 0.0) length = len(lst) if length == 0: return (0.0, 0.0) elif length == 1: return lst[0][2], lst[0][3] elif self.VFO < lst[0][0]: # before first data point i1 = 0 i2 = 1 elif lst[length - 1][0] < self.VFO: # after last data point i1 = length - 2 i2 = length - 1 else: # Binary search for the bracket VFO i1 = 0 i2 = length index = (i1 + i2) / 2 for i in range(length): diff = lst[index][0] - self.VFO if diff < 0: i1 = index elif diff > 0: i2 = index else: # equal VFO's return lst[index][2], lst[index][3] if i2 - i1 <= 1: break index = (i1 + i2) / 2 d1 = self.VFO - lst[i1][0] # linear interpolation d2 = lst[i2][0] - self.VFO dx = d1 + d2 ampl = (d1 * lst[i2][2] + d2 * lst[i1][2]) / dx phas = (d1 * lst[i2][3] + d2 * lst[i1][3]) / dx return ampl, phas def PostStartup(self): # called once after sound attempts to start self.config_screen.OnGraphData(None) # update config in case sound is not running def FldigiPoll(self): # Keep Quisk and Fldigi frequencies equal; control Fldigi PTT from Quisk if self.fldigi_server is None: return if self.fldigi_new_freq: # Our frequency changed; send to fldigi try: self.fldigi_server.main.set_frequency(float(self.fldigi_new_freq)) except: # traceback.print_exc() pass self.fldigi_new_freq = None self.fldigi_timer = time.time() return try: freq = self.fldigi_server.main.get_frequency() except: # traceback.print_exc() return else: freq = int(freq + 0.5) try: rxtx = self.fldigi_server.main.get_trx_status() # returns rx, tx, tune except: return if time.time() - self.fldigi_timer < 0.3: # If timer is small, change originated in Quisk self.fldigi_rxtx = rxtx self.fldigi_freq = freq return if self.fldigi_freq != freq: self.fldigi_freq = freq #print "Change freq", freq self.ChangeRxTxFrequency(None, freq) self.fldigi_new_freq = None if self.fldigi_rxtx != rxtx: self.fldigi_rxtx = rxtx #print 'Fldigi changed to', rxtx if self.pttButton: if rxtx == 'rx': self.pttButton.SetValue(0, True) else: self.pttButton.SetValue(1, True) self.fldigi_timer = time.time() else: if QS.is_key_down(): if rxtx == 'rx': self.fldigi_server.main.tx() self.fldigi_timer = time.time() else: # key is up if rxtx != 'rx': self.fldigi_server.main.rx() self.fldigi_timer = time.time() def HamlibPoll(self): # Poll for Hamlib commands if self.hamlib_socket: try: # Poll for new client connections. conn, address = self.hamlib_socket.accept() except socket.error: pass else: # print 'Connection from', address self.hamlib_clients.append(HamlibHandler(self, conn, address)) for client in self.hamlib_clients: # Service existing clients if not client.Process(): # False return indicates a closed connection; remove the handler for this client self.hamlib_clients.remove(client) # print 'Remove', client.address break def OnReadSound(self): # called at frequent intervals self.timer = time.time() if self.screen == self.scope: data = QS.get_graph(0, 1.0, 0) # get raw data if data: self.scope.OnGraphData(data) # Send message to draw new data return 1 # we got new graph/scope data elif False and self.screen == self.filter_screen: data = QS.get_audio_graph() # Display the audio FFT in the filter window if data: self.screen.data = data self.screen.OnGraphData(data) else: data = QS.get_graph(1, self.zoom, float(self.zoom_deltaf)) # get FFT data if data: #T('') if self.smeter_frequency: self.MeasureFrequency() else: self.NewSmeter() # update the S-meter if self.screen == self.graph: self.waterfall.OnGraphData(data) # save waterfall data self.graph.OnGraphData(data) # Send message to draw new data elif self.screen == self.config_screen: pass else: self.screen.OnGraphData(data) # Send message to draw new data #T('graph data') #application.Yield() #T('Yield') return 1 # We got new graph/scope data if QS.get_overrange(): self.clip_time0 = self.timer self.freqDisplay.Clip(1) if self.clip_time0: if self.timer - self.clip_time0 > 1.0: self.clip_time0 = 0 self.freqDisplay.Clip(0) if self.timer - self.heart_time0 > 0.10: # call hardware to perform background tasks self.heart_time0 = self.timer if self.screen == self.config_screen: self.screen.OnGraphData() # Send message to draw new data Hardware.HeartBeat() if self.add_version and Hardware.GetFirmwareVersion() is not None: self.add_version = False self.config_text = "%s, firmware version 1.%d" % (self.config_text, Hardware.GetFirmwareVersion()) if not self.band_up_down: # Poll the hardware for changed frequency. This is used for hardware # that can change its frequency independently of Quisk; eg. K3. tune, vfo = Hardware.ReturnFrequency() if tune is not None and vfo is not None: self.BandFromFreq(tune) self.ChangeDisplayFrequency(tune - vfo, vfo) self.FldigiPoll() self.HamlibPoll() if self.timer - self.save_time0 > 20.0: self.save_time0 = self.timer if self.CheckState(): self.SaveState() if self.tmp_playing and QS.set_record_state(-1): # poll to see if playback is finished self.btnTmpPlay.SetValue(False, True) def main(): """If quisk is installed as a package, you can run it with quisk.main().""" App() application.MainLoop() if __name__ == '__main__': main() quisk-3.6.11/makefile0000644000175000017500000000045311632372224014022 0ustar jimjim00000000000000 all: python setup.py build_ext --force --inplace win: C:/Python27/python.exe setup.py build_ext -c mingw32 --inplace --force winrun: C:/Python27/python.exe quisk.py winmsi: C:/Python27/python.exe wix/files.py wininstall: msiexec -i wix\\quisk.msi winuninstall: msiexec -x wix\\quisk.msi quisk-3.6.11/quisk_conf_sdriq.py0000644000175000017500000000234712135622437016246 0ustar jimjim00000000000000# These are the configuration parameters for Quisk using the # SDR-IQ by RfSpace as the capture device. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. from sdriqpkg import quisk_hardware # Use different hardware file # In ALSA, soundcards have these names: #name_of_sound_play = "hw:0" #name_of_sound_play = "hw:1" #name_of_sound_play = "plughw" #name_of_sound_play = "plughw:1" #name_of_sound_play = "default" use_sdriq = 1 # Use the SDR-IQ #sdriq_name = "/dev/ft2450" # Name of the SDR-IQ device to open sdriq_name = "/dev/ttyUSB2" # Name of the SDR-IQ device to open sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal) sdriq_decimation = 1250 # Must be 360, 500, 600, or 1250 sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this name_of_sound_capt = "" # We do not capture from the soundcard name_of_sound_play = "hw:0" # Play back on this soundcard playback_rate = 48000 # Radio sound play rate channel_i = 0 # Soundcard index of left channel channel_q = 1 # Soundcard index of right channel display_fraction = 0.85 # The edges of the full bandwidth are not valid quisk-3.6.11/filters.h0000666000175000017500000022702712113422202014142 0ustar jimjim00000000000000// Sample 48000 Hz, pass 1350, stop 1750, ripple 1 dB, atten 80 dB (coef_tx). Stop 0.036458. double quiskMicFilt48Coefs[325] = { 0.000070000950338734, 0.000060542525732639, 0.000084830915167248, 0.000113820318991206, 0.000147523658260692, 0.000185727097247136, 0.000228017694264326, 0.000273714746744222, 0.000321902242967596, 0.000371355069437399, 0.000420595492180569, 0.000467865412686539, 0.000511235564174107, 0.000548584697295435, 0.000577683697404093, 0.000596168573595124, 0.000601725499419238, 0.000592142083607333, 0.000565459097743531, 0.000519884471131262, 0.000454031497680723, 0.000367015380281216, 0.000258599355817496, 0.000128888056076112, -0.000021074826181109, -0.000189585802186493, -0.000374389987374961, -0.000572207780852182, -0.000779359325040342, -0.000991335380833019, -0.001203244280115714, -0.001409670281637694, -0.001605003575053789, -0.001783471817219780, -0.001939438753998784, -0.002067470485014850, -0.002162628068669760, -0.002220597743425130, -0.002237960051673301, -0.002212264773625852, -0.002142247186138010, -0.002027907322210780, -0.001870648667784210, -0.001673216059663119, -0.001439782952032160, -0.001175849407968695, -0.000888138367181945, -0.000584400564491252, -0.000273350274681290, 0.000035800336978808, 0.000333410168961052, 0.000609868204837889, 0.000855845198751289, 0.001062645743133108, 0.001222567778915907, 0.001329178561171123, 0.001377619146269160, 0.001364836763234778, 0.001289791422827911, 0.001153569049793089, 0.000959442606127223, 0.000712858984801055, 0.000421343499696318, 0.000094311703309987, -0.000257178812726900, -0.000620740024523200, -0.000983067401076951, -0.001330378208545664, -0.001648868642029554, -0.001925231739749957, -0.002147185427808426, -0.002303924955683100, -0.002386617358290471, -0.002388809260074332, -0.002306735130576522, -0.002139640086196955, -0.001889862283127962, -0.001562946712603551, -0.001167542853751166, -0.000715240442693352, -0.000220259485535331, 0.000300952307259904, 0.000830234179165372, 0.001348316435464076, 0.001835484518420602, 0.002272286892056382, 0.002640275270224598, 0.002922747186895021, 0.003105429025669433, 0.003177121318055631, 0.003130264761140124, 0.002961377569599093, 0.002671367231884301, 0.002265711108816848, 0.001754448044185524, 0.001152016769339380, 0.000476936676175902, -0.000248718444031171, -0.000999948124398612, -0.001749629130166096, -0.002469433330814752, -0.003130790556013717, -0.003705967375692800, -0.004169105103972317, -0.004497290920890501, -0.004671516289830527, -0.004677586380416906, -0.004506861602367489, -0.004156859083959776, -0.003631621917386205, -0.002941916481868308, -0.002105153002563826, -0.001145089028022731, -0.000091277027194512, 0.001021707212306502, 0.002155280663061357, 0.003268024493993296, 0.004317048090841251, 0.005259445594087794, 0.006053837753595639, 0.006661931665353417, 0.007050060676035087, 0.007190601958065676, 0.007063321534553406, 0.006656461303944376, 0.005967650471713226, 0.005004501271125813, 0.003784934033421286, 0.002337151835923401, 0.000699290786282728, -0.001081281658450751, -0.002948980083931280, -0.004841350286243770, -0.006690670765283031, -0.008425801537676034, -0.009974215633219711, -0.011264158097802190, -0.012226858155753686, -0.012798749185527288, -0.012923592591893964, -0.012554478278462186, -0.011655599268700838, -0.010203756484326235, -0.008189534541107277, -0.005618124746137401, -0.002509708641553183, 0.001100549166042612, 0.005162968475167027, 0.009614243563845803, 0.014378746109223314, 0.019370216567322070, 0.024493786616406266, 0.029648291853908371, 0.034728809072115958, 0.039629330964538544, 0.044245520769433347, 0.048477462256357018, 0.052232311099492307, 0.055426788736225432, 0.057989428195401226, 0.059862511141804443, 0.061003649799348830, 0.061386934931288717, 0.061003649799348830, 0.059862511141804443, 0.057989428195401226, 0.055426788736225432, 0.052232311099492307, 0.048477462256357018, 0.044245520769433347, 0.039629330964538544, 0.034728809072115958, 0.029648291853908371, 0.024493786616406266, 0.019370216567322070, 0.014378746109223314, 0.009614243563845803, 0.005162968475167027, 0.001100549166042612, -0.002509708641553183, -0.005618124746137401, -0.008189534541107277, -0.010203756484326235, -0.011655599268700838, -0.012554478278462186, -0.012923592591893964, -0.012798749185527288, -0.012226858155753686, -0.011264158097802190, -0.009974215633219711, -0.008425801537676034, -0.006690670765283031, -0.004841350286243770, -0.002948980083931280, -0.001081281658450751, 0.000699290786282728, 0.002337151835923401, 0.003784934033421286, 0.005004501271125813, 0.005967650471713226, 0.006656461303944376, 0.007063321534553406, 0.007190601958065676, 0.007050060676035087, 0.006661931665353417, 0.006053837753595639, 0.005259445594087794, 0.004317048090841251, 0.003268024493993296, 0.002155280663061357, 0.001021707212306502, -0.000091277027194512, -0.001145089028022731, -0.002105153002563826, -0.002941916481868308, -0.003631621917386205, -0.004156859083959776, -0.004506861602367489, -0.004677586380416906, -0.004671516289830527, -0.004497290920890501, -0.004169105103972317, -0.003705967375692800, -0.003130790556013717, -0.002469433330814752, -0.001749629130166096, -0.000999948124398612, -0.000248718444031171, 0.000476936676175902, 0.001152016769339380, 0.001754448044185524, 0.002265711108816848, 0.002671367231884301, 0.002961377569599093, 0.003130264761140124, 0.003177121318055631, 0.003105429025669433, 0.002922747186895021, 0.002640275270224598, 0.002272286892056382, 0.001835484518420602, 0.001348316435464076, 0.000830234179165372, 0.000300952307259904, -0.000220259485535331, -0.000715240442693352, -0.001167542853751166, -0.001562946712603551, -0.001889862283127962, -0.002139640086196955, -0.002306735130576522, -0.002388809260074332, -0.002386617358290471, -0.002303924955683100, -0.002147185427808426, -0.001925231739749957, -0.001648868642029554, -0.001330378208545664, -0.000983067401076951, -0.000620740024523200, -0.000257178812726900, 0.000094311703309987, 0.000421343499696318, 0.000712858984801055, 0.000959442606127223, 0.001153569049793089, 0.001289791422827911, 0.001364836763234778, 0.001377619146269160, 0.001329178561171123, 0.001222567778915907, 0.001062645743133108, 0.000855845198751289, 0.000609868204837889, 0.000333410168961052, 0.000035800336978808, -0.000273350274681290, -0.000584400564491252, -0.000888138367181945, -0.001175849407968695, -0.001439782952032160, -0.001673216059663119, -0.001870648667784210, -0.002027907322210780, -0.002142247186138010, -0.002212264773625852, -0.002237960051673301, -0.002220597743425130, -0.002162628068669760, -0.002067470485014850, -0.001939438753998784, -0.001783471817219780, -0.001605003575053789, -0.001409670281637694, -0.001203244280115714, -0.000991335380833019, -0.000779359325040342, -0.000572207780852182, -0.000374389987374961, -0.000189585802186493, -0.000021074826181109, 0.000128888056076112, 0.000258599355817496, 0.000367015380281216, 0.000454031497680723, 0.000519884471131262, 0.000565459097743531, 0.000592142083607333, 0.000601725499419238, 0.000596168573595124, 0.000577683697404093, 0.000548584697295435, 0.000511235564174107, 0.000467865412686539, 0.000420595492180569, 0.000371355069437399, 0.000321902242967596, 0.000273714746744222, 0.000228017694264326, 0.000185727097247136, 0.000147523658260692, 0.000113820318991206, 0.000084830915167248, 0.000060542525732639, 0.000070000950338734} ; // Rate 8000, pass 1350, stop 1700, ripple 0.2 dB, Atten 100 dB, taps 93 (tune 1650). Stop 0.2125 double quiskMicFilt8Coefs[93] = { -0.000048361334397216, -0.000162172832480051, -0.000233937595698212, -0.000006327103457766, 0.000686150429731403, 0.001555572669911020, 0.001852235322638049, 0.001010518676959113, -0.000533703037637750, -0.001395527281294679, -0.000547805689731835, 0.001291819787342756, 0.002005877810728077, 0.000349773034952121, -0.002188174349636707, -0.002546652809598079, 0.000326796204088075, 0.003522458156729808, 0.002929815624806958, -0.001643263026946036, -0.005188443834846179, -0.002794087489903680, 0.003828812643532208, 0.006979098861533383, 0.001700757602284474, -0.007013801827881641, -0.008485813922195549, 0.000867966129209818, 0.011177153889901327, 0.009069558799223736, -0.005488279673121778, -0.016106658511052186, -0.007822070151870978, 0.012835116756370880, 0.021388877055372072, 0.003393318192541889, -0.023987911353715568, -0.026461891098409809, 0.006724804206592470, 0.041707244257452522, 0.030690541453250592, -0.029955120082834141, -0.077739106243522968, -0.033499374091835024, 0.116943716609774510, 0.290907261177841880, 0.367819184749133500, 0.290907261177841880, 0.116943716609774510, -0.033499374091835024, -0.077739106243522968, -0.029955120082834141, 0.030690541453250592, 0.041707244257452522, 0.006724804206592470, -0.026461891098409809, -0.023987911353715568, 0.003393318192541889, 0.021388877055372072, 0.012835116756370880, -0.007822070151870978, -0.016106658511052186, -0.005488279673121778, 0.009069558799223736, 0.011177153889901327, 0.000867966129209818, -0.008485813922195549, -0.007013801827881641, 0.001700757602284474, 0.006979098861533383, 0.003828812643532208, -0.002794087489903680, -0.005188443834846179, -0.001643263026946036, 0.002929815624806958, 0.003522458156729808, 0.000326796204088075, -0.002546652809598079, -0.002188174349636707, 0.000349773034952121, 0.002005877810728077, 0.001291819787342756, -0.000547805689731835, -0.001395527281294679, -0.000533703037637750, 0.001010518676959113, 0.001852235322638049, 0.001555572669911020, 0.000686150429731403, -0.000006327103457766, -0.000233937595698212, -0.000162172832480051, -0.000048361334397216} ; // Rate 48000, pass 3200, stop 4500, ripple 0.2 dB, atten 100 dB, taps 144. Stop .09375. double quiskLpFilt48Coefs[144] = {-0.000017125474330604, -0.000040011820393130, -0.000077862936583202, -0.000127389313997705, -0.000181102741386044, -0.000225109758175834, -0.000239838685218700, -0.000202969232396477, -0.000094305597311178, 0.000097794345082862, 0.000369998664433527, 0.000699241419612492, 0.001041511593601482, 0.001335775967586111, 0.001513363005661080, 0.001512024052854210, 0.001292282575245647, 0.000852402910741175, 0.000237845095399279, -0.000458531344106017, -0.001107710877113322, -0.001566990390963083, -0.001710431193735069, -0.001461394216561484, -0.000819564995596107, 0.000125333340929399, 0.001199019317168316, 0.002169473500980469, 0.002792319280177214, 0.002866870662163649, 0.002290930866878644, 0.001100704907673480, -0.000516328530790399, -0.002243035863158312, -0.003688859468654476, -0.004472285396379554, -0.004313484308907802, -0.003116141834256676, -0.001017067737117166, 0.001613055660814351, 0.004224931456170525, 0.006196508693202270, 0.006971075945479586, 0.006198930990039089, 0.003849274053846188, 0.000261650017776247, -0.003883392014577992, -0.007678244207599024, -0.010171159926985415, -0.010584341389004935, -0.008520924878120863, -0.004111405600230054, 0.001942089793582858, 0.008446987602879255, 0.013924611888810799, 0.016907513230850324, 0.016275537240591227, 0.011561878706483661, 0.003159517846795821, -0.007627342018415888, -0.018714786943998040, -0.027545855699856577, -0.031527533359270804, -0.028522764468194239, -0.017305127467535198, 0.002115380882896933, 0.028367517836585164, 0.058831871715231798, 0.089984540025951881, 0.117919393961330910, 0.138960802368858470, 0.150258729900921100, 0.150258729900921100, 0.138960802368858470, 0.117919393961330910, 0.089984540025951881, 0.058831871715231798, 0.028367517836585164, 0.002115380882896933, -0.017305127467535198, -0.028522764468194239, -0.031527533359270804, -0.027545855699856577, -0.018714786943998040, -0.007627342018415888, 0.003159517846795821, 0.011561878706483661, 0.016275537240591227, 0.016907513230850324, 0.013924611888810799, 0.008446987602879255, 0.001942089793582858, -0.004111405600230054, -0.008520924878120863, -0.010584341389004935, -0.010171159926985415, -0.007678244207599024, -0.003883392014577992, 0.000261650017776247, 0.003849274053846188, 0.006198930990039089, 0.006971075945479586, 0.006196508693202270, 0.004224931456170525, 0.001613055660814351, -0.001017067737117166, -0.003116141834256676, -0.004313484308907802, -0.004472285396379554, -0.003688859468654476, -0.002243035863158312, -0.000516328530790399, 0.001100704907673480, 0.002290930866878644, 0.002866870662163649, 0.002792319280177214, 0.002169473500980469, 0.001199019317168316, 0.000125333340929399, -0.000819564995596107, -0.001461394216561484, -0.001710431193735069, -0.001566990390963083, -0.001107710877113322, -0.000458531344106017, 0.000237845095399279, 0.000852402910741175, 0.001292282575245647, 0.001512024052854210, 0.001513363005661080, 0.001335775967586111, 0.001041511593601482, 0.000699241419612492, 0.000369998664433527, 0.000097794345082862, -0.000094305597311178, -0.000202969232396477, -0.000239838685218700, -0.000225109758175834, -0.000181102741386044, -0.000127389313997705, -0.000077862936583202, -0.000040011820393130, -0.000017125474330604 } ; // Sample 1 Hz, pass 0.125, stop 0.192, ripple 0.1 dB, atten 100 dB, taps 64. Stop 0.192. double quiskFilt12_19Coefs[64] = { 0.000043810351462319, 0.000138863869398690, 0.000206835545025070, 0.000047730531591317, -0.000514727559529336, -0.001353635480056038, -0.001881242409327435, -0.001336759882352925, 0.000480762137654505, 0.002595795305500315, 0.003157538223935716, 0.000883738175457450, -0.003304786290465149, -0.006137600456523736, -0.004232173904239833, 0.002529546544381186, 0.009496143474996962, 0.009949625572871518, 0.000962602913419665, -0.012260655539427043, -0.018443416827456323, -0.008986096201165510, 0.012737225552167929, 0.030249086308101754, 0.024812387650292519, -0.007810917817793795, -0.047781081559953899, -0.059071807532626572, -0.012800932712041477, 0.089119808681493592, 0.208124268210933110, 0.287998295491409540, 0.287998295491409540, 0.208124268210933110, 0.089119808681493592, -0.012800932712041477, -0.059071807532626572, -0.047781081559953899, -0.007810917817793795, 0.024812387650292519, 0.030249086308101754, 0.012737225552167929, -0.008986096201165510, -0.018443416827456323, -0.012260655539427043, 0.000962602913419665, 0.009949625572871518, 0.009496143474996962, 0.002529546544381186, -0.004232173904239833, -0.006137600456523736, -0.003304786290465149, 0.000883738175457450, 0.003157538223935716, 0.002595795305500315, 0.000480762137654505, -0.001336759882352925, -0.001881242409327435, -0.001353635480056038, -0.000514727559529336, 0.000047730531591317, 0.000206835545025070, 0.000138863869398690, 0.000043810351462319} ; // Sample 185185 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.12960. double quiskFilt185D3Coefs[188] = { 0.000008153800001840, -0.000001771417630395, -0.000037253333929034, -0.000119009795238060, -0.000255018503860098, -0.000431457630502916, -0.000606779374823655, -0.000718366697089728, -0.000703620301380014, -0.000529751805487936, -0.000219462957628643, 0.000142545317473537, 0.000431747689511389, 0.000531458261578183, 0.000388343045150861, 0.000049369127393032, -0.000342917144392365, -0.000603313895145129, -0.000587692675369399, -0.000270442421243832, 0.000225386999468089, 0.000669074815263746, 0.000825032169620294, 0.000573830722863008, -0.000009077307935200, -0.000664918089414559, -0.001061106586632969, -0.000955502500127749, -0.000336438190374833, 0.000539349074607305, 0.001245645977048461, 0.001389173752996503, 0.000822043470106957, -0.000247598052622219, -0.001319476735963911, -0.001828796700280690, -0.001437569856610004, -0.000242431773066792, 0.001222656916942065, 0.002216144517102359, 0.002157389501918925, 0.000954312268698896, -0.000889647952809809, -0.002472890164473277, -0.002928202444412127, -0.001887404641539060, 0.000266028947341680, 0.002515528194768854, 0.003680340277064590, 0.003024505869869945, 0.000697099931502566, -0.002249597199494156, -0.004320335692842188, -0.004323014468691384, -0.002034738390180464, 0.001575270318365026, 0.004732326142178709, 0.005712473175796522, 0.003763483203528208, -0.000391719810437692, -0.004781111888508037, -0.007096880559266867, -0.005884712017661407, -0.001407862533738378, 0.004306693842081116, 0.008352211939490001, 0.008388529075785354, 0.003946736249321500, -0.003112792599933821, -0.009323923519118172, -0.011269282117577429, -0.007398426385575320, 0.000928531365753789, 0.009809484942446507, 0.014553037120437585, 0.012062615692744548, 0.002683413619215453, -0.009516487432546697, -0.018375440190605826, -0.018584023004946444, -0.008607549657362717, 0.007911844367040830, 0.023198314076417474, 0.028659214411537771, 0.019167047651360933, -0.003633593297082508, -0.030707268487267729, -0.048352925046987114, -0.043463395046782413, -0.009280832167164070, 0.050801866891763532, 0.123196454160356600, 0.188154012695948810, 0.226499569996940320, 0.226499569996940320, 0.188154012695948810, 0.123196454160356600, 0.050801866891763532, -0.009280832167164070, -0.043463395046782413, -0.048352925046987114, -0.030707268487267729, -0.003633593297082508, 0.019167047651360933, 0.028659214411537771, 0.023198314076417474, 0.007911844367040830, -0.008607549657362717, -0.018584023004946444, -0.018375440190605826, -0.009516487432546697, 0.002683413619215453, 0.012062615692744548, 0.014553037120437585, 0.009809484942446507, 0.000928531365753789, -0.007398426385575320, -0.011269282117577429, -0.009323923519118172, -0.003112792599933821, 0.003946736249321500, 0.008388529075785354, 0.008352211939490001, 0.004306693842081116, -0.001407862533738378, -0.005884712017661407, -0.007096880559266867, -0.004781111888508037, -0.000391719810437692, 0.003763483203528208, 0.005712473175796522, 0.004732326142178709, 0.001575270318365026, -0.002034738390180464, -0.004323014468691384, -0.004320335692842188, -0.002249597199494156, 0.000697099931502566, 0.003024505869869945, 0.003680340277064590, 0.002515528194768854, 0.000266028947341680, -0.001887404641539060, -0.002928202444412127, -0.002472890164473277, -0.000889647952809809, 0.000954312268698896, 0.002157389501918925, 0.002216144517102359, 0.001222656916942065, -0.000242431773066792, -0.001437569856610004, -0.001828796700280690, -0.001319476735963911, -0.000247598052622219, 0.000822043470106957, 0.001389173752996503, 0.001245645977048461, 0.000539349074607305, -0.000336438190374833, -0.000955502500127749, -0.001061106586632969, -0.000664918089414559, -0.000009077307935200, 0.000573830722863008, 0.000825032169620294, 0.000669074815263746, 0.000225386999468089, -0.000270442421243832, -0.000587692675369399, -0.000603313895145129, -0.000342917144392365, 0.000049369127393032, 0.000388343045150861, 0.000531458261578183, 0.000431747689511389, 0.000142545317473537, -0.000219462957628643, -0.000529751805487936, -0.000703620301380014, -0.000718366697089728, -0.000606779374823655, -0.000431457630502916, -0.000255018503860098, -0.000119009795238060, -0.000037253333929034, -0.000001771417630395, 0.000008153800001840 }; // Sample 185185 Hz, pass 15000, stop 23900, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.129060. double quiskFilt185D3XCoefs[88] = { -0.000026016801458962, -0.000079343977811083, -0.000167897725115826, -0.000272158478205181, -0.000343785933253942, -0.000310796788289393, -0.000102311891399797, 0.000311300138822939, 0.000877228005105512, 0.001440583394256035, 0.001767836749778265, 0.001621580974541500, 0.000871040137123456, -0.000402149294308734, -0.001857385353819294, -0.002952994474321905, -0.003118971956742465, -0.002002468636632821, 0.000304795748571584, 0.003168465665729574, 0.005527734084410955, 0.006236194024480606, 0.004538088065486723, 0.000504287301538830, -0.004776061900406583, -0.009396166048199123, -0.011236677659113514, -0.008814076686757433, -0.002068388398230007, 0.007257051941983628, 0.015896603006282241, 0.020037182698727726, 0.016744338396284194, 0.005368795820044257, -0.011616528320034477, -0.028774969855905743, -0.038977373476370786, -0.035506674315576942, -0.014373032297997279, 0.023936198172814224, 0.073933459676699551, 0.126134168736811850, 0.169387884611201690, 0.193878581402395330, 0.193878581402395330, 0.169387884611201690, 0.126134168736811850, 0.073933459676699551, 0.023936198172814224, -0.014373032297997279, -0.035506674315576942, -0.038977373476370786, -0.028774969855905743, -0.011616528320034477, 0.005368795820044257, 0.016744338396284194, 0.020037182698727726, 0.015896603006282241, 0.007257051941983628, -0.002068388398230007, -0.008814076686757433, -0.011236677659113514, -0.009396166048199123, -0.004776061900406583, 0.000504287301538830, 0.004538088065486723, 0.006236194024480606, 0.005527734084410955, 0.003168465665729574, 0.000304795748571584, -0.002002468636632821, -0.003118971956742465, -0.002952994474321905, -0.001857385353819294, -0.000402149294308734, 0.000871040137123456, 0.001621580974541500, 0.001767836749778265, 0.001440583394256035, 0.000877228005105512, 0.000311300138822939, -0.000102311891399797, -0.000310796788289393, -0.000343785933253942, -0.000272158478205181, -0.000167897725115826, -0.000079343977811083, -0.000026016801458962} ; // Sample 185185 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Stop 0.064800. double quiskFilt185D7Coefs[325] = { 0.000011585872492535, 0.000021202775655724, 0.000038515581433427, 0.000062668164659740, 0.000093940890103130, 0.000131718743859808, 0.000174225065604974, 0.000218342986026828, 0.000259582942086064, 0.000292202414812531, 0.000309501208323850, 0.000304347853118504, 0.000269885084834102, 0.000200329336288352, 0.000091873319388286, -0.000056460226867932, -0.000242180306367212, -0.000458826972767189, -0.000695972007921572, -0.000939539009494425, -0.001172660992563646, -0.001376927020458812, -0.001534012395041686, -0.001627510712907692, -0.001644810967208332, -0.001578811291153747, -0.001429231737210363, -0.001203341468259860, -0.000915956952592136, -0.000588604281778632, -0.000247881153416102, 0.000076883069806609, 0.000356496498766536, 0.000564970346134735, 0.000682503931650803, 0.000697978266499694, 0.000610677107413264, 0.000430929848100204, 0.000179551442826917, -0.000113968106450125, -0.000414397628381283, -0.000684546545073360, -0.000889508690226669, -0.001000889233610915, -0.001000492619169160, -0.000883003638604998, -0.000657261341613736, -0.000345878903792753, 0.000016835572177804, 0.000388523086839818, 0.000723605124037493, 0.000978796711705906, 0.001118627280774081, 0.001120302957105695, 0.000977241071844119, 0.000700761818102867, 0.000319615424985736, -0.000122724655145581, -0.000572787713987942, -0.000973362887973448, -0.001270584863164685, -0.001420984914880352, -0.001397605040893653, -0.001194338356762529, -0.000827834100503333, -0.000336591061237865, 0.000222813863757337, 0.000782022394777827, 0.001269065085645792, 0.001617440270226089, 0.001774989493019493, 0.001711406052073067, 0.001423329284260602, 0.000936230433482062, 0.000302669877122975, -0.000403051367712102, -0.001093347917242359, -0.001677989133371222, -0.002075657051446509, -0.002224973164684223, -0.002093532018815395, -0.001683654864926617, -0.001033944903045330, -0.000216202715201031, 0.000672136237235640, 0.001519308622149400, 0.002212998394841567, 0.002654922443391980, 0.002774368358702789, 0.002538866483308035, 0.001960451088476113, 0.001096459360528461, 0.000044471086033573, -0.001068263405090781, -0.002099826730828226, -0.002911349453455988, -0.003385273847682783, -0.003441820002543952, -0.003051407043926876, -0.002241202920048492, -0.001094628195429446, 0.000256492779785520, 0.001646511036377237, 0.002895722994780784, 0.003833041920244146, 0.004318777856326995, 0.004264570929820472, 0.003647733587396600, 0.002517835568167883, 0.000994251746281646, -0.000745501220005664, -0.002485634335945939, -0.003998039828567652, -0.005071301821004867, -0.005539183731069824, -0.005304874120435773, -0.004357624572350711, -0.002779195755674417, -0.000738704575887045, 0.001524133036686280, 0.003725875479734138, 0.005573480900438330, 0.006801730588660005, 0.007209350069135231, 0.006689128326667765, 0.005247829163413888, 0.003012735394874103, 0.000223174064082399, -0.002792831962376837, -0.005654763344137692, -0.007974895792849587, -0.009407569536250765, -0.009696510630814705, -0.008714169676261001, -0.006487651574925092, -0.003207133255888027, 0.000785450700374519, 0.005027410607157849, 0.008983570118297410, 0.012107159427564776, 0.013906909894651421, 0.014012809617679676, 0.012232695276105182, 0.008592471450916649, 0.003354235296550607, -0.002991194159451697, -0.009758117856276788, -0.016123999816583842, -0.021206724919405923, -0.024153695524852702, -0.024233748891356845, -0.020922161341036132, -0.013969353698339257, -0.003445298078014795, 0.010246061695767921, 0.026385065799221116, 0.043986586663902316, 0.061878202104145755, 0.078799201858789497, 0.093511010803744687, 0.104908248570820360, 0.112119405527806140, 0.114587041362813750, 0.112119405527806140, 0.104908248570820360, 0.093511010803744687, 0.078799201858789497, 0.061878202104145755, 0.043986586663902316, 0.026385065799221116, 0.010246061695767921, -0.003445298078014795, -0.013969353698339257, -0.020922161341036132, -0.024233748891356845, -0.024153695524852702, -0.021206724919405923, -0.016123999816583842, -0.009758117856276788, -0.002991194159451697, 0.003354235296550607, 0.008592471450916649, 0.012232695276105182, 0.014012809617679676, 0.013906909894651421, 0.012107159427564776, 0.008983570118297410, 0.005027410607157849, 0.000785450700374519, -0.003207133255888027, -0.006487651574925092, -0.008714169676261001, -0.009696510630814705, -0.009407569536250765, -0.007974895792849587, -0.005654763344137692, -0.002792831962376837, 0.000223174064082399, 0.003012735394874103, 0.005247829163413888, 0.006689128326667765, 0.007209350069135231, 0.006801730588660005, 0.005573480900438330, 0.003725875479734138, 0.001524133036686280, -0.000738704575887045, -0.002779195755674417, -0.004357624572350711, -0.005304874120435773, -0.005539183731069824, -0.005071301821004867, -0.003998039828567652, -0.002485634335945939, -0.000745501220005664, 0.000994251746281646, 0.002517835568167883, 0.003647733587396600, 0.004264570929820472, 0.004318777856326995, 0.003833041920244146, 0.002895722994780784, 0.001646511036377237, 0.000256492779785520, -0.001094628195429446, -0.002241202920048492, -0.003051407043926876, -0.003441820002543952, -0.003385273847682783, -0.002911349453455988, -0.002099826730828226, -0.001068263405090781, 0.000044471086033573, 0.001096459360528461, 0.001960451088476113, 0.002538866483308035, 0.002774368358702789, 0.002654922443391980, 0.002212998394841567, 0.001519308622149400, 0.000672136237235640, -0.000216202715201031, -0.001033944903045330, -0.001683654864926617, -0.002093532018815395, -0.002224973164684223, -0.002075657051446509, -0.001677989133371222, -0.001093347917242359, -0.000403051367712102, 0.000302669877122975, 0.000936230433482062, 0.001423329284260602, 0.001711406052073067, 0.001774989493019493, 0.001617440270226089, 0.001269065085645792, 0.000782022394777827, 0.000222813863757337, -0.000336591061237865, -0.000827834100503333, -0.001194338356762529, -0.001397605040893653, -0.001420984914880352, -0.001270584863164685, -0.000973362887973448, -0.000572787713987942, -0.000122724655145581, 0.000319615424985736, 0.000700761818102867, 0.000977241071844119, 0.001120302957105695, 0.001118627280774081, 0.000978796711705906, 0.000723605124037493, 0.000388523086839818, 0.000016835572177804, -0.000345878903792753, -0.000657261341613736, -0.000883003638604998, -0.001000492619169160, -0.001000889233610915, -0.000889508690226669, -0.000684546545073360, -0.000414397628381283, -0.000113968106450125, 0.000179551442826917, 0.000430929848100204, 0.000610677107413264, 0.000697978266499694, 0.000682503931650803, 0.000564970346134735, 0.000356496498766536, 0.000076883069806609, -0.000247881153416102, -0.000588604281778632, -0.000915956952592136, -0.001203341468259860, -0.001429231737210363, -0.001578811291153747, -0.001644810967208332, -0.001627510712907692, -0.001534012395041686, -0.001376927020458812, -0.001172660992563646, -0.000939539009494425, -0.000695972007921572, -0.000458826972767189, -0.000242180306367212, -0.000056460226867932, 0.000091873319388286, 0.000200329336288352, 0.000269885084834102, 0.000304347853118504, 0.000309501208323850, 0.000292202414812531, 0.000259582942086064, 0.000218342986026828, 0.000174225065604974, 0.000131718743859808, 0.000093940890103130, 0.000062668164659740, 0.000038515581433427, 0.000021202775655724, 0.000011585872492535} ; // Sample 133333 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.18000. double quiskFilt133D2Coefs[136] = { 0.000017194140195307, 0.000013031580406032, -0.000070982819622986, -0.000297799318127961, -0.000645057684247744, -0.000951723373793975, -0.000976667009837673, -0.000579840699091521, 0.000098129751533427, 0.000644977424009104, 0.000648591932388761, 0.000063466245825653, -0.000655952785922865, -0.000858530950797784, -0.000263313568128542, 0.000697280609267464, 0.001152025473909408, 0.000556416972642962, -0.000702600426682260, -0.001503408593721275, -0.000962293487226091, 0.000635424413378249, 0.001893865760533597, 0.001494654948692980, -0.000464212878209573, -0.002304129661798076, -0.002165029121341371, 0.000156986911460916, 0.002712310672598236, 0.002984071948396753, 0.000321449210044334, -0.003091821762536665, -0.003961473137247651, -0.001010870707262950, 0.003410242877909513, 0.005106330989341096, 0.001957278141537391, -0.003628441800145526, -0.006428886895772534, -0.003216116999687284, 0.003699894436571663, 0.007945926308831793, 0.004862613142073883, -0.003562107867854992, -0.009680253224586733, -0.006996529395398682, 0.003139846233471389, 0.011684868441375082, 0.009783362061267441, -0.002313232717655680, -0.014049355073607583, -0.013495163730537300, 0.000895100102567855, 0.016959635420547809, 0.018648538187471329, 0.001461901498462892, -0.020821848411902603, -0.026360133080398199, -0.005525410959722330, 0.026648719554864163, 0.039549486288596822, 0.013454287175328376, -0.037723817929648518, -0.068973339495709857, -0.034792487725714472, 0.073207163331834649, 0.211614628197181350, 0.308128392192117740, 0.308128392192117740, 0.211614628197181350, 0.073207163331834649, -0.034792487725714472, -0.068973339495709857, -0.037723817929648518, 0.013454287175328376, 0.039549486288596822, 0.026648719554864163, -0.005525410959722330, -0.026360133080398199, -0.020821848411902603, 0.001461901498462892, 0.018648538187471329, 0.016959635420547809, 0.000895100102567855, -0.013495163730537300, -0.014049355073607583, -0.002313232717655680, 0.009783362061267441, 0.011684868441375082, 0.003139846233471389, -0.006996529395398682, -0.009680253224586733, -0.003562107867854992, 0.004862613142073883, 0.007945926308831793, 0.003699894436571663, -0.003216116999687284, -0.006428886895772534, -0.003628441800145526, 0.001957278141537391, 0.005106330989341096, 0.003410242877909513, -0.001010870707262950, -0.003961473137247651, -0.003091821762536665, 0.000321449210044334, 0.002984071948396753, 0.002712310672598236, 0.000156986911460916, -0.002165029121341371, -0.002304129661798076, -0.000464212878209573, 0.001494654948692980, 0.001893865760533597, 0.000635424413378249, -0.000962293487226091, -0.001503408593721275, -0.000702600426682260, 0.000556416972642962, 0.001152025473909408, 0.000697280609267464, -0.000263313568128542, -0.000858530950797784, -0.000655952785922865, 0.000063466245825653, 0.000648591932388761, 0.000644977424009104, 0.000098129751533427, -0.000579840699091521, -0.000976667009837673, -0.000951723373793975, -0.000645057684247744, -0.000297799318127961, -0.000070982819622986, 0.000013031580406032, 0.000017194140195307 } ; // Sample 133333 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Stop 0.09000. double quiskFilt133D5Coefs[235] = { 0.000017189993342429, 0.000044738485582654, 0.000095017992345093, 0.000171520768649681, 0.000274754514100238, 0.000398861594001340, 0.000529984999270100, 0.000646117397525726, 0.000718766415753168, 0.000716925008973219, 0.000612844047432097, 0.000388876459995003, 0.000043995168792169, -0.000401638582561071, -0.000905542666180542, -0.001406385530252347, -0.001832160018119073, -0.002112253709578303, -0.002191408150519588, -0.002042816719676478, -0.001677284024812651, -0.001145752378681760, -0.000533679761891523, 0.000052653624322135, 0.000505907329874479, 0.000739851765907619, 0.000709229648947976, 0.000422523833395244, -0.000056020452981720, -0.000616720304461352, -0.001125962440173316, -0.001454995787757606, -0.001509950907384681, -0.001256131267758628, -0.000730326866325590, -0.000037158838317771, 0.000671036130692201, 0.001227356473019533, 0.001489601586267346, 0.001376632327061763, 0.000892728515088217, 0.000132987785167989, -0.000733102122237588, -0.001497662325285410, -0.001962695382200209, -0.001989694482613183, -0.001538410312914189, -0.000684278577781320, 0.000391518648789513, 0.001439060262231111, 0.002196666221903917, 0.002455206790769118, 0.002114248789295101, 0.001215358226109379, -0.000057550388771950, -0.001413462921977421, -0.002519018104662746, -0.003078793094584098, -0.002912162814601297, -0.002007172281996295, -0.000536145063816962, 0.001173803706907478, 0.002711347438868158, 0.003677986766436793, 0.003789135200490261, 0.002954134059121999, 0.001313489128052297, -0.000779246120784695, -0.002830527021932420, -0.004320552674014772, -0.004832115109577898, -0.004163289510814260, -0.002394421340991988, 0.000110859904206459, 0.002775804501582138, 0.004939612978506710, 0.006017429310863970, 0.005653427023669567, 0.003828044237650523, 0.000888978423738288, -0.002507663812902237, -0.005538235553289072, -0.007405523728182901, -0.007541454609909858, -0.005768568026570733, -0.002376693049722654, 0.001911054897098118, 0.006083411898142144, 0.009070202108022866, 0.010005711453736786, 0.008463803744478828, 0.004604287191332431, -0.000813142277372015, -0.006562286180605113, -0.011211419856533258, -0.013459517260663504, -0.012472773254562211, -0.008139991258903686, -0.001177765649827518, 0.006953975184466299, 0.014324290436841271, 0.018945676347138025, 0.019248150626647365, 0.014509895663648657, 0.005142708852136439, -0.007245145517153711, -0.020042796993989549, -0.030067767509750015, -0.034161762145356343, -0.029838715290132833, -0.015854346901954634, 0.007424778279719944, 0.037939728171909451, 0.072177533053372794, 0.105698112853527980, 0.133859311332239410, 0.152607173067114270, 0.159182344236760560, 0.152607173067114270, 0.133859311332239410, 0.105698112853527980, 0.072177533053372794, 0.037939728171909451, 0.007424778279719944, -0.015854346901954634, -0.029838715290132833, -0.034161762145356343, -0.030067767509750015, -0.020042796993989549, -0.007245145517153711, 0.005142708852136439, 0.014509895663648657, 0.019248150626647365, 0.018945676347138025, 0.014324290436841271, 0.006953975184466299, -0.001177765649827518, -0.008139991258903686, -0.012472773254562211, -0.013459517260663504, -0.011211419856533258, -0.006562286180605113, -0.000813142277372015, 0.004604287191332431, 0.008463803744478828, 0.010005711453736786, 0.009070202108022866, 0.006083411898142144, 0.001911054897098118, -0.002376693049722654, -0.005768568026570733, -0.007541454609909858, -0.007405523728182901, -0.005538235553289072, -0.002507663812902237, 0.000888978423738288, 0.003828044237650523, 0.005653427023669567, 0.006017429310863970, 0.004939612978506710, 0.002775804501582138, 0.000110859904206459, -0.002394421340991988, -0.004163289510814260, -0.004832115109577898, -0.004320552674014772, -0.002830527021932420, -0.000779246120784695, 0.001313489128052297, 0.002954134059121999, 0.003789135200490261, 0.003677986766436793, 0.002711347438868158, 0.001173803706907478, -0.000536145063816962, -0.002007172281996295, -0.002912162814601297, -0.003078793094584098, -0.002519018104662746, -0.001413462921977421, -0.000057550388771950, 0.001215358226109379, 0.002114248789295101, 0.002455206790769118, 0.002196666221903917, 0.001439060262231111, 0.000391518648789513, -0.000684278577781320, -0.001538410312914189, -0.001989694482613183, -0.001962695382200209, -0.001497662325285410, -0.000733102122237588, 0.000132987785167989, 0.000892728515088217, 0.001376632327061763, 0.001489601586267346, 0.001227356473019533, 0.000671036130692201, -0.000037158838317771, -0.000730326866325590, -0.001256131267758628, -0.001509950907384681, -0.001454995787757606, -0.001125962440173316, -0.000616720304461352, -0.000056020452981720, 0.000422523833395244, 0.000709229648947976, 0.000739851765907619, 0.000505907329874479, 0.000052653624322135, -0.000533679761891523, -0.001145752378681760, -0.001677284024812651, -0.002042816719676478, -0.002191408150519588, -0.002112253709578303, -0.001832160018119073, -0.001406385530252347, -0.000905542666180542, -0.000401638582561071, 0.000043995168792169, 0.000388876459995003, 0.000612844047432097, 0.000716925008973219, 0.000718766415753168, 0.000646117397525726, 0.000529984999270100, 0.000398861594001340, 0.000274754514100238, 0.000171520768649681, 0.000095017992345093, 0.000044738485582654, 0.000017189993342429} ; // Sample 111111 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.21600. double quiskFilt111D2Coefs[114] = { 0.000039619752517087, 0.000089439819783633, 0.000017353012666121, -0.000334808345968833, -0.000892257134326630, -0.001221700854092078, -0.000859742027523152, 0.000086110163390211, 0.000794431841612731, 0.000492910288706401, -0.000542730604541516, -0.001057738392194920, -0.000232619264909279, 0.001101735902638522, 0.001208303693873524, -0.000351788978766190, -0.001781186751638964, -0.001038581835235810, 0.001330430232082531, 0.002355496074120870, 0.000292615997120782, -0.002623102550864884, -0.002462643018753817, 0.001194053806308097, 0.003912675164153385, 0.001670607202119238, -0.003361036335001390, -0.004638914091859385, 0.000363767953875138, 0.005797757906125993, 0.004088942448683545, -0.003689094083671128, -0.007701448612726584, -0.001601464053307583, 0.007864313939600763, 0.007963248868264130, -0.003156323310881499, -0.011852746523309575, -0.005390083465132761, 0.009915212572859983, 0.014053676129843581, -0.000996935620086296, -0.017619302590712586, -0.012439281622203873, 0.011722997082370391, 0.024364733312011930, 0.004596957308944789, -0.026911691600293927, -0.027288530345555617, 0.013072844783675014, 0.047281998734662697, 0.021354076339639792, -0.051099079289920336, -0.080397920778604998, 0.013794073914731197, 0.205298935938689170, 0.362799183591728360, 0.362799183591728360, 0.205298935938689170, 0.013794073914731197, -0.080397920778604998, -0.051099079289920336, 0.021354076339639792, 0.047281998734662697, 0.013072844783675014, -0.027288530345555617, -0.026911691600293927, 0.004596957308944789, 0.024364733312011930, 0.011722997082370391, -0.012439281622203873, -0.017619302590712586, -0.000996935620086296, 0.014053676129843581, 0.009915212572859983, -0.005390083465132761, -0.011852746523309575, -0.003156323310881499, 0.007963248868264130, 0.007864313939600763, -0.001601464053307583, -0.007701448612726584, -0.003689094083671128, 0.004088942448683545, 0.005797757906125993, 0.000363767953875138, -0.004638914091859385, -0.003361036335001390, 0.001670607202119238, 0.003912675164153385, 0.001194053806308097, -0.002462643018753817, -0.002623102550864884, 0.000292615997120782, 0.002355496074120870, 0.001330430232082531, -0.001038581835235810, -0.001781186751638964, -0.000351788978766190, 0.001208303693873524, 0.001101735902638522, -0.000232619264909279, -0.001057738392194920, -0.000542730604541516, 0.000492910288706401, 0.000794431841612731, 0.000086110163390211, -0.000859742027523152, -0.001221700854092078, -0.000892257134326630, -0.000334808345968833, 0.000017353012666121, 0.000089439819783633, 0.000039619752517087 } ; // Sample 111111 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Stop 0.10800. double quiskFilt111D4Coefs[196] = { 0.000022860383861326, 0.000070265173417164, 0.000160689233204503, 0.000301317969124407, 0.000487289901409396, 0.000694724116305488, 0.000878636067621920, 0.000977522977076171, 0.000925771316840867, 0.000672305339588912, 0.000201226295657756, -0.000452162019544330, -0.001196628260487459, -0.001896523042546486, -0.002399782411882304, -0.002577406131356652, -0.002364065883391685, -0.001786962447427500, -0.000971468216463463, -0.000117441349581108, 0.000550823899522796, 0.000848990131462632, 0.000692513431543379, 0.000131676598678132, -0.000652871765004500, -0.001397429828707858, -0.001834711252195214, -0.001782286112376423, -0.001211048928870428, -0.000268185005007021, 0.000757996926666718, 0.001525273309644227, 0.001751649817944780, 0.001319320688138531, 0.000330934715806419, -0.000906405873937246, -0.001970890581915849, -0.002464861139454794, -0.002158210203051176, -0.001085620699944977, 0.000441507737096167, 0.001920949956624443, 0.002821890381744697, 0.002772521251916338, 0.001707992629296951, -0.000078236168178539, -0.002007203892070514, -0.003396752476301502, -0.003697747220029350, -0.002703958879036829, -0.000657405952388967, 0.001798494644242414, 0.003814960168125246, 0.004625841420163100, 0.003831836297877268, 0.001577797389627854, -0.001450651164746532, -0.004226329291915980, -0.005721230469088120, -0.005278368569659456, -0.002883121089582856, 0.000773112126565357, 0.004478776308038774, 0.006893091575659842, 0.007019574634915599, 0.004598796615908167, 0.000271268071355489, -0.004569531219948477, -0.008209861014252150, -0.009205194241390222, -0.006929272243366950, -0.001881659896440290, 0.004379813721900100, 0.009694113972501929, 0.012015064656800249, 0.010162418707817443, 0.004341783259066366, -0.003775178431738174, -0.011484866194632987, -0.015901979746403339, -0.014972424881419052, -0.008312775352876528, 0.002435156726078577, 0.013913027108919607, 0.021990371341685223, 0.023101099895195237, 0.015573244973319158, 0.000514891807100321, -0.018080409101544084, -0.034128539734629829, -0.040997556950638683, -0.033400949657662792, -0.009105399838522790, 0.030066051833635116, 0.078279007079479407, 0.126836610192946620, 0.166170707028785000, 0.188161385669205480, 0.188161385669205480, 0.166170707028785000, 0.126836610192946620, 0.078279007079479407, 0.030066051833635116, -0.009105399838522790, -0.033400949657662792, -0.040997556950638683, -0.034128539734629829, -0.018080409101544084, 0.000514891807100321, 0.015573244973319158, 0.023101099895195237, 0.021990371341685223, 0.013913027108919607, 0.002435156726078577, -0.008312775352876528, -0.014972424881419052, -0.015901979746403339, -0.011484866194632987, -0.003775178431738174, 0.004341783259066366, 0.010162418707817443, 0.012015064656800249, 0.009694113972501929, 0.004379813721900100, -0.001881659896440290, -0.006929272243366950, -0.009205194241390222, -0.008209861014252150, -0.004569531219948477, 0.000271268071355489, 0.004598796615908167, 0.007019574634915599, 0.006893091575659842, 0.004478776308038774, 0.000773112126565357, -0.002883121089582856, -0.005278368569659456, -0.005721230469088120, -0.004226329291915980, -0.001450651164746532, 0.001577797389627854, 0.003831836297877268, 0.004625841420163100, 0.003814960168125246, 0.001798494644242414, -0.000657405952388967, -0.002703958879036829, -0.003697747220029350, -0.003396752476301502, -0.002007203892070514, -0.000078236168178539, 0.001707992629296951, 0.002772521251916338, 0.002821890381744697, 0.001920949956624443, 0.000441507737096167, -0.001085620699944977, -0.002158210203051176, -0.002464861139454794, -0.001970890581915849, -0.000906405873937246, 0.000330934715806419, 0.001319320688138531, 0.001751649817944780, 0.001525273309644227, 0.000757996926666718, -0.000268185005007021, -0.001211048928870428, -0.001782286112376423, -0.001834711252195214, -0.001397429828707858, -0.000652871765004500, 0.000131676598678132, 0.000692513431543379, 0.000848990131462632, 0.000550823899522796, -0.000117441349581108, -0.000971468216463463, -0.001786962447427500, -0.002364065883391685, -0.002577406131356652, -0.002399782411882304, -0.001896523042546486, -0.001196628260487459, -0.000452162019544330, 0.000201226295657756, 0.000672305339588912, 0.000925771316840867, 0.000977522977076171, 0.000878636067621920, 0.000694724116305488, 0.000487289901409396, 0.000301317969124407, 0.000160689233204503, 0.000070265173417164, 0.000022860383861326} ; // Sample 53333 Hz, pass 20000, stop 24000, ripple 0.1 dB, atten 100 dB. For SDR-IQ. Stop 0.45000. double quiskFilt53D1Coefs[55] = { 0.000318858391362187, 0.001662116369387873, -0.000065237353639775, -0.000854885424783294, 0.001693126335254083, -0.002034310867663472, 0.001354648789538254, 0.000509693525155950, -0.003079059747940221, 0.005242349925004462, -0.005626507739484119, 0.003235398612833476, 0.001883583294529978, -0.008273775245721798, 0.013282431836060808, -0.013924391581141530, 0.008176677795586052, 0.003763659697675038, -0.018814370186261472, 0.031357304759835808, -0.034684131608746831, 0.023184334016039702, 0.005435239957731122, -0.048724194253317150, 0.099481724552805198, -0.147334801628740130, 0.181502639813268140, 0.806108236192275450, 0.181502639813268140, -0.147334801628740130, 0.099481724552805198, -0.048724194253317150, 0.005435239957731122, 0.023184334016039702, -0.034684131608746831, 0.031357304759835808, -0.018814370186261472, 0.003763659697675038, 0.008176677795586052, -0.013924391581141530, 0.013282431836060808, -0.008273775245721798, 0.001883583294529978, 0.003235398612833476, -0.005626507739484119, 0.005242349925004462, -0.003079059747940221, 0.000509693525155950, 0.001354648789538254, -0.002034310867663472, 0.001693126335254083, -0.000854885424783294, -0.000065237353639775, 0.001662116369387873, 0.000318858391362187 } ; // Sample 53333 Hz, pass 10000, stop 12000, ripple 0.5 dB, atten 100 dB. For SDR-IQ. Stop 0.22500. double quiskFilt53D2Coefs[93] = { 0.000107966318729964, 0.000421475598772498, 0.000731343669484184, 0.000328611865414609, -0.001457272471508304, -0.004143803290279123, -0.005736802939367581, -0.004303861070721504, -0.000415676176666607, 0.002561521351129964, 0.001705074918770091, -0.001794491466202784, -0.003398011312785532, -0.000595401366072839, 0.003389160538244070, 0.003117806598779015, -0.001738195724034938, -0.004960858372597238, -0.001539269216218705, 0.004783351138955084, 0.005278243767957266, -0.001906381347753796, -0.007653356303201065, -0.003190874189611138, 0.006849740993527085, 0.008664448318071482, -0.002035800124581497, -0.011780892066463697, -0.005873932705860416, 0.009972743922291657, 0.014072286848767549, -0.002113998573380457, -0.018521807368841001, -0.010490752431554192, 0.015285369742599874, 0.023814301314901452, -0.002148815334259815, -0.031770485009434718, -0.020238958138733353, 0.027248391304817831, 0.048071554306549469, -0.002165663523025174, -0.075199791717139086, -0.060076551864238638, 0.094944856808714839, 0.301769455144326630, 0.397829555404577600, 0.301769455144326630, 0.094944856808714839, -0.060076551864238638, -0.075199791717139086, -0.002165663523025174, 0.048071554306549469, 0.027248391304817831, -0.020238958138733353, -0.031770485009434718, -0.002148815334259815, 0.023814301314901452, 0.015285369742599874, -0.010490752431554192, -0.018521807368841001, -0.002113998573380457, 0.014072286848767549, 0.009972743922291657, -0.005873932705860416, -0.011780892066463697, -0.002035800124581497, 0.008664448318071482, 0.006849740993527085, -0.003190874189611138, -0.007653356303201065, -0.001906381347753796, 0.005278243767957266, 0.004783351138955084, -0.001539269216218705, -0.004960858372597238, -0.001738195724034938, 0.003117806598779015, 0.003389160538244070, -0.000595401366072839, -0.003398011312785532, -0.001794491466202784, 0.001705074918770091, 0.002561521351129964, -0.000415676176666607, -0.004303861070721504, -0.005736802939367581, -0.004143803290279123, -0.001457272471508304, 0.000328611865414609, 0.000731343669484184, 0.000421475598772498, 0.000107966318729964} ; // Sample 240 kHz, pass 15, stop 23.9, ripple 0. 1dB, atten 100 dB, taps 114. For 240 to 48 decimation by 5. Stop 0.09958. double quiskFilt240D5Coefs[114] = { -0.000017444714121896, -0.000043389176259008, -0.000086666475464372, -0.000143622066705595, -0.000204429258992282, -0.000250894192563019, -0.000258038648420713, -0.000198760816315186, -0.000051592624047688, 0.000190007232237523, 0.000509003255256297, 0.000859996990289808, 0.001171187148400100, 0.001354817951508860, 0.001325999614958582, 0.001026888404781159, 0.000450896776475450, -0.000340058091672613, -0.001212260716607277, -0.001975712012888962, -0.002419081295027340, -0.002359587962889753, -0.001697757353388466, -0.000463309281242825, 0.001162369385377015, 0.002858574184542211, 0.004216991598475732, 0.004827550436585937, 0.004383011824547803, 0.002778680650352727, 0.000180287057286554, -0.002963889630832239, -0.005980581348043338, -0.008097241865875090, -0.008616599305826346, -0.007104942880323794, -0.003549433861261754, 0.001560075425221182, 0.007257901257043677, 0.012249987278338943, 0.015166545447995922, 0.014877026236042860, 0.010803636353332058, 0.003161070172512297, -0.006942541244647841, -0.017585167076596235, -0.026297182632904086, -0.030480128886681127, -0.027906762548949221, -0.017206725660431417, 0.001763368880847165, 0.027750612266565198, 0.058186952307218993, 0.089522326728125629, 0.117760091355900630, 0.139101943345962650, 0.150584021572851110, 0.150584021572851110, 0.139101943345962650, 0.117760091355900630, 0.089522326728125629, 0.058186952307218993, 0.027750612266565198, 0.001763368880847165, -0.017206725660431417, -0.027906762548949221, -0.030480128886681127, -0.026297182632904086, -0.017585167076596235, -0.006942541244647841, 0.003161070172512297, 0.010803636353332058, 0.014877026236042860, 0.015166545447995922, 0.012249987278338943, 0.007257901257043677, 0.001560075425221182, -0.003549433861261754, -0.007104942880323794, -0.008616599305826346, -0.008097241865875090, -0.005980581348043338, -0.002963889630832239, 0.000180287057286554, 0.002778680650352727, 0.004383011824547803, 0.004827550436585937, 0.004216991598475732, 0.002858574184542211, 0.001162369385377015, -0.000463309281242825, -0.001697757353388466, -0.002359587962889753, -0.002419081295027340, -0.001975712012888962, -0.001212260716607277, -0.000340058091672613, 0.000450896776475450, 0.001026888404781159, 0.001325999614958582, 0.001354817951508860, 0.001171187148400100, 0.000859996990289808, 0.000509003255256297, 0.000190007232237523, -0.000051592624047688, -0.000198760816315186, -0.000258038648420713, -0.000250894192563019, -0.000204429258992282, -0.000143622066705595, -0.000086666475464372, -0.000043389176259008, -0.000017444714121896} ; // Sample 240 kHz, pass 20, stop 24, ripple 0. 1dB, atten 100 dB, taps 114. For 240 to 48 decimation by 5. Stop 0.1000. double quiskFilt240D5CoefsSharp[246] = { 0.000011951828200011, 0.000019798433756403, 0.000028547330106604, 0.000030165284908057, 0.000016460532579755, -0.000020835366942643, -0.000087256395370183, -0.000182447830402188, -0.000297836387286273, -0.000416082361724969, -0.000513090543707066, -0.000562800094080439, -0.000543922161049598, -0.000447038893351438, -0.000279964105369211, -0.000069269573936326, 0.000143339868281261, 0.000309776397278667, 0.000387771231401110, 0.000353469185042608, 0.000210686954436390, -0.000006554284588476, -0.000240063519947365, -0.000421527417296624, -0.000491443283168306, -0.000417820101680067, -0.000208868052760534, 0.000085048027839757, 0.000382180878613336, 0.000591123735768924, 0.000638042870263572, 0.000491558598565883, 0.000177179393286866, -0.000224481053594759, -0.000597014064504330, -0.000820930704466417, -0.000810918218693337, -0.000546326732285124, -0.000084459306793206, 0.000449422013818846, 0.000894687281371102, 0.001102541594699144, 0.000984325470442889, 0.000545624937191001, -0.000106146183328305, -0.000785797405770491, -0.001281535037100789, -0.001419612701203994, -0.001123137180667268, -0.000445673862380164, 0.000433514280597531, 0.001254730807221768, 0.001752968220115270, 0.001741675133186359, 0.001179202567033726, 0.000195102369455356, -0.000935783344044036, -0.001867876483977602, -0.002288593398642863, -0.002020698232986274, -0.001090456401574151, 0.000263178814654847, 0.001646402890369986, 0.002622726888175473, 0.002848310252497599, 0.002189220340667481, 0.000781654013623377, -0.000988901141783250, -0.002589700588821625, -0.003498176390167329, -0.003369141152473258, -0.002159241772770695, -0.000165464996932323, 0.002041618007644499, 0.003777187265991297, 0.004450866229775656, 0.003762315917274342, 0.001820394865830094, -0.000858234059046015, -0.003480363951041699, -0.005206132491721142, -0.005412440056656052, -0.003908911556192801, -0.001033963211572532, 0.002409267811432101, 0.005369858454077349, 0.006862619655562839, 0.006286791984567192, 0.003649433286047820, -0.000385090824056697, -0.004649684536230074, -0.007801516508809942, -0.008732884415488085, -0.006943637236744675, -0.002754601930921507, 0.002718968772510816, 0.007846810206617289, 0.010951016745475875, 0.010832279872067337, 0.007196213900006544, 0.000837720738654166, -0.006496855603590420, -0.012558347528192997, -0.015246550948573622, -0.013285617706403107, -0.006719315573973105, 0.002942907242266441, 0.013010190699738699, 0.020286552390091313, 0.021982424443790855, 0.016621666248368951, 0.004683273039499340, -0.011231582005110220, -0.026802267461528154, -0.036907110368292514, -0.036858745295310878, -0.023657596515413496, 0.003060851507965577, 0.040649713296411087, 0.083777373113400611, 0.125416065458074430, 0.158282028171104980, 0.176396323031566690, 0.176396323031566690, 0.158282028171104980, 0.125416065458074430, 0.083777373113400611, 0.040649713296411087, 0.003060851507965577, -0.023657596515413496, -0.036858745295310878, -0.036907110368292514, -0.026802267461528154, -0.011231582005110220, 0.004683273039499340, 0.016621666248368951, 0.021982424443790855, 0.020286552390091313, 0.013010190699738699, 0.002942907242266441, -0.006719315573973105, -0.013285617706403107, -0.015246550948573622, -0.012558347528192997, -0.006496855603590420, 0.000837720738654166, 0.007196213900006544, 0.010832279872067337, 0.010951016745475875, 0.007846810206617289, 0.002718968772510816, -0.002754601930921507, -0.006943637236744675, -0.008732884415488085, -0.007801516508809942, -0.004649684536230074, -0.000385090824056697, 0.003649433286047820, 0.006286791984567192, 0.006862619655562839, 0.005369858454077349, 0.002409267811432101, -0.001033963211572532, -0.003908911556192801, -0.005412440056656052, -0.005206132491721142, -0.003480363951041699, -0.000858234059046015, 0.001820394865830094, 0.003762315917274342, 0.004450866229775656, 0.003777187265991297, 0.002041618007644499, -0.000165464996932323, -0.002159241772770695, -0.003369141152473258, -0.003498176390167329, -0.002589700588821625, -0.000988901141783250, 0.000781654013623377, 0.002189220340667481, 0.002848310252497599, 0.002622726888175473, 0.001646402890369986, 0.000263178814654847, -0.001090456401574151, -0.002020698232986274, -0.002288593398642863, -0.001867876483977602, -0.000935783344044036, 0.000195102369455356, 0.001179202567033726, 0.001741675133186359, 0.001752968220115270, 0.001254730807221768, 0.000433514280597531, -0.000445673862380164, -0.001123137180667268, -0.001419612701203994, -0.001281535037100789, -0.000785797405770491, -0.000106146183328305, 0.000545624937191001, 0.000984325470442889, 0.001102541594699144, 0.000894687281371102, 0.000449422013818846, -0.000084459306793206, -0.000546326732285124, -0.000810918218693337, -0.000820930704466417, -0.000597014064504330, -0.000224481053594759, 0.000177179393286866, 0.000491558598565883, 0.000638042870263572, 0.000591123735768924, 0.000382180878613336, 0.000085048027839757, -0.000208868052760534, -0.000417820101680067, -0.000491443283168306, -0.000421527417296624, -0.000240063519947365, -0.000006554284588476, 0.000210686954436390, 0.000353469185042608, 0.000387771231401110, 0.000309776397278667, 0.000143339868281261, -0.000069269573936326, -0.000279964105369211, -0.000447038893351438, -0.000543922161049598, -0.000562800094080439, -0.000513090543707066, -0.000416082361724969, -0.000297836387286273, -0.000182447830402188, -0.000087256395370183, -0.000020835366942643, 0.000016460532579755, 0.000030165284908057, 0.000028547330106604, 0.000019798433756403, 0.000011951828200011 }; // Sample 48 kHz, pass 10, stop 12, ripple 0.1 dB, atten 100 dB. Stop 0.25000. double quiskFilt48dec24Coefs[98] = { 0.000036864882767612, 0.000009858596392836, -0.000330770380800406, -0.001009174072411182, -0.001404963853116591, -0.000770236458542885, 0.000523955998497470, 0.000947009978368078, -0.000170647420729277, -0.001215337186275615, -0.000339882761263432, 0.001380697691347411, 0.001052816245779061, -0.001289457483737270, -0.001905995022750999, 0.000806360758757266, 0.002752294066736399, 0.000151371304906695, -0.003382080182092562, -0.001586160863198252, 0.003550356871637037, 0.003397108074666923, -0.003014198882506884, -0.005368247151920206, 0.001578030229641401, 0.007172700113962798, 0.000859017219495951, -0.008394441438252027, -0.004260927420042382, 0.008565389049746911, 0.008423570232799422, -0.007213182430375741, -0.012960608818773384, 0.003906137602881253, 0.017299646590834120, 0.001710647317106962, -0.020687435471124054, -0.009911496013769150, 0.022192116474879110, 0.020997544995749250, -0.020577450597980520, -0.035567363858049900, 0.013892294138831605, 0.055472458661532512, 0.002296277239682308, -0.087929779622300100, -0.045452533452794319, 0.182125569604839360, 0.410917417297433360, 0.410917417297433360, 0.182125569604839360, -0.045452533452794319, -0.087929779622300100, 0.002296277239682308, 0.055472458661532512, 0.013892294138831605, -0.035567363858049900, -0.020577450597980520, 0.020997544995749250, 0.022192116474879110, -0.009911496013769150, -0.020687435471124054, 0.001710647317106962, 0.017299646590834120, 0.003906137602881253, -0.012960608818773384, -0.007213182430375741, 0.008423570232799422, 0.008565389049746911, -0.004260927420042382, -0.008394441438252027, 0.000859017219495951, 0.007172700113962798, 0.001578030229641401, -0.005368247151920206, -0.003014198882506884, 0.003397108074666923, 0.003550356871637037, -0.001586160863198252, -0.003382080182092562, 0.000151371304906695, 0.002752294066736399, 0.000806360758757266, -0.001905995022750999, -0.001289457483737270, 0.001052816245779061, 0.001380697691347411, -0.000339882761263432, -0.001215337186275615, -0.000170647420729277, 0.000947009978368078, 0.000523955998497470, -0.000770236458542885, -0.001404963853116591, -0.001009174072411182, -0.000330770380800406, 0.000009858596392836, 0.000036864882767612} ; // Sample 24 kHz, pass 4, stop 6, ripple 0.2 dB, atten 100 dB. Stop 0.25000. double quiskAudio24p4Coefs[47] = { -0.000088032928341076, -0.000644655891856698, -0.001950684938386873, -0.003218845681314026, -0.002450782287864210, 0.001217506567762789, 0.004686926326285676, 0.002765800843238593, -0.004566450766965229, -0.008584510412060854, -0.000971556018221359, 0.012083832500170146, 0.012188815169382777, -0.007290936633701373, -0.024348624812992169, -0.010068583077594291, 0.027777796699414107, 0.039152990662982279, -0.009401736137370085, -0.072784723467554810, -0.051588082257896843, 0.099826186027899166, 0.298074745160505860, 0.389807370973666690, 0.298074745160505860, 0.099826186027899166, -0.051588082257896843, -0.072784723467554810, -0.009401736137370085, 0.039152990662982279, 0.027777796699414107, -0.010068583077594291, -0.024348624812992169, -0.007290936633701373, 0.012188815169382777, 0.012083832500170146, -0.000971556018221359, -0.008584510412060854, -0.004566450766965229, 0.002765800843238593, 0.004686926326285676, 0.001217506567762789, -0.002450782287864210, -0.003218845681314026, -0.001950684938386873, -0.000644655891856698, -0.000088032928341076} ; // Sample 24 kHz, pass 6, stop 8, ripple 0.5 dB, atten 80 dB. Stop 0.33333. double quiskAudio24p6Coefs[36] = { 0.001199140008010727, 0.005953815908571521, 0.008621055763448699, -0.000319602525571569, -0.008665733839154772, 0.003122601697996235, 0.011839435384729619, -0.008973143363910490, -0.014884256392667099, 0.019451226278492342, 0.015232717446420085, -0.036364345084318225, -0.008723687718470995, 0.063232433222709966, -0.014104739941611717, -0.115885442639735490, 0.103975832351096060, 0.487646324142562260, 0.487646324142562260, 0.103975832351096060, -0.115885442639735490, -0.014104739941611717, 0.063232433222709966, -0.008723687718470995, -0.036364345084318225, 0.015232717446420085, 0.019451226278492342, -0.014884256392667099, -0.008973143363910490, 0.011839435384729619, 0.003122601697996235, -0.008665733839154772, -0.000319602525571569, 0.008621055763448699, 0.005953815908571521, 0.001199140008010727} ; // Sample 48 kHz, pass 6, stop 8, ripple 0.5 dB, atten 80 dB. Stop 0.16667. double quiskAudio48p6Coefs[71] = { 0.000324677779792651, 0.001038192405843851, 0.002082337464742640, 0.002938055116822665, 0.002811674671240099, 0.001132278163758895, -0.001835394694865431, -0.004766409947196539, -0.005833007003128954, -0.003914015660218843, 0.000296099005521212, 0.004239593489554206, 0.004918390640978499, 0.001100872619673516, -0.005241634309386784, -0.009658192522859132, -0.008117324326241930, -0.000324815284776402, 0.009102631659469559, 0.013098226740520415, 0.007176675441219364, -0.006349840429806648, -0.018522542400385748, -0.019189364957006558, -0.004749023128788906, 0.017303403623348305, 0.031306220127229140, 0.023400239035184393, -0.007229519056042042, -0.043717246110810550, -0.058176618846235130, -0.027325746983863020, 0.051711450483087174, 0.155566868220561340, 0.243667260926508620, 0.278152523812557280, 0.243667260926508620, 0.155566868220561340, 0.051711450483087174, -0.027325746983863020, -0.058176618846235130, -0.043717246110810550, -0.007229519056042042, 0.023400239035184393, 0.031306220127229140, 0.017303403623348305, -0.004749023128788906, -0.019189364957006558, -0.018522542400385748, -0.006349840429806648, 0.007176675441219364, 0.013098226740520415, 0.009102631659469559, -0.000324815284776402, -0.008117324326241930, -0.009658192522859132, -0.005241634309386784, 0.001100872619673516, 0.004918390640978499, 0.004239593489554206, 0.000296099005521212, -0.003914015660218843, -0.005833007003128954, -0.004766409947196539, -0.001835394694865431, 0.001132278163758895, 0.002811674671240099, 0.002938055116822665, 0.002082337464742640, 0.001038192405843851, 0.000324677779792651} ; // Sample 96 kHz, pass 6, stop 40, ripple 0.1 dB, atten 100 dB. Stop 0.41667. double quiskAudio96Coefs[11] = { -0.004756607210954994, -0.022893760473075838, -0.023609616122334920, 0.078161168368381481, 0.277880235815005590, 0.388489826271597950, 0.277880235815005590, 0.078161168368381481, -0.023609616122334920, -0.022893760473075838, -0.004756607210954994} ; // Sample 12000 kHz, high pass, stop 180, pass 300, ripple 0.2 dB, atten 80 dB. double quiskAudioFmHpCoefs[309] = { 0.004847574947800705, -0.001211970386842814, -0.001072277374239886, -0.000949749961336003, -0.000841696354699768, -0.000745515693376396, -0.000658731927598885, -0.000579117971409598, -0.000504808183463150, -0.000434052387522716, -0.000365311474947399, -0.000297420057921267, -0.000229505695217796, -0.000160920338573639, -0.000091306103977099, -0.000020600671979957, 0.000051022545303487, 0.000123144667419350, 0.000195091536211946, 0.000265999359621072, 0.000334844261309097, 0.000400429077199748, 0.000461460673600523, 0.000516639603401830, 0.000564613893906762, 0.000603966827912324, 0.000633383885155741, 0.000651723486505544, 0.000657887414710607, 0.000650908078289207, 0.000630221666830102, 0.000595435888069700, 0.000546108904674455, 0.000484276489349049, 0.000401543327440382, 0.000321419603506285, 0.000213106256109367, 0.000098353002391692, -0.000019740287652141, -0.000144911454925575, -0.000277381849908065, -0.000413476038173425, -0.000548427361576298, -0.000678490099554352, -0.000801069365710719, -0.000914049078670187, -0.001015286248346293, -0.001102331400542105, -0.001172396297916355, -0.001222632870457348, -0.001250498303855702, -0.001253983783014675, -0.001231724573461644, -0.001182999511712966, -0.001107609474592948, -0.001005802502109255, -0.000878333102915519, -0.000726459269042778, -0.000551839538058223, -0.000356598632546370, -0.000143511677076383, 0.000084082690787220, 0.000322510489680255, 0.000567640643123008, 0.000814725473802231, 0.001058851063175263, 0.001295215851931261, 0.001517809497406495, 0.001723717744529424, 0.001902986849115314, 0.002058196188280081, 0.002178885915107971, 0.002262004073121292, 0.002306568447922007, 0.002308817130050681, 0.002265197627398382, 0.002174415827424258, 0.002036784086082496, 0.001852852576328433, 0.001623326794876901, 0.001349852467618926, 0.001035442578833791, 0.000684336173595900, 0.000301699601011732, -0.000106613479977550, -0.000534173868829619, -0.000973944167066713, -0.001418238552947833, -0.001858773604862586, -0.002286765126902860, -0.002693131197271969, -0.003068872591348129, -0.003405360512862820, -0.003694294048148267, -0.003927679645897309, -0.004098170195163846, -0.004199334823619039, -0.004225516845056660, -0.004171926884864147, -0.004035318109791245, -0.003814086552001789, -0.003507185822613928, -0.003116677958603595, -0.002643536244472083, -0.002094553515010935, -0.001473198308268938, -0.000787663079055384, -0.000048057914319065, 0.000736224014748010, 0.001553680380245313, 0.002390615203692300, 0.003232587312827377, 0.004064917562862491, 0.004872099692091644, 0.005637649839955575, 0.006344792681250736, 0.006977074214765010, 0.007518456060848391, 0.007953298539805269, 0.008266566568951741, 0.008444193362869966, 0.008473441636160825, 0.008343141792745356, 0.008043815615010122, 0.007567858472781280, 0.006909789777373219, 0.006066331643824790, 0.005036377728498742, 0.003821244456796700, 0.002425048400384444, 0.000854549919626146, -0.000881361873217043, -0.002771584559469569, -0.004802304296173217, -0.006957451254254373, -0.009219821548686471, -0.011569065498728633, -0.013984260863667768, -0.016442032516463558, -0.018919305853375375, -0.021391356610149178, -0.023832595189340611, -0.026218718241990988, -0.028524575634244292, -0.030725193547532524, -0.032797022202043544, -0.034717887030001365, -0.036466683292335302, -0.038023870249327039, -0.039372161079335152, -0.040496648982101487, -0.041384719119703033, -0.042026270620733261, -0.042414057053836371, 0.957456210208300410, -0.042414057053836371, -0.042026270620733261, -0.041384719119703033, -0.040496648982101487, -0.039372161079335152, -0.038023870249327039, -0.036466683292335302, -0.034717887030001365, -0.032797022202043544, -0.030725193547532524, -0.028524575634244292, -0.026218718241990988, -0.023832595189340611, -0.021391356610149178, -0.018919305853375375, -0.016442032516463558, -0.013984260863667768, -0.011569065498728633, -0.009219821548686471, -0.006957451254254373, -0.004802304296173217, -0.002771584559469569, -0.000881361873217043, 0.000854549919626146, 0.002425048400384444, 0.003821244456796700, 0.005036377728498742, 0.006066331643824790, 0.006909789777373219, 0.007567858472781280, 0.008043815615010122, 0.008343141792745356, 0.008473441636160825, 0.008444193362869966, 0.008266566568951741, 0.007953298539805269, 0.007518456060848391, 0.006977074214765010, 0.006344792681250736, 0.005637649839955575, 0.004872099692091644, 0.004064917562862491, 0.003232587312827377, 0.002390615203692300, 0.001553680380245313, 0.000736224014748010, -0.000048057914319065, -0.000787663079055384, -0.001473198308268938, -0.002094553515010935, -0.002643536244472083, -0.003116677958603595, -0.003507185822613928, -0.003814086552001789, -0.004035318109791245, -0.004171926884864147, -0.004225516845056660, -0.004199334823619039, -0.004098170195163846, -0.003927679645897309, -0.003694294048148267, -0.003405360512862820, -0.003068872591348129, -0.002693131197271969, -0.002286765126902860, -0.001858773604862586, -0.001418238552947833, -0.000973944167066713, -0.000534173868829619, -0.000106613479977550, 0.000301699601011732, 0.000684336173595900, 0.001035442578833791, 0.001349852467618926, 0.001623326794876901, 0.001852852576328433, 0.002036784086082496, 0.002174415827424258, 0.002265197627398382, 0.002308817130050681, 0.002306568447922007, 0.002262004073121292, 0.002178885915107971, 0.002058196188280081, 0.001902986849115314, 0.001723717744529424, 0.001517809497406495, 0.001295215851931261, 0.001058851063175263, 0.000814725473802231, 0.000567640643123008, 0.000322510489680255, 0.000084082690787220, -0.000143511677076383, -0.000356598632546370, -0.000551839538058223, -0.000726459269042778, -0.000878333102915519, -0.001005802502109255, -0.001107609474592948, -0.001182999511712966, -0.001231724573461644, -0.001253983783014675, -0.001250498303855702, -0.001222632870457348, -0.001172396297916355, -0.001102331400542105, -0.001015286248346293, -0.000914049078670187, -0.000801069365710719, -0.000678490099554352, -0.000548427361576298, -0.000413476038173425, -0.000277381849908065, -0.000144911454925575, -0.000019740287652141, 0.000098353002391692, 0.000213106256109367, 0.000321419603506285, 0.000401543327440382, 0.000484276489349049, 0.000546108904674455, 0.000595435888069700, 0.000630221666830102, 0.000650908078289207, 0.000657887414710607, 0.000651723486505544, 0.000633383885155741, 0.000603966827912324, 0.000564613893906762, 0.000516639603401830, 0.000461460673600523, 0.000400429077199748, 0.000334844261309097, 0.000265999359621072, 0.000195091536211946, 0.000123144667419350, 0.000051022545303487, -0.000020600671979957, -0.000091306103977099, -0.000160920338573639, -0.000229505695217796, -0.000297420057921267, -0.000365311474947399, -0.000434052387522716, -0.000504808183463150, -0.000579117971409598, -0.000658731927598885, -0.000745515693376396, -0.000841696354699768, -0.000949749961336003, -0.001072277374239886, -0.001211970386842814, 0.004847574947800705} ; // Sample 24 kHz, pass 3, stop 4, ripple 0.2 dB, atten 100 dB. Stop 0.166667. double quiskAudio24p3Coefs[93] = { -0.000037783993624828, -0.000115216534351507, -0.000197004848051633, -0.000166882497461099, 0.000128538373562514, 0.000763065896965353, 0.001593251408880778, 0.002221476977470587, 0.002159957821475971, 0.001165685783386774, -0.000455884791825150, -0.001852148041710624, -0.002061857791611326, -0.000704774303788570, 0.001548186623458437, 0.003181880133780748, 0.002773578777222453, 0.000127448157901667, -0.003249774740083473, -0.004900026839230316, -0.003119142778828723, 0.001505846985194979, 0.006005835857891277, 0.006816532154902235, 0.002465206003840461, -0.004779621260530268, -0.009853981311881564, -0.008278389476095381, 0.000168292207858724, 0.010329120063920900, 0.014549834598444522, 0.008161510823584768, -0.006176039595703008, -0.018913340959814302, -0.019528202468339487, -0.004537713172735999, 0.018084136858548469, 0.032234903031086101, 0.023988321525860046, -0.007153715631741163, -0.043920635751648937, -0.058267538333419230, -0.027093916052665576, 0.052156072898706766, 0.155951479742186460, 0.243837576013442580, 0.278208881979582880, 0.243837576013442580, 0.155951479742186460, 0.052156072898706766, -0.027093916052665576, -0.058267538333419230, -0.043920635751648937, -0.007153715631741163, 0.023988321525860046, 0.032234903031086101, 0.018084136858548469, -0.004537713172735999, -0.019528202468339487, -0.018913340959814302, -0.006176039595703008, 0.008161510823584768, 0.014549834598444522, 0.010329120063920900, 0.000168292207858724, -0.008278389476095381, -0.009853981311881564, -0.004779621260530268, 0.002465206003840461, 0.006816532154902235, 0.006005835857891277, 0.001505846985194979, -0.003119142778828723, -0.004900026839230316, -0.003249774740083473, 0.000127448157901667, 0.002773578777222453, 0.003181880133780748, 0.001548186623458437, -0.000704774303788570, -0.002061857791611326, -0.001852148041710624, -0.000455884791825150, 0.001165685783386774, 0.002159957821475971, 0.002221476977470587, 0.001593251408880778, 0.000763065896965353, 0.000128538373562514, -0.000166882497461099, -0.000197004848051633, -0.000115216534351507, -0.000037783993624828} ; // Sample 166.667 kHz, pass 20.000, stop 23.900, ripple 0.1dB, atten 100 dB. Stop 0.143400. double quiskFilt167D3Coefs[173] = { 0.000027361057967466, 0.000079022927580003, 0.000153315280214681, 0.000217036303406228, 0.000216051711988195, 0.000097396424148557, -0.000154926195574306, -0.000490420382204739, -0.000792207008833313, -0.000919092591781850, -0.000778111000786101, -0.000391274475742801, 0.000087636155699997, 0.000431036292372644, 0.000453513042034128, 0.000127278368774421, -0.000375305195602114, -0.000754032727213185, -0.000745162366934028, -0.000291077295308464, 0.000391691804410550, 0.000907469994025008, 0.000906322210882447, 0.000315586781248832, -0.000570606431536495, -0.001224850102488048, -0.001191706572954991, -0.000392843729362266, 0.000766771909476392, 0.001591024783572854, 0.001502286627641521, 0.000433072083786191, -0.001058714434132909, -0.002065657351825392, -0.001872596976495124, -0.000447193062325162, 0.001448204360826397, 0.002647575301181126, 0.002286703308575930, 0.000403725700513730, -0.001971005587443560, -0.003359964169317242, -0.002743264224337261, -0.000278054902152837, 0.002659789549535132, 0.004222291522979791, 0.003233725726619094, 0.000035039391335235, -0.003557779274022707, -0.005259805099663439, -0.003746914316541065, 0.000371441180756436, 0.004722776316977453, 0.006507912944025527, 0.004270009795668968, -0.001002952818151785, -0.006235533234742016, -0.008019243636496016, -0.004787772358159753, 0.001948724018108411, 0.008220101302576532, 0.009881282059334088, 0.005283717292111678, -0.003348783872543343, -0.010884795691042899, -0.012252153446073137, -0.005739902334679721, 0.005449960457274001, 0.014621846680862713, 0.015450997622704835, 0.006140561144775123, -0.008746269854437872, -0.020270474363958398, -0.020205028153266937, -0.006470785151112811, 0.014438262597161191, 0.030022509645911820, 0.028563858550479816, 0.006716896161104373, -0.026463233531944890, -0.051946702805221123, -0.049198922096865508, -0.006868026781416496, 0.069760519092899292, 0.158783283295639180, 0.229837831554147300, 0.256919080611963280, 0.229837831554147300, 0.158783283295639180, 0.069760519092899292, -0.006868026781416496, -0.049198922096865508, -0.051946702805221123, -0.026463233531944890, 0.006716896161104373, 0.028563858550479816, 0.030022509645911820, 0.014438262597161191, -0.006470785151112811, -0.020205028153266937, -0.020270474363958398, -0.008746269854437872, 0.006140561144775123, 0.015450997622704835, 0.014621846680862713, 0.005449960457274001, -0.005739902334679721, -0.012252153446073137, -0.010884795691042899, -0.003348783872543343, 0.005283717292111678, 0.009881282059334088, 0.008220101302576532, 0.001948724018108411, -0.004787772358159753, -0.008019243636496016, -0.006235533234742016, -0.001002952818151785, 0.004270009795668968, 0.006507912944025527, 0.004722776316977453, 0.000371441180756436, -0.003746914316541065, -0.005259805099663439, -0.003557779274022707, 0.000035039391335235, 0.003233725726619094, 0.004222291522979791, 0.002659789549535132, -0.000278054902152837, -0.002743264224337261, -0.003359964169317242, -0.001971005587443560, 0.000403725700513730, 0.002286703308575930, 0.002647575301181126, 0.001448204360826397, -0.000447193062325162, -0.001872596976495124, -0.002065657351825392, -0.001058714434132909, 0.000433072083786191, 0.001502286627641521, 0.001591024783572854, 0.000766771909476392, -0.000392843729362266, -0.001191706572954991, -0.001224850102488048, -0.000570606431536495, 0.000315586781248832, 0.000906322210882447, 0.000907469994025008, 0.000391691804410550, -0.000291077295308464, -0.000745162366934028, -0.000754032727213185, -0.000375305195602114, 0.000127278368774421, 0.000453513042034128, 0.000431036292372644, 0.000087636155699997, -0.000391274475742801, -0.000778111000786101, -0.000919092591781850, -0.000792207008833313, -0.000490420382204739, -0.000154926195574306, 0.000097396424148557, 0.000216051711988195, 0.000217036303406228, 0.000153315280214681, 0.000079022927580003, 0.000027361057967466 } ; quisk-3.6.11/extdemod.c0000644000175000017500000000343311632372222014276 0ustar jimjim00000000000000#include #include #include #include #include "quisk.h" // If you set add_extern_demod in your config file, you will get another // button that will call this module. Change it to what you want. Save // a copy because new releases of Quisk will overwrite this file. // // NOTE: NEW RELEASES OF QUISK WILL OVERWRITE THIS FILE! int quisk_extern_demod(complex * cSamples, int nSamples, double decim) { // Filter and demodulate the I/Q samples into audio play samples. // cSamples: The input I/Q samples, and the output stereo play samples. // nSamples: The number of input samples; maximum is SAMP_BUFFER_SIZE. // decim: The decimation needed (1.0 for no decimation). // The output play samples are stereo, and are placed into cSamples. // The return value is the number of output samples = nSamples / decim. // See quisk.h for useful data in quisk_sound_state. For example, the // sample rate is quisk_sound_state.sample_rate. If you need decimation, // look at iDecimate() and fDecimate() in quisk.c. int i; double d, di; complex cx; static complex fm_1 = 10; // Sample delayed by one static complex fm_2 = 10; // Sample delayed by two if (fabs (decim - 1.0) > 0.001) // no provision for decimation return 0; for (i = 0; i < nSamples; i++) { // narrow FM cx = cSamples[i]; di = creal(fm_1) * (cimag(cx) - cimag(fm_2)) - cimag(fm_1) * (creal(cx) - creal(fm_2)); d = creal(fm_1) * creal(fm_1) + cimag(fm_1) * cimag(fm_1); if (d == 0) // I don't think this can happen di = 0; else di = di / d * quisk_sound_state.sample_rate; fm_2 = fm_1; // fm_2 is sample cSamples[i - 2] fm_1 = cx; // fm_1 is sample cSamples[i - 1] cSamples[i] = di + I * di; // monophonic sound, two channels } return nSamples; // Number of play samples } quisk-3.6.11/quisk.c0000666000175000017500000026206012132073614013627 0ustar jimjim00000000000000#include #include #include #include // Use native C99 complex type for fftw3 #include #include #ifdef MS_WINDOWS #include #define QUISK_SHUT_RD SD_RECEIVE #define QUISK_SHUT_BOTH SD_BOTH #else #include #include #define INVALID_SOCKET -1 #define QUISK_SHUT_RD SHUT_RD #define QUISK_SHUT_BOTH SHUT_RDWR #endif #include "quisk.h" #include "filter.h" #define DEBUG 0 #define FM_FILTER_DEMPH 300.0 // Frequency of FM lowpass de-emphasis filter static int fft_error; // fft error count static int count_fft; // how many fft's have occurred (for average) enum fft_status {EMPTY, // fft_data is currently unused FILLING, // now writing samples to this fft READY}; // ready to perform fft typedef struct fftd { fftw_complex * samples; // complex data for fft fftw_plan plan; // fft plan for fftW int index; // position of next fft sample enum fft_status status; // whether the fft is busy struct fftd * next; // the next data block to use } fft_data; static fft_data * FFT1, * FFT2, * FFT3; // data for three fft's WB4JFI ADD third FFT static fft_data * ptWriteFft; // Write the current samples to this fft static double * fft_avg; // Array to average the FFT static double * fft_window; // Window for FFT data static double * current_graph; // current graph data as returned static int use_remove_dc=1; // Remove DC from samples static PyObject * QuiskError; // Exception for this module static PyObject * pyApp; // Application instance static int fft_size; // size of fft, e.g. 1024 int data_width; // number of points to return as graph data; fft_size * n int rxMode; // 0 to 9, 10 to 12: CWL, CWU, LSB, USB, AM, FM, EXT, DGT-U, DGT-L, DGT-IQ, IMD(10 to 12) int quisk_noise_blanker; // noise blanker level, 0 for off static int quisk_auto_notch; // auto notch control PyObject * quisk_pyConfig=NULL; // Configuration module instance long quisk_mainwin_handle; // Handle of the main window static int sample_rate=1; // Sample rate such as 48000, 96000, 192000 static int graphX; // Origin of first X value for graph data static int graphY; // Origin of 0 dB for graph data static int average_count; // Number of FFT's to average for graph static double graphScale; // Scale factor for graph static complex testtonePhase; // Phase increment for test tone double quisk_audioVolume; // Audio output level, 0.0 to 1.0 static double cFilterI[MAX_FILTER_SIZE]; // Digital filter coefficients for receive static double cFilterQ[MAX_FILTER_SIZE]; // Digital filter coefficients static int sizeFilter; // Number of coefficients for filters static int isFDX; // Are we in full duplex mode? static int filter_bandwidth; // Current filter bandwidth in Hertz static int quisk_decim_srate; // Sample rate after decimation static int quisk_demod_srate; // Sample rate after demodulation static int quisk_filter_srate=48000; // Frequency for filters static int split_rxtx; // Are we in split rx/tx mode? static double sidetoneVolume; // Audio output level of the CW sidetone, 0.0 to 1.0 static int keyupDelay; // Play silence after sidetone ends static complex sidetonePhase; // Phase increment for sidetone int quisk_sidetoneCtrl; // sidetone control value 0 to 1000 static int agcInUse; // 0 for no AGC static double agcRelease, agcLevel; // AGC parameters static double agcMaxGain; // Max AGC gain static double agcOffGain; // Gain when AGC is off static double squelch_level; // setting of squelch control static int quisk_invert_spectrum = 0; // Invert the input RF spectrum static double Smeter; // Measured RMS signal strength static int rx_tune_freq; // Receive tuning frequency as +/- sample_rate / 2 int quisk_tx_tune_freq; // Transmit tuning frequency as +/- sample_rate / 2 static int rit_freq; // RIT frequency in Hertz #define RX_UDP_SIZE 1442 // Expected size of UDP samples packet static int rx_udp_socket = INVALID_SOCKET; // Socket for receiving ADC samples from UDP static int rx_udp_started = 0; // Have we received any data yet? int quisk_using_udp = 0; // Are we using rx_udp_socket? static double rx_udp_gain_correct = 0; // For decimation by 5, correct by 4096 / 5**5 static double rx_udp_clock; // Clock frequency for UDP samples static int rx_udp_read_blocks = 0; // Number of blocks to read for each read call static int is_little_endian; // Test byte order; is it little-endian? enum quisk_rec_state quisk_record_state = IDLE; static float * quisk_record_buffer; static int quisk_record_bufsize; static int quisk_record_index; static int quisk_play_index; static int quisk_mic_index; static int quisk_record_full; // These are used to measure the frequency of a continuous RF signal. static void measure_freq(complex *, int, int); static double measured_frequency; static int measure_freq_mode=0; #if 0 static int fFracDecim(double * dSamples, int nSamples, double fdecim) { int i, nout; double xm0, xm1, xm2, xm3; static double dindex = 1; static double y0=0, y1=0, y2=0, y3=0; static int in=0, out=0; in += nSamples; nout = 0; for (i = 0; i < nSamples; i++) { y3 = dSamples[i]; if (dindex < 1 || dindex >= 2.4) printf ("dindex %.5f fdecim %.8f\n", dindex, fdecim); if (dindex < 2) { #if 0 dSamples[nout++] = (1 - (dindex - 1)) * y1 + (dindex - 1) * y2; #else xm0 = dindex - 0; xm1 = dindex - 1; xm2 = dindex - 2; xm3 = dindex - 3; dSamples[nout++] = xm1 * xm2 * xm3 * y0 / -6.0 + xm0 * xm2 * xm3 * y1 / 2.0 + xm0 * xm1 * xm3 * y2 / -2.0 + xm0 * xm1 * xm2 * y3 / 6.0; #endif out++; dindex += fdecim - 1; y0 = y1; y1 = y2; y2 = y3; } else { if (dindex > 2.5) printf ("Skip at %.2f\n", dindex); y0 = y1; y1 = y2; y2 = y3; dindex -= 1; } } //printf ("in %d out %d\n", in, out); return nout; } #endif static int cFracDecim(complex * cSamples, int nSamples, double fdecim) { // Fractional decimation of I/Q signals works poorly because it introduces aliases and birdies. int i, nout; double xm0, xm1, xm2, xm3; static double dindex = 1; static complex c0=0, c1=0, c2=0, c3=0; static int in=0, out=0; in += nSamples; nout = 0; for (i = 0; i < nSamples; i++) { c3 = cSamples[i]; if (dindex < 1 || dindex >= 2.4) printf ("dindex %.5f fdecim %.8f\n", dindex, fdecim); if (dindex < 2) { #if 0 cSamples[nout++] = (1 - (dindex - 1)) * c1 + (dindex - 1) * c2; #else xm0 = dindex - 0; xm1 = dindex - 1; xm2 = dindex - 2; xm3 = dindex - 3; cSamples[nout++] = (xm1 * xm2 * xm3 * c0 / -6.0 + xm0 * xm2 * xm3 * c1 / 2.0 + xm0 * xm1 * xm3 * c2 / -2.0 + xm0 * xm1 * xm2 * c3 / 6.0); #endif out++; dindex += fdecim - 1; c0 = c1; c1 = c2; c2 = c3; } else { if (dindex > 2.5) printf ("Skip at %.2f\n", dindex); c0 = c1; c1 = c2; c2 = c3; dindex -= 1; } } //printf ("in %d out %d\n", in, out); return nout; } #define QUISK_NB_HWINDOW_SECS 500.E-6 // half-size of blanking window in seconds static void NoiseBlanker(complex * cSamples, int nSamples) { static complex * cSaved = NULL; static double * dSaved = NULL; static double save_sum; static int save_size, hwindow_size, state, index, win_index; static int sample_rate = -1; int i, j, k, is_pulse; double mag, limit; complex samp; #if DEBUG static time_t time0 = 0; static int debug_count = 0; #endif if (quisk_noise_blanker <= 0) return; if (quisk_sound_state.sample_rate != sample_rate) { // Initialization sample_rate = quisk_sound_state.sample_rate; state = 0; index = 0; win_index = 0; save_sum = 0.0; hwindow_size = (int)(sample_rate * QUISK_NB_HWINDOW_SECS + 0.5); save_size = hwindow_size * 3; // number of samples in the average i = save_size * sizeof(double); dSaved = (double *) realloc(dSaved, i); memset (dSaved, 0, i); i = save_size * sizeof(complex); cSaved = (complex *)realloc(cSaved, i); memset (cSaved, 0, i); #if DEBUG printf ("Noise blanker: save_size %d hwindow_size %d\n", save_size, hwindow_size); #endif } switch(quisk_noise_blanker) { case 1: default: limit = 6.0; break; case 2: limit = 4.0; break; case 3: limit = 2.5; break; } for (i = 0; i < nSamples; i++) { // output oldest sample, save newest samp = cSamples[i]; // newest sample cSamples[i] = cSaved[index]; // oldest sample cSaved[index] = samp; // use newest sample mag = cabs(samp); save_sum -= dSaved[index]; // remove oldest sample magnitude dSaved[index] = mag; // save newest sample magnitude save_sum += mag; // update sum of samples if (mag <= save_sum / save_size * limit) // see if we have a large pulse is_pulse = 0; else is_pulse = 1; switch (state) { case 0: // Normal state if (is_pulse) { // wait for a pulse state = 1; k = index; for (j = 0; j < hwindow_size; j++) { // apply window to prior samples cSaved[k--] *= (double)j / hwindow_size; if (k < 0) k = save_size - 1; } } else if (win_index) { // pulses have stopped, increase window to 1.0 cSaved[index] *= (double)win_index / hwindow_size; if (++win_index >= hwindow_size) win_index = 0; // no more window } break; case 1: // we got a pulse cSaved[index] = 0; // zero samples until the pulses stop if ( ! is_pulse) { // start raising the window, but be prepared to window another pulse state = 0; win_index = 1; } break; } #if DEBUG if (debug_count) { printf ("%d", is_pulse); if (--debug_count == 0) printf ("\n"); } else if (is_pulse && time(NULL) != time0) { time0 = time(NULL); debug_count = hwindow_size * 2; printf ("%d", is_pulse); } #endif if (++index >= save_size) index = 0; } return; } #define NOTCH_DEBUG 0 #define NOTCH_DATA_SIZE 2048 #define NOTCH_FILTER_DESIGN_SIZE NOTCH_DATA_SIZE / 4 #define NOTCH_FILTER_SIZE (NOTCH_FILTER_DESIGN_SIZE - 1) #define NOTCH_FILTER_FFT_SIZE (NOTCH_FILTER_SIZE / 2 + 1) #define NOTCH_DATA_START_SIZE (NOTCH_FILTER_SIZE - 1) #define NOTCH_DATA_OUTPUT_SIZE (NOTCH_DATA_SIZE - NOTCH_DATA_START_SIZE) #define NOTCH_FFT_SIZE (NOTCH_DATA_SIZE / 2 + 1) static void dAutoNotch(double * dsamples, int nSamples, int sidetone, int rate) { int i, j, k, i1, i2, inp, signal, delta_sig, delta_i1, half_width; double d, d1, d2, avg; static int old1, count1, old2, count2; static int index; static fftw_plan planFwd=NULL; static fftw_plan planRev,fltrFwd, fltrRev; static double data_in[NOTCH_DATA_SIZE]; static double data_out[NOTCH_DATA_SIZE]; static complex notch_fft[NOTCH_FFT_SIZE]; static double fft_window[NOTCH_DATA_SIZE]; static double fltr_in[NOTCH_DATA_SIZE]; static double fltr_out[NOTCH_FILTER_DESIGN_SIZE]; static complex fltr_fft[NOTCH_FFT_SIZE]; static double average_fft[NOTCH_FFT_SIZE]; static int fltrSig; #if NOTCH_DEBUG static char * txt; double dmax; #endif if ( ! planFwd) { // set up FFT plans planFwd = fftw_plan_dft_r2c_1d(NOTCH_DATA_SIZE, data_in, notch_fft, FFTW_MEASURE); planRev = fftw_plan_dft_c2r_1d(NOTCH_DATA_SIZE, notch_fft, data_out, FFTW_MEASURE); // destroys notch_fft fltrFwd = fftw_plan_dft_r2c_1d(NOTCH_DATA_SIZE, fltr_in, fltr_fft, FFTW_MEASURE); fltrRev = fftw_plan_dft_c2r_1d(NOTCH_FILTER_DESIGN_SIZE, fltr_fft, fltr_out, FFTW_MEASURE); for (i = 0; i < NOTCH_FILTER_SIZE; i++) fft_window[i] = 0.50 - 0.50 * cos(2. * M_PI * i / (NOTCH_FILTER_SIZE)); // Hanning //fft_window[i] = 0.54 - 0.46 * cos(2. * M_PI * i / (NOTCH_FILTER_SIZE)); // Hamming } if ( ! dsamples) { // initialize index = NOTCH_DATA_START_SIZE; fltrSig = -1; old1 = old2 = 0; count1 = count2 = -4; memset(data_out, 0, sizeof(double) * NOTCH_DATA_SIZE); memset(data_in, 0, sizeof(double) * NOTCH_DATA_SIZE); memset(average_fft, 0, sizeof(double) * NOTCH_FFT_SIZE); return; } if ( ! quisk_auto_notch) return; // index into FFT data = frequency * 2 * NOTCH_FFT_SIZE / rate // index into filter design = frequency * 2 * NOTCH_FILTER_FFT_SIZE / rate for (inp = 0; inp < nSamples; inp++) { data_in[index] = dsamples[inp]; dsamples[inp] = data_out[index]; if (++index >= NOTCH_DATA_SIZE) { // we have a full FFT of samples index = NOTCH_DATA_START_SIZE; fftw_execute(planFwd); // Calculate forward FFT // Find maximum FFT bins delta_sig = (300 * 2 * NOTCH_FFT_SIZE + rate / 2) / rate; // small frequency interval delta_i1 = (400 * 2 * NOTCH_FFT_SIZE + rate / 2) / rate; // small frequency interval if (sidetone != 0) // For CW, accept a signal at the frequency of the RIT signal = (abs(sidetone) * 2 * NOTCH_FFT_SIZE + rate / 2) / rate; else signal = -999; avg = 1; #if NOTCH_DEBUG dmax = 0; #endif d1 = 0; i1 = 0; // First maximum signal for (i = 0; i < NOTCH_FFT_SIZE; i++) { d = cabs(notch_fft[i]); avg += d; //average_fft[i] = 0.9 * average_fft[i] + 0.1 * d; average_fft[i] = 0.5 * average_fft[i] + 0.5 * d; if (abs(i - signal) > delta_sig && average_fft[i] > d1) { d1 = average_fft[i]; i1 = i; #if NOTCH_DEBUG dmax = d; #endif } } if (abs(i1 - old1) < 3) // See if the maximum bin i1 is changing count1++; else count1--; if (count1 > 4) count1 = 4; else if (count1 < -1) count1 = -1; if (count1 < 0) old1 = i1; avg /= NOTCH_FFT_SIZE; d2 = 0; i2 = 0; // Next maximum signal not near the first for (i = 0; i < NOTCH_FFT_SIZE; i++) { if (abs(i - signal) > delta_sig && abs(i - i1) > delta_i1 && average_fft[i] > d2) { d2 = average_fft[i]; i2 = i; } } if (abs(i2 - old2) < 3) // See if the maximum bin i2 is changing count2++; else count2--; if (count2 > 4) count2 = 4; else if (count2 < -2) count2 = -2; if (count2 < 0) old2 = i2; if (count1 > 0 && count2 > 0) k = i1 + 10000 * i2; // trial filter index else if(count1 > 0) k = i1; else k = 0; // Make the filter if it is different if (fltrSig != k) { fltrSig = k; half_width = (100 * 2 * NOTCH_FILTER_FFT_SIZE + rate / 2) / rate; // half the width of the notch if (half_width < 3) half_width = 3; for (i = 0; i < NOTCH_FILTER_FFT_SIZE; i++) fltr_fft[i] = 1.0; k = (i1 + 2) / 4; // Ratio of index values is 4 #if NOTCH_DEBUG txt = "Fxx"; #endif if (count1 > 0) { #if NOTCH_DEBUG txt = "F1"; #endif for (i = -half_width; i <= half_width; i++) { j = k + i; if (j >= 0 && j < NOTCH_FILTER_FFT_SIZE) fltr_fft[j] = 0.0; } } k = (i2 + 2) / 4; // Ratio of index values is 4 if (count1 > 0 && count2 > 0) { #if NOTCH_DEBUG txt = "F12"; #endif for (i = -half_width; i <= half_width; i++) { j = k + i; if (j >= 0 && j < NOTCH_FILTER_FFT_SIZE) fltr_fft[j] = 0.0; } } fftw_execute(fltrRev); // center the coefficient zero, make the filter symetric, reduce the size by one memmove(fltr_out + NOTCH_FILTER_DESIGN_SIZE / 2 - 1, fltr_out, sizeof(double) * (NOTCH_FILTER_SIZE / 2 - 1)); for (i = NOTCH_FILTER_DESIGN_SIZE / 2 - 2, j = NOTCH_FILTER_DESIGN_SIZE / 2; i >= 0; i--, j++) fltr_out[i] = fltr_out[j]; for (i = 0; i < NOTCH_FILTER_SIZE; i++) fltr_in[i] = fltr_out[i] * fft_window[i] / NOTCH_FILTER_DESIGN_SIZE; for (i = NOTCH_FILTER_SIZE; i < NOTCH_DATA_SIZE; i++) fltr_in[i] = 0.0; fftw_execute(fltrFwd); // The filter is fltr_fft[] } #if NOTCH_DEBUG printf("Max %12.0lf frequency index1 %3d %5d %12.0lf index2 %3d %5d %12.0lf avg %12.0lf %s\n", dmax, count1, i1, d1, count2, i2, d2, avg, txt); #endif for (i = 0; i < NOTCH_FFT_SIZE; i++) // Apply the filter notch_fft[i] *= fltr_fft[i]; fftw_execute(planRev); // Calculate inverse FFT memmove(data_in, data_in + NOTCH_DATA_OUTPUT_SIZE, NOTCH_DATA_START_SIZE * sizeof(double)); for (i = NOTCH_DATA_START_SIZE; i < NOTCH_DATA_SIZE; i++) data_out[i] /= NOTCH_DATA_SIZE / 20; // Empirical } } return; } #if 0 static complex * audio_fft; static int audio_fft_ready=0; static void calc_audio_graph(double * dsamples, int nSamples) { // Calculate an FFT for the audio data int i, inp; static int index; static int audio_fft_size; static fftw_plan plan; static double * data_in; static double * fft_window; if ( ! dsamples) { // malloc new space and initialize index = 0; audio_fft_size = data_width; data_in = (double *)malloc(audio_fft_size * sizeof(double)); fft_window = (double *)malloc(audio_fft_size * sizeof(double)); audio_fft = (complex *)malloc((audio_fft_size / 2 + 1) * sizeof(complex)); plan = fftw_plan_dft_r2c_1d(audio_fft_size, data_in, audio_fft, FFTW_MEASURE); for (i = 0; i < audio_fft_size; i++) fft_window[i] = 0.50 - 0.50 * cos(2. * M_PI * i / audio_fft_size); // Hanning return; } for (inp = 0; inp < nSamples; inp++) { data_in[index] = dsamples[inp]; if (++index >= audio_fft_size) { // we have a full FFT of samples index = 0; for (i = 0; i < audio_fft_size; i++) data_in[i] *= fft_window[i]; // multiply by window fftw_execute(plan); // Calculate forward FFT audio_fft_ready = (audio_fft_ready + 1) & 0xff; //printf("Audio FFT %d %d %d\n", audio_fft_ready, audio_fft_size, data_width); } } } static PyObject * get_audio_graph(PyObject * self, PyObject * args) { int i, j, k; static int seq = 0; double d2, scale; PyObject * tuple2; if (!PyArg_ParseTuple (args, "")) return NULL; if (seq == audio_fft_ready) { // a new graph is not yet available Py_INCREF (Py_None); return Py_None; } seq = audio_fft_ready; tuple2 = PyTuple_New(data_width); scale = log10((double)data_width) + 31.0 * log10(2.0); scale *= 20.0; j = 0; k = data_width / 2 - 1; for (i = 0; i < data_width / 2; i++, k--) { d2 = 20.0 * log10(cabs(audio_fft[k])) - scale; if (d2 < -200) d2 = -200; PyTuple_SetItem(tuple2, j++, PyFloat_FromDouble(d2)); } for (i = 0; i < data_width / 2; i++) { d2 = 20.0 * log10(cabs(audio_fft[i])) - scale; if (d2 < -200) d2 = -200; PyTuple_SetItem(tuple2, j++, PyFloat_FromDouble(d2)); } if (j < data_width) PyTuple_SetItem(tuple2, j++, PyFloat_FromDouble(-200.0)); return tuple2; } #else static PyObject * get_audio_graph(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; Py_INCREF (Py_None); return Py_None; } #endif static complex dRxFilterOut(complex sample, int bank) { // Rx FIR filter; bank is the static storage index, and must be different for different data streams complex cx; int j, k; static int init = 0; static struct stStorage { int indexFilter; // current index into sample buffer complex bufFilterC[MAX_FILTER_SIZE]; // Digital filter sample buffer } Storage[2]; struct stStorage * ptBuf = Storage + bank; if ( ! init) { init = 1; memset(Storage, 0, sizeof(struct stStorage)); memset(Storage + 1, 0, sizeof(struct stStorage)); } if ( ! sizeFilter) return sample; if (ptBuf->indexFilter >= sizeFilter) ptBuf->indexFilter = 0; ptBuf->bufFilterC[ptBuf->indexFilter] = sample; cx = 0; j = ptBuf->indexFilter; for (k = 0; k < sizeFilter; k++) { cx += ptBuf->bufFilterC[j] * cFilterI[k]; if (++j >= sizeFilter) j = 0; } ptBuf->indexFilter++; return cx; } static complex cRxFilterOut(complex sample, int bank) { // Rx FIR filter; bank is the static storage index, and must be different for different data streams double accI, accQ; int j, k; static int init = 0; static struct stStorage { int indexFilter; // current index into sample buffer double bufFilterI[MAX_FILTER_SIZE]; // Digital filter sample buffer double bufFilterQ[MAX_FILTER_SIZE]; // Digital filter sample buffer } Storage[2]; struct stStorage * ptBuf = Storage + bank; if ( ! init) { init = 1; memset(Storage, 0, sizeof(struct stStorage)); memset(Storage + 1, 0, sizeof(struct stStorage)); } if ( ! sizeFilter) return sample; if (ptBuf->indexFilter >= sizeFilter) ptBuf->indexFilter = 0; ptBuf->bufFilterI[ptBuf->indexFilter] = creal(sample); ptBuf->bufFilterQ[ptBuf->indexFilter] = cimag(sample); accI = accQ = 0; j = ptBuf->indexFilter; for (k = 0; k < sizeFilter; k++) { accI += ptBuf->bufFilterI[j] * cFilterI[k]; accQ += ptBuf->bufFilterQ[j] * cFilterQ[k]; if (++j >= sizeFilter) j = 0; } ptBuf->indexFilter++; return accI + I * accQ; } static void AddTestTone(complex * cSamples, int nSamples) { int i; static complex testtoneVector = 21474836.47; // -40 dB static complex audioVector = 1.0; complex audioPhase; switch (rxMode) { default: //testtonePhase = cexp(I * 2 * M_PI * (quisk_sidetoneCtrl - 500) / 1000.0); for (i = 0; i < nSamples; i++) { cSamples[i] += testtoneVector; testtoneVector *= testtonePhase; } break; case 4: // AM //audioPhase = cexp(I * 2 * M_PI * quisk_sidetoneCtrl * 5 / sample_rate); audioPhase = cexp(I * 2.0 * M_PI * 1000 / sample_rate); for (i = 0; i < nSamples; i++) { cSamples[i] += testtoneVector * (1.0 + creal(audioVector)); testtoneVector *= testtonePhase; audioVector *= audioPhase; } break; case 5: // FM //audioPhase = cexp(I * 2 * M_PI * quisk_sidetoneCtrl * 5 / sample_rate); audioPhase = cexp(I * 2.0 * M_PI * 1000 / sample_rate); for (i = 0; i < nSamples; i++) { cSamples[i] += testtoneVector * cexp(I * creal(audioVector)); testtoneVector *= testtonePhase; audioVector *= audioPhase; } break; } } static int IsSquelch(int freq) { // measure the signal level for squelch int i, i1, i2, width; double meter; width = 5000 * data_width / sample_rate; // bandwidth determines number of pixels to average i1 = (int)((double)freq * data_width / sample_rate + data_width / 2.0 - width / 2.0 + 0.5); i2 = i1 + width; meter = 0; if (i1 >= 0 && i2 < data_width) { // too close to edge? for (i = i1; i < i2; i++) { meter += current_graph[i]; } } meter /= width; if (meter == 0 || meter < squelch_level) return 1; // meter == 0 means Rx freq is off-screen so squelch is on else return 0; } static PyObject * set_record_state(PyObject * self, PyObject * args) { // called when a Record or Play button is pressed, or with -1 to poll int button; if (!PyArg_ParseTuple (args, "i", &button)) return NULL; switch (button) { case 0: // press record if ( ! quisk_record_buffer) { // initialize quisk_record_bufsize = (int)(QuiskGetConfigDouble("max_record_minutes", 0.25) * quisk_sound_state.playback_rate * 60.0 + 0.2); quisk_record_buffer = (float *)malloc(sizeof(float) * quisk_record_bufsize); } quisk_record_index = 0; quisk_play_index = 0; quisk_mic_index = 0; quisk_record_full = 0; quisk_record_state = RECORD; break; case 1: // release record quisk_record_state = IDLE; break; case 2: // press play if (quisk_record_full) { quisk_play_index = quisk_record_index + 1; if (quisk_play_index >= quisk_record_bufsize) quisk_play_index = 0; } else { quisk_play_index = 0; } quisk_mic_index = quisk_play_index; quisk_record_state = PLAYBACK; break; case 3: // release play quisk_record_state = IDLE; break; } return PyInt_FromLong(quisk_record_state != PLAYBACK); } static void tmp_record(complex * cSamples, int nSamples) // save radio sound { int i; for (i = 0; i < nSamples; i++) { quisk_record_buffer[quisk_record_index++] = creal(cSamples[i]); if (quisk_record_index >= quisk_record_bufsize) { quisk_record_index = 0; quisk_record_full = 1; } } } static void tmp_playback(complex * cSamples, int nSamples, double volume) { // replace radio sound with saved sound int i; double d; for (i = 0; i < nSamples; i++) { d = quisk_record_buffer[quisk_play_index++] * volume; cSamples[i] = d + I * d; if (quisk_play_index >= quisk_record_bufsize) quisk_play_index = 0; if (quisk_play_index == quisk_record_index) { quisk_record_state = IDLE; return; } } } void quisk_tmp_microphone(complex * cSamples, int nSamples) { // replace microphone samples with saved sound int i; double d; for (i = 0; i < nSamples; i++) { d = quisk_record_buffer[quisk_mic_index++]; cSamples[i] = d + I * d; if (quisk_mic_index >= quisk_record_bufsize) quisk_mic_index = 0; if (quisk_mic_index == quisk_record_index) { quisk_record_state = IDLE; return; } } } static int quisk_process_decimate(complex * cSamples, int nSamples, int bank) { int i, final_filter; static struct stStorage { struct quisk_cHB45Filter HalfBand1; struct quisk_cHB45Filter HalfBand2; struct quisk_cHB45Filter HalfBand3; struct quisk_cFilter filtSdriq111; struct quisk_cFilter filtSdriq53; struct quisk_cFilter filtSdriq133; struct quisk_cFilter filtSdriq167; struct quisk_cFilter filtSdriq185; struct quisk_cFilter filtDecim5; struct quisk_cFilter filtDecim5S; struct quisk_cFilter filtDecim48to24; } Storage[2] ; if ( ! cSamples) { // Initialize all filters for (i = 0; i < 2; i++) { memset(&Storage[i].HalfBand1, 0, sizeof(struct quisk_cHB45Filter)); memset(&Storage[i].HalfBand2, 0, sizeof(struct quisk_cHB45Filter)); memset(&Storage[i].HalfBand3, 0, sizeof(struct quisk_cHB45Filter)); quisk_filt_cInit(&Storage[i].filtSdriq111, quiskFilt111D2Coefs, sizeof(quiskFilt111D2Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtSdriq53, quiskFilt53D1Coefs, sizeof(quiskFilt53D1Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtSdriq133, quiskFilt133D2Coefs, sizeof(quiskFilt133D2Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtSdriq167, quiskFilt167D3Coefs, sizeof(quiskFilt167D3Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtSdriq185, quiskFilt185D3Coefs, sizeof(quiskFilt185D3Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtDecim5, quiskFilt240D5Coefs, sizeof(quiskFilt240D5Coefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtDecim5S, quiskFilt240D5CoefsSharp, sizeof(quiskFilt240D5CoefsSharp)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtDecim48to24, quiskFilt48dec24Coefs, sizeof(quiskFilt48dec24Coefs)/sizeof(double)); } return 0; } // Decimate: Lower the sample rate to 48000 sps (or approx). Filters are designed for // a pass bandwidth of 20 kHz and a stop bandwidth of 24 kHz. // We use 48 ksps to accommodate wide digital modes. final_filter = (rxMode == 7 || rxMode == 8 || rxMode == 9); // Use sharp FIR final filter for decimate quisk_decim_srate = 48000; switch((quisk_sound_state.sample_rate + 100) / 1000) { case 41: case 48: break; case 53: // SDR-IQ quisk_decim_srate = quisk_sound_state.sample_rate; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq53, 1); break; case 96: if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); else nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); break; case 111: // SDR-IQ quisk_decim_srate = quisk_sound_state.sample_rate / 2; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq111, 2); break; case 133: // SDR-IQ quisk_decim_srate = quisk_sound_state.sample_rate / 2; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq133, 2); break; case 185: // SDR-IQ quisk_decim_srate = quisk_sound_state.sample_rate / 3; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq185, 3); break; case 192: nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); else nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); break; case 240: if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim5S, 5); else nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim5, 5); break; case 370: quisk_decim_srate = quisk_sound_state.sample_rate / 6; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq185, 3); break; case 384: nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand3); if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); else nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); break; case 480: nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim5, 5); if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); else nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); break; case 740: quisk_decim_srate = quisk_sound_state.sample_rate / 12; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand3); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq185, 3); break; case 960: nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim5, 5); if (final_filter) nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); else nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); break; case 1333: quisk_decim_srate = quisk_sound_state.sample_rate / 24; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand1); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand2); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand3); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtSdriq167, 3); break; default: printf ("Failure in quisk.c in integer decimation\n"); break; } return nSamples; } static int quisk_process_demodulate(complex * cSamples, double * dsamples, int nSamples, int bank) { int i; complex cx, cpx; double d, di; static struct stStorage { complex fm_1; // Sample delayed by one double dc_remove; // DC removal for AM double FM_www; double FM_nnn, FM_a_0, FM_a_1, FM_b_1, FM_x_1, FM_y_1; // filter for FM struct quisk_cHB45Filter HalfBand4; struct quisk_cHB45Filter HalfBand5; struct quisk_dHB45Filter HalfBand6; struct quisk_dFilter filtAudio24p3; struct quisk_dFilter filtAudio24p4; struct quisk_dFilter filtAudio12p2; struct quisk_dFilter filtAudio24p6; struct quisk_dFilter filtAudioFmHp; struct quisk_cFilter filtDecim48to24; } Storage[2] ; if ( ! cSamples) { // Initialize all filters for (i = 0; i < 2; i++) { memset(&Storage[i].HalfBand4, 0, sizeof(struct quisk_cHB45Filter)); memset(&Storage[i].HalfBand5, 0, sizeof(struct quisk_cHB45Filter)); memset(&Storage[i].HalfBand6, 0, sizeof(struct quisk_dHB45Filter)); quisk_filt_dInit(&Storage[i].filtAudio24p3, quiskAudio24p3Coefs, sizeof(quiskAudio24p3Coefs)/sizeof(double)); quisk_filt_dInit(&Storage[i].filtAudio24p4, quiskAudio24p4Coefs, sizeof(quiskAudio24p4Coefs)/sizeof(double)); quisk_filt_dInit(&Storage[i].filtAudio12p2, quiskAudio24p4Coefs, sizeof(quiskAudio24p4Coefs)/sizeof(double)); quisk_filt_dInit(&Storage[i].filtAudio24p6, quiskAudio24p6Coefs, sizeof(quiskAudio24p6Coefs)/sizeof(double)); quisk_filt_dInit(&Storage[i].filtAudioFmHp, quiskAudioFmHpCoefs, sizeof(quiskAudioFmHpCoefs)/sizeof(double)); quisk_filt_cInit(&Storage[i].filtDecim48to24, quiskFilt48dec24Coefs, sizeof(quiskFilt48dec24Coefs)/sizeof(double)); Storage[i].fm_1 = 10; Storage[i].FM_www = tan(M_PI * FM_FILTER_DEMPH / 24000); // filter for FM Storage[i].FM_nnn = 1.0 / (1.0 + Storage[i].FM_www); Storage[i].FM_a_0 = Storage[i].FM_www * Storage[i].FM_nnn; Storage[i].FM_a_1 = Storage[i].FM_a_0; Storage[i].FM_b_1 = Storage[i].FM_nnn * (Storage[i].FM_www - 1.0); //printf ("dsamples[i] = y_1 = di * %12.6lf + x_1 * %12.6lf - y_1 * %12.6lf\n", FM_a_0, FM_a_1, FM_b_1); } return 0; } // Filter and demodulate signal, copy capture buffer cSamples to play buffer dsamples. // quisk_decim_srate is the sample rate after integer decimation. quisk_demod_srate = quisk_decim_srate; switch(rxMode) { case 0: // lower sideband CW at 6 ksps quisk_demod_srate /= 8; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand5); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand4); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) + cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate); nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2); nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6); quisk_demod_srate *= 4; break; case 1: // upper sideband CW at 6 ksps quisk_demod_srate /= 8; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand5); nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand4); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) - cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, rit_freq, quisk_filter_srate); nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio12p2, 2); nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6); quisk_demod_srate *= 4; break; case 2: // lower sideband SSB at 12 ksps quisk_demod_srate /= 4; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand5); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) + cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); //calc_audio_graph(dsamples, nSamples); nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p4, 2); quisk_demod_srate *= 2; break; case 3: // upper sideband SSB at 12 ksps default: quisk_demod_srate /= 4; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecim2HB45(cSamples, nSamples, &Storage[bank].HalfBand5); nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) - cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); //calc_audio_graph(dsamples, nSamples); nSamples = quisk_dInterpolate(dsamples, nSamples, &Storage[bank].filtAudio24p4, 2); quisk_demod_srate *= 2; break; case 4: // AM at 24 ksps quisk_demod_srate /= 2; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = dRxFilterOut(cSamples[i], bank); di = cabs(cx); d = di + Storage[bank].dc_remove * 0.99; // DC removal; R.G. Lyons page 553 di = d - Storage[bank].dc_remove; Storage[bank].dc_remove = d; dsamples[i] = di; } nSamples = quisk_dFilter(dsamples, nSamples, &Storage[bank].filtAudio24p6); if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); break; case 5: // FM at 24 ksps quisk_demod_srate /= 2; quisk_filter_srate = quisk_demod_srate; nSamples = quisk_cDecimate(cSamples, nSamples, &Storage[bank].filtDecim48to24, 2); for (i = 0; i < nSamples; i++) { cx = dRxFilterOut(cSamples[i], bank); cpx = cx * conj(Storage[bank].fm_1); Storage[bank].fm_1 = cx; di = quisk_demod_srate * carg(cpx); // FM de-emphasis dsamples[i] = Storage[bank].FM_y_1 = di * Storage[bank].FM_a_0 + Storage[bank].FM_x_1 * Storage[bank].FM_a_1 - Storage[bank].FM_y_1 * Storage[bank].FM_b_1; Storage[bank].FM_x_1 = di; } nSamples = quisk_dDecimate(dsamples, nSamples, &Storage[bank].filtAudio24p3, 2); nSamples = quisk_dFilter(dsamples, nSamples, &Storage[bank].filtAudioFmHp); nSamples = quisk_dInterp2HB45(dsamples, nSamples, &Storage[bank].HalfBand6); if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); break; case 7: // digital mode DGT-U at 48 ksps quisk_filter_srate = quisk_demod_srate; for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) - cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); break; case 8: // digital mode DGT-L at 48 ksps quisk_filter_srate = quisk_demod_srate; for (i = 0; i < nSamples; i++) { cx = cRxFilterOut(cSamples[i], bank); dsamples[i] = creal(cx) + cimag(cx); } if(bank == 0) dAutoNotch(dsamples, nSamples, 0, quisk_filter_srate); break; case 9: // digital mode DGT-IQ at 48 ksps quisk_filter_srate = quisk_demod_srate; if (filter_bandwidth < 19000) { // No filtering for wide bandwidth for (i = 0; i < nSamples; i++) cSamples[i] = dRxFilterOut(cSamples[i], bank); } break; } return nSamples; } static double quisk_process_agc(double agcPeak, double agcGain, int nSamples) { // return the new agcGain given agcPeak double d, di; #if DEBUG static int printit; static time_t time0; if (time(NULL) != time0) { time0 = time(NULL); printit = 1; } else { printit = 0; } #endif // Normalize peak amplitude to 1.0 maximum if (agcPeak < 2E3) agcPeak = 2E3 / CLIP32; else agcPeak /= CLIP32; // Change volume using automatic gain control, AGC. // The maximum signal is about 2^31, namely 2e9. // This is the change fraction di, maximum 1 di = (double)nSamples / quisk_sound_state.playback_rate / agcRelease; if (di > 1.0) di = 1.0; // The current output if agcGain is not changed is agcPeak * agcGain if (rxMode == 5) { // mode is FM // Brick wall agc; make all signals the same volume if (agcPeak * agcGain >= 1.0) // clipping agcGain = 0.5 / agcPeak; else // move toward target volume agcGain += (0.5 / agcPeak - agcGain) * di; } else if (agcInUse) { // Set gain with the level control, but limit max signal d = agcMaxGain * agcLevel; // target gain if (d > 0.5 / agcPeak) d = 0.5 / agcPeak; if (agcPeak * agcGain >= 1.0) // clipping agcGain = 0.5 / agcPeak; else agcGain += (d - agcGain) * di; } else { // For no AGC set the gain, but limit to clipping agcGain += (agcOffGain - agcGain) * di; if (agcPeak * agcGain >= 1.0) // clipping agcGain = 1.0 / agcPeak; } #if DEBUG if (printit) { d = CLIP32; printf("agcGain %12.1lf agcMaxGain * agcLevel %.1lf agcPeak %.6lf agcOffGain %.1lf\n", agcGain, agcMaxGain * agcLevel, agcPeak / 2.e9, agcOffGain); } #endif return agcGain; } int quisk_process_samples(complex * cSamples, int nSamples) { // Called when samples are available. // Samples range from about 2^16 to a max of 2^31. int i, n, nout, is_key_down, interp; double d, dr, di, agcPeak; double double_filter_decim; complex phase; int orig_nSamples; static int size_dsamples = 0; // Current dimension of dsamples, dsamples2, orig_cSamples static double * dsamples = NULL; static double * dsamples2 = NULL; static complex * orig_cSamples = NULL; static double agcGainReal; // Volume level control for audio output static double agcGainImag; // Volume level control for audio output static complex rxTuneVector = 1; static complex txTuneVector = 1; static complex sidetoneVector = BIG_VOLUME; static double dOutCounter = 0; // Cumulative net output samples for sidetone etc. static int sidetoneIsOn = 0; // The status of the sidetone static double sidetoneEnvelope; // Shape the rise and fall times of the sidetone static double keyupEnvelope = 1.0; // Shape the rise time on key up static int playSilence; static int is_squelch = 0; // Are we squelched? static struct quisk_cHB45Filter HalfBand7 = {NULL, 0, 0}; static struct quisk_cHB45Filter HalfBand8 = {NULL, 0, 0}; static struct quisk_cHB45Filter HalfBand9 = {NULL, 0, 0}; #if DEBUG static int printit; static time_t time0; static double levelA=0, levelB=0, levelC=0, levelD=0, levelE=0; if (time(NULL) != time0) { time0 = time(NULL); printit = 1; } else { printit = 0; } #endif if (nSamples <= 0) return nSamples; if (nSamples > size_dsamples) { if (dsamples) free(dsamples); if (dsamples2) free(dsamples2); if (orig_cSamples) free(orig_cSamples); size_dsamples = nSamples * 2; dsamples = (double *)malloc(size_dsamples * sizeof(double)); dsamples2 = (double *)malloc(size_dsamples * sizeof(double)); orig_cSamples = (complex *)malloc(size_dsamples * sizeof(complex)); } is_key_down = quisk_is_key_down(); orig_nSamples = nSamples; if (split_rxtx) memcpy(orig_cSamples, cSamples, nSamples * sizeof(complex)); if (is_key_down && !isFDX) { // The key is down; replace this data block dOutCounter += (double)nSamples * quisk_sound_state.playback_rate / quisk_sound_state.sample_rate; nout = (int)dOutCounter; // number of samples to output dOutCounter -= nout; playSilence = keyupDelay; keyupEnvelope = 0; if (rxMode == 0 || rxMode == 1) { // Play sidetone instead of radio for CW if (! sidetoneIsOn) { // turn on sidetone sidetoneIsOn = 1; sidetoneEnvelope = 0; sidetoneVector = BIG_VOLUME; } for (i = 0 ; i < nout; i++) { if (sidetoneEnvelope < 1.0) { sidetoneEnvelope += 1. / (quisk_sound_state.playback_rate * 5e-3); // 5 milliseconds if (sidetoneEnvelope > 1.0) sidetoneEnvelope = 1.0; } d = creal(sidetoneVector) * sidetoneVolume * sidetoneEnvelope; cSamples[i] = d + I * d; sidetoneVector *= sidetonePhase; } } else { // Otherwise play silence for (i = 0 ; i < nout; i++) cSamples[i] = 0; } return nout; } // Key is up if(sidetoneIsOn) { // decrease sidetone until it is off dOutCounter += (double)nSamples * quisk_sound_state.playback_rate / quisk_sound_state.sample_rate; nout = (int)dOutCounter; // number of samples to output dOutCounter -= nout; for (i = 0; i < nout; i++) { sidetoneEnvelope -= 1. / (quisk_sound_state.playback_rate * 5e-3); // 5 milliseconds if (sidetoneEnvelope < 0) { sidetoneIsOn = 0; sidetoneEnvelope = 0; break; // sidetone is zero } d = creal(sidetoneVector) * sidetoneVolume * sidetoneEnvelope; cSamples[i] = d + I * d; sidetoneVector *= sidetonePhase; } for ( ; i < nout; i++) { // continue with playSilence, even if zero cSamples[i] = 0; playSilence--; } return nout; } if (playSilence > 0) { // Continue to play silence after the key is up dOutCounter += (double)nSamples * quisk_sound_state.playback_rate / quisk_sound_state.sample_rate; nout = (int)dOutCounter; // number of samples to output dOutCounter -= nout; for (i = 0; i < nout; i++) cSamples[i] = 0; playSilence -= nout; return nout; } // We are done replacing sound with a sidetone or silence. Filter and // demodulate the samples as radio sound. // Add a test tone to the data if (testtonePhase) AddTestTone(cSamples, nSamples); // Invert spectrum if (quisk_invert_spectrum) { for (i = 0; i < nSamples; i++) { cSamples[i] = conj(cSamples[i]); } } NoiseBlanker(cSamples, nSamples); // Check for space, then put samples into the fft input array. // Thanks to WB4JFI for the code to add a third FFT buffer, July 2010 (but changed to linked list). if (ptWriteFft->status == EMPTY) { ptWriteFft->status = FILLING; ptWriteFft->index = 0; } if (ptWriteFft->status == FILLING) { // write samples to fft data array for (i = 0; i < nSamples; i++) { ptWriteFft->samples[ptWriteFft->index] = cSamples[i]; if (++(ptWriteFft->index) >= fft_size) { // check sample count ptWriteFft->status = READY; // ready to run fft ptWriteFft = ptWriteFft->next; // next data block if (ptWriteFft->status == EMPTY) { // continue writing samples ptWriteFft->status = FILLING; ptWriteFft->index = 0; } else { // no place to write samples fft_error++; break; } } } } // No need to tune and demodulate if we don't play sound if (quisk_sound_state.dev_play_name[0] == 0) return 0; // Tune the data to frequency if (rx_tune_freq) { phase = cexp((I * -2.0 * M_PI * rx_tune_freq) / quisk_sound_state.sample_rate); for (i = 0; i < nSamples; i++) { cSamples[i] *= rxTuneVector; rxTuneVector *= phase; } } if (rxMode == 6) { // External filter and demodulate d = (double)quisk_sound_state.sample_rate / quisk_sound_state.playback_rate; // total decimation needed nSamples = quisk_extern_demod(cSamples, nSamples, d); goto start_agc; } // Perhaps write sample data to the soundcard output without decimation if (TEST_AUDIO == 1) { // Copy I channel capture to playback di = 1.e4 * quisk_audioVolume; for (i = 0; i < nSamples; i++) cSamples[i] = creal(cSamples[i]) * di; return nSamples; } else if (TEST_AUDIO == 2) { // Copy Q channel capture to playback di = 1.e4 * quisk_audioVolume; for (i = 0; i < nSamples; i++) cSamples[i] = cimag(cSamples[i]) * di; return nSamples; } #if DEBUG for (i = 0; i < nSamples; i++) { d = cabs(cSamples[i]); if (levelA < d) levelA = d; } #endif nSamples = quisk_process_decimate(cSamples, nSamples, 0); #if DEBUG for (i = 0; i < nSamples; i++) { d = cabs(cSamples[i]); if (levelB < d) levelB = d; } #endif if (measure_freq_mode) measure_freq(cSamples, nSamples, quisk_decim_srate); nSamples = quisk_process_demodulate(cSamples, dsamples, nSamples, 0); if (rxMode == 9) { ; // This mode is already stereo } else if (split_rxtx) { // Demodulate a second channel phase = cexp((I * -2.0 * M_PI * quisk_tx_tune_freq) / quisk_sound_state.sample_rate); // Tune the second channel to frequency for (i = 0; i < orig_nSamples; i++) { orig_cSamples[i] *= txTuneVector; txTuneVector *= phase; } n = quisk_process_decimate(orig_cSamples, orig_nSamples, 1); n = quisk_process_demodulate(orig_cSamples, dsamples2, n, 1); // We assume that n == nSamples switch(split_rxtx) { default: case 1: // stereo, higher frequency is real if (quisk_tx_tune_freq < rx_tune_freq) { for (i = 0; i < nSamples; i++) cSamples[i] = dsamples[i] + I * dsamples2[i]; } else { for (i = 0; i < nSamples; i++) cSamples[i] = dsamples2[i] + I * dsamples[i]; } break; case 2: // stereo, lower frequency is real if (quisk_tx_tune_freq >= rx_tune_freq) { for (i = 0; i < nSamples; i++) cSamples[i] = dsamples[i] + I * dsamples2[i]; } else { for (i = 0; i < nSamples; i++) cSamples[i] = dsamples2[i] + I * dsamples[i]; } break; case 3: // mono receive channel for (i = 0; i < nSamples; i++) cSamples[i] = dsamples[i] + I * dsamples[i]; break; case 4: // mono transmit channel for (i = 0; i < nSamples; i++) cSamples[i] = dsamples2[i] + I * dsamples2[i]; break; } } else { // monophonic sound played on both channels for (i = 0; i < nSamples; i++) { d = dsamples[i]; cSamples[i] = d + I * d; } } // Perhaps decimate by an additional fraction if (quisk_decim_srate != 48000) { double_filter_decim = quisk_decim_srate / 48000.0; nSamples = cFracDecim(cSamples, nSamples, double_filter_decim); quisk_demod_srate = (int)(quisk_demod_srate / double_filter_decim + 0.5); } // Interpolate the samples back to the play rate. // quisk_demod_srate is either 24000 or 48000 +/- clock tolerance. quisk_demod_srate = ((quisk_demod_srate + 12000) / 24000) * 24000; interp = quisk_sound_state.playback_rate / quisk_demod_srate; if (interp > 1) { nSamples = quisk_cInterp2HB45(cSamples, nSamples, &HalfBand7); interp /= 2; } if (interp > 1) { nSamples = quisk_cInterp2HB45(cSamples, nSamples, &HalfBand8); interp /= 2; } if (interp > 1) { nSamples = quisk_cInterp2HB45(cSamples, nSamples, &HalfBand9); interp /= 2; } if (interp != 1) printf ("Failure in quisk.c in integer interpolation\n"); // Find the peak signal amplitude start_agc: if (rxMode == 6 || rxMode == 9) { // DGT-IQ stereo sound agcPeak = 0; for (i = 0; i < nSamples; i++) { d = creal(cSamples[i]); d = fabs(d); if (agcPeak < d) agcPeak = d; d = cimag(cSamples[i]); d = fabs(d); if (agcPeak < d) agcPeak = d; } agcGainReal = quisk_process_agc(agcPeak, agcGainReal, nSamples); d = agcGainReal * 0.95; for (i = 0; i < nSamples; i++) cSamples[i] *= d; } else if (split_rxtx) { // sepatate AGC for left and right channels dr = di = 0; for (i = 0; i < nSamples; i++) { d = creal(cSamples[i]); d = fabs(d); if (dr < d) dr = d; d = cimag(cSamples[i]); d = fabs(d); if (di < d) di = d; } agcGainReal = quisk_process_agc(dr, agcGainReal, nSamples); agcGainImag = quisk_process_agc(di, agcGainImag, nSamples); dr = agcGainReal * 0.95; di = agcGainImag * 0.95; for (i = 0; i < nSamples; i++) cSamples[i] = creal(cSamples[i]) * dr + I * cimag(cSamples[i]) * di; } else { // monophonic sound agcPeak = 0; for (i = 0; i < nSamples; i++) { d = creal(cSamples[i]); d = fabs(d); if (agcPeak < d) agcPeak = d; } agcGainReal = quisk_process_agc(agcPeak, agcGainReal, nSamples); d = agcGainReal * 0.95; for (i = 0; i < nSamples; i++) cSamples[i] *= d; } #if DEBUG if (printit) { d = CLIP32; //printf ("Levels: %12.8lf %12.8lf %12.8lf %12.8lf %12.8lf\n", // levelA/d, levelB/d, levelC/d, levelD/d, levelE/d); levelA = levelB = levelC = levelD = levelE = 0; } #endif if (rxMode == 5) { // mode is FM if (IsSquelch(quisk_tx_tune_freq)) { is_squelch = 1; for (i = 0; i < nSamples; i++) cSamples[i] = 0; } else { is_squelch = 0; } } else { is_squelch = 0; } if (keyupEnvelope < 1.0) { // raise volume slowly after the key goes up di = 1. / (quisk_sound_state.playback_rate * 5e-3); // 5 milliseconds for (i = 0; i < nSamples; i++) { keyupEnvelope += di; if (keyupEnvelope > 1.0) { keyupEnvelope = 1.0; break; } cSamples[i] *= keyupEnvelope; } } if (quisk_record_state == RECORD && ! is_squelch) tmp_record(cSamples, nSamples); // save radio sound if (quisk_record_state == PLAYBACK) tmp_playback(cSamples, nSamples, quisk_audioVolume); // replace radio sound return nSamples; } static PyObject * get_state(PyObject * self, PyObject * args) { int unused = 0; if (args && !PyArg_ParseTuple (args, "")) // args=NULL internal call return NULL; return Py_BuildValue("iiiiisisiiiiiiiii", quisk_sound_state.rate_min, quisk_sound_state.rate_max, quisk_sound_state.sample_rate, quisk_sound_state.chan_min, quisk_sound_state.chan_max, &quisk_sound_state.msg1, unused, &quisk_sound_state.err_msg, quisk_sound_state.read_error, quisk_sound_state.write_error, quisk_sound_state.underrun_error, quisk_sound_state.latencyCapt, quisk_sound_state.latencyPlay, quisk_sound_state.interupts, fft_error, mic_max_display, quisk_sound_state.data_poll_usec ); } static PyObject * get_squelch(PyObject * self, PyObject * args) { int freq; if (!PyArg_ParseTuple (args, "i", &freq)) return NULL; return PyInt_FromLong(IsSquelch(freq)); } static PyObject * get_overrange(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; return PyInt_FromLong(quisk_get_overrange()); } static PyObject * get_filter_rate(PyObject * self, PyObject * args) { // return the filter sample rate as used by quisk_process_samples complex cSamples[2]; double dsamples[2]; if (!PyArg_ParseTuple (args, "")) return NULL; // run some fake data through the filters to calculate the rates quisk_process_decimate(cSamples, 0, 0); quisk_process_demodulate(cSamples, dsamples, 0, 0); return PyInt_FromLong(quisk_filter_srate); } static PyObject * get_smeter(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; return PyFloat_FromDouble(Smeter); } static PyObject * measure_frequency(PyObject * self, PyObject * args) { int mode; if (!PyArg_ParseTuple (args, "i", &mode)) return NULL; if (mode >= 0) // mode >= 0 set the mode; mode < 0, just return the frequency measure_freq_mode = mode; return PyFloat_FromDouble(measured_frequency); } static PyObject * add_tone(PyObject * self, PyObject * args) { /* Add a test tone to the captured audio data */ int freq; if (!PyArg_ParseTuple (args, "i", &freq)) return NULL; if (freq && sample_rate) testtonePhase = cexp((I * 2.0 * M_PI * freq) / sample_rate); else testtonePhase = 0; Py_INCREF (Py_None); return Py_None; } static PyObject * open_key(PyObject * self, PyObject * args) { const char * name; if (!PyArg_ParseTuple (args, "s", &name)) return NULL; return PyInt_FromLong(quisk_open_key(name)); } static PyObject * open_rx_udp(PyObject * self, PyObject * args) { const char * ip; int port; char buf[128]; struct sockaddr_in Addr; int recvsize; #if DEBUG_IO int intbuf; #ifdef MS_WINDOWS int bufsize = sizeof(int); #else socklen_t bufsize = sizeof(int); #endif #endif #ifdef MS_WINDOWS WORD wVersionRequested; WSADATA wsaData; #endif if (!PyArg_ParseTuple (args, "si", &ip, &port)) return NULL; #ifdef MS_WINDOWS wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { sprintf(buf, "Failed to initialize Winsock (WSAStartup)"); return PyString_FromString(buf); } #endif quisk_using_udp = 1; rx_udp_socket = socket(PF_INET, SOCK_DGRAM, 0); if (rx_udp_socket != INVALID_SOCKET) { recvsize = 256000; setsockopt(rx_udp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, sizeof(recvsize)); memset(&Addr, 0, sizeof(Addr)); Addr.sin_family = AF_INET; Addr.sin_port = htons(port); #ifdef MS_WINDOWS Addr.sin_addr.S_un.S_addr = inet_addr(ip); #else inet_aton(ip, &Addr.sin_addr); #endif if (connect(rx_udp_socket, (const struct sockaddr *)&Addr, sizeof(Addr)) != 0) { shutdown(rx_udp_socket, QUISK_SHUT_BOTH); close(rx_udp_socket); rx_udp_socket = INVALID_SOCKET; sprintf(buf, "Failed to connect to UDP %s port 0x%X", ip, port); } else { sprintf(buf, "Capture from UDP %s port 0x%X", ip, port); #if DEBUG_IO if (getsockopt(rx_udp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&intbuf, &bufsize) == 0) printf("UDP socket receive buffer size %d\n", intbuf); else printf ("Failure SO_RCVBUF\n"); #endif } } else { sprintf(buf, "Failed to open socket"); } return PyString_FromString(buf); } static PyObject * close_rx_udp(PyObject * self, PyObject * args) { short msg = 0x7373; // shutdown if (!PyArg_ParseTuple (args, "")) return NULL; if (rx_udp_socket != INVALID_SOCKET) { shutdown(rx_udp_socket, QUISK_SHUT_RD); send(rx_udp_socket, (char *)&msg, 2, 0); send(rx_udp_socket, (char *)&msg, 2, 0); QuiskSleepMicrosec(3000000); close(rx_udp_socket); rx_udp_socket = INVALID_SOCKET; } rx_udp_started = 0; if (quisk_using_udp) { quisk_using_udp = 0; #ifdef MS_WINDOWS WSACleanup(); #endif } Py_INCREF (Py_None); return Py_None; } int quisk_read_rx_udp(complex * samp) // Read samples from UDP { // Size of complex sample array is SAMP_BUFFER_SIZE ssize_t bytes; unsigned char buf[1500]; // Maximum Ethernet is 1500 bytes. static unsigned char seq0; // must be 8 bits int i, count, nSamples, xr, xi, index; unsigned char * ptxr, * ptxi; struct timeval tm_wait; fd_set fds; static complex dc_average = 0; // Average DC component in samples static complex dc_sum = 0; static int dc_count = 0; static int dc_key_delay = 0; // Data from the receiver is little-endian if ( ! rx_udp_read_blocks) { // "rx_udp_read_blocks" is the number of UDP blocks to read at once rx_udp_read_blocks = (int)(quisk_sound_state.data_poll_usec * 1e-6 * sample_rate + 0.5); rx_udp_read_blocks = (rx_udp_read_blocks + (RX_UDP_SIZE / 12)) / (RX_UDP_SIZE / 6); // 6 bytes per sample if (rx_udp_read_blocks < 1) rx_udp_read_blocks = 1; #if DEBUG_IO printf("read_rx_udp: rx_udp_read_blocks %d\n", rx_udp_read_blocks); #endif } if ( ! rx_udp_gain_correct) { int dec; dec = (int)(rx_udp_clock / sample_rate + 0.5); if ((dec / 5) * 5 == dec) // Decimation by a factor of 5 rx_udp_gain_correct = 1.31072; else // Decimation by factors of two rx_udp_gain_correct = 1.0; } if ( ! rx_udp_started) { // we never received any data // send our return address until we receive UDP blocks tm_wait.tv_sec = 0; tm_wait.tv_usec = 5000; FD_ZERO (&fds); FD_SET (rx_udp_socket, &fds); if (select (rx_udp_socket + 1, &fds, NULL, NULL, &tm_wait) == 1) { // see if data is available bytes = recv(rx_udp_socket, (char *)buf, 1500, 0); // throw away the first block seq0 = buf[0] + 1; // Next expected sequence number rx_udp_started = 1; #if DEBUG_IO printf("Udp data started\n"); #endif } else { // send our return address to the sample source buf[0] = buf[1] = 0x72; // UDP command "register return address" send(rx_udp_socket, (char *)buf, 2, 0); return 0; } } nSamples = 0; for (count = 0; count < rx_udp_read_blocks; count++) { // read several UDP blocks tm_wait.tv_sec = 0; tm_wait.tv_usec = 100000; // Linux seems to have problems with very small time intervals FD_ZERO (&fds); FD_SET (rx_udp_socket, &fds); i = select (rx_udp_socket + 1, &fds, NULL, NULL, &tm_wait); if (i == 1) ; else if (i == 0) { #if DEBUG_IO printf("Udp socket timeout\n"); #endif return 0; } else { #if DEBUG_IO printf("Udp select error %d\n", i); #endif return 0; } bytes = recv(rx_udp_socket, (char *)buf, 1500, 0); // blocking read if (bytes != RX_UDP_SIZE) { // Known size of sample block quisk_sound_state.read_error++; #if DEBUG_IO printf("read_rx_udp: Bad block size\n"); #endif continue; } // buf[0] is the sequence number // buf[1] is the status: // bit 0: key up/down state // bit 1: set for ADC overrange (clip) if (buf[0] != seq0) { #if DEBUG_IO printf("read_rx_udp: Bad sequence want %3d got %3d at block %d of %d\n", (unsigned int)seq0, (unsigned int)buf[0], count, rx_udp_read_blocks); #endif quisk_sound_state.read_error++; } seq0 = buf[0] + 1; // Next expected sequence number quisk_set_key_down(buf[1] & 0x01); // bit zero is key state if (buf[1] & 0x02) // bit one is ADC overrange quisk_sound_state.overrange++; index = 2; ptxr = (unsigned char *)&xr; ptxi = (unsigned char *)ξ // convert 24-bit samples to 32-bit samples; int must be 32 bits. if (is_little_endian) { while (index < bytes) { xr = xi = 0; memcpy (ptxr + 1, buf + index, 3); index += 3; memcpy (ptxi + 1, buf + index, 3); index += 3; samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct; xr = xi = 0; memcpy (ptxr + 1, buf + index, 3); index += 3; memcpy (ptxi + 1, buf + index, 3); index += 3; samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct;; //if (nSamples == 2) printf("%12d %12d\n", xr, xi); } } else { // big-endian while (index < bytes) { *(ptxr ) = buf[index + 2]; *(ptxr + 1) = buf[index + 1]; *(ptxr + 2) = buf[index ]; *(ptxr + 3) = 0; index += 3; *(ptxi ) = buf[index + 2]; *(ptxi + 1) = buf[index + 1]; *(ptxi + 2) = buf[index ]; *(ptxi + 3) = 0; index += 3; samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct;; *(ptxr ) = buf[index + 2]; *(ptxr + 1) = buf[index + 1]; *(ptxr + 2) = buf[index ]; *(ptxr + 3) = 0; index += 3; *(ptxi ) = buf[index + 2]; *(ptxi + 1) = buf[index + 1]; *(ptxi + 2) = buf[index ]; *(ptxi + 3) = 0; index += 3; samp[nSamples++] = (xr + xi * I) * rx_udp_gain_correct;; } } } if (quisk_is_key_down()) { dc_key_delay = 0; dc_sum = 0; dc_count = 0; } else if (dc_key_delay < quisk_sound_state.sample_rate) { dc_key_delay += nSamples; } else { dc_count += nSamples; for (i = 0; i < nSamples; i++) // Correction for DC offset in samples dc_sum += samp[i]; if (dc_count > quisk_sound_state.sample_rate * 2) { dc_average = dc_sum / dc_count; dc_sum = 0; dc_count = 0; //printf("dc average %lf %lf %d\n", creal(dc_average), cimag(dc_average), dc_count); //printf("dc polar %.0lf %d\n", cabs(dc_average), // (int)(360.0 / 2 / M_PI * atan2(cimag(dc_average), creal(dc_average)))); } } if (use_remove_dc) for (i = 0; i < nSamples; i++) // Correction for DC offset in samples samp[i] -= dc_average; return nSamples; } static PyObject * open_sound(PyObject * self, PyObject * args) { char * capt, * play, * mname, * mip, * mpname; if (!PyArg_ParseTuple (args, "ssiiissiiiidsi", &capt, &play, &quisk_sound_state.sample_rate, &quisk_sound_state.data_poll_usec, &quisk_sound_state.latency_millisecs, &mname, &mip, &quisk_sound_state.tx_audio_port, &quisk_sound_state.mic_sample_rate, &quisk_sound_state.mic_channel_I, &quisk_sound_state.mic_channel_Q, &quisk_sound_state.mic_out_volume, &mpname, &quisk_sound_state.mic_playback_rate )) return NULL; if (quisk_sound_state.mic_out_volume > 0.7) // maximum value must leave headroom for quisk_sound_state.mic_out_volume = 0.7; // the amplitude and phase adjustments quisk_sound_state.playback_rate = QuiskGetConfigInt("playback_rate", 48000); quisk_mic_preemphasis = QuiskGetConfigDouble("mic_preemphasis", 0.6); //if (quisk_mic_preemphasis < 0.0 || quisk_mic_preemphasis > 1.0) // quisk_mic_preemphasis = 1.0; quisk_mic_clip = QuiskGetConfigDouble("mic_clip", 3.0); strncpy(quisk_sound_state.dev_capt_name, capt, QUISK_SC_SIZE); strncpy(quisk_sound_state.dev_play_name, play, QUISK_SC_SIZE); strncpy(quisk_sound_state.mic_dev_name, mname, QUISK_SC_SIZE); strncpy(quisk_sound_state.name_of_mic_play, mpname, QUISK_SC_SIZE); strncpy(quisk_sound_state.mic_ip, mip, IP_SIZE); fft_error = 0; quisk_open_sound(); quisk_open_mic(); sample_rate = quisk_sound_state.sample_rate; return get_state(NULL, NULL); } static PyObject * close_sound(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; quisk_close_mic(); quisk_close_sound(); quisk_close_key(); Py_INCREF (Py_None); return Py_None; } static PyObject * change_rate(PyObject * self, PyObject * args) // Called from GUI thread { // Change to a new sample rate if (!PyArg_ParseTuple (args, "ii", &sample_rate, &average_count)) return NULL; quisk_sound_state.sample_rate = sample_rate; rx_udp_read_blocks = 0; // re-calculate rx_udp_gain_correct = 0; // re-calculate Py_INCREF (Py_None); return Py_None; } static PyObject * read_sound(PyObject * self, PyObject * args) { int n; if (!PyArg_ParseTuple (args, "")) return NULL; Py_BEGIN_ALLOW_THREADS n = quisk_read_sound(); Py_END_ALLOW_THREADS return PyInt_FromLong(n); } static PyObject * start_sound(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; quisk_start_sound(); Py_INCREF (Py_None); return Py_None; } static PyObject * mixer_set(PyObject * self, PyObject * args) { char * card_name; int numid; double value; char err_msg[QUISK_SC_SIZE]; if (!PyArg_ParseTuple (args, "sid", &card_name, &numid, &value)) return NULL; quisk_mixer_set(card_name, numid, value, err_msg, QUISK_SC_SIZE); return PyString_FromString(err_msg); } static PyObject * invert_spectrum(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &quisk_invert_spectrum)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_agc(PyObject * self, PyObject * args) { /* Change the AGC parameters */ if (!PyArg_ParseTuple (args, "idd", &agcInUse, &agcLevel, &agcRelease)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_filters(PyObject * self, PyObject * args) { // Enter the coefficients of the I and Q digital filters. The storage for // filters is not malloc'd because filters may be changed while being used. PyObject * filterI, * filterQ; int i, size; PyObject * obj; char buf98[98]; if (!PyArg_ParseTuple (args, "OOi", &filterI, &filterQ, &filter_bandwidth)) return NULL; if (PySequence_Check(filterI) != 1) { PyErr_SetString (QuiskError, "Filter I is not a sequence"); return NULL; } if (PySequence_Check(filterQ) != 1) { PyErr_SetString (QuiskError, "Filter Q is not a sequence"); return NULL; } size = PySequence_Size(filterI); if (size != PySequence_Size(filterQ)) { PyErr_SetString (QuiskError, "The size of filters I and Q must be equal"); return NULL; } if (size >= MAX_FILTER_SIZE) { snprintf(buf98, 98, "Filter size must be less than %d", MAX_FILTER_SIZE); PyErr_SetString (QuiskError, buf98); return NULL; } for (i = 0; i < size; i++) { obj = PySequence_GetItem(filterI, i); cFilterI[i] = PyFloat_AsDouble(obj); Py_XDECREF(obj); obj = PySequence_GetItem(filterQ, i); cFilterQ[i] = PyFloat_AsDouble(obj); Py_XDECREF(obj); } sizeFilter = size; Py_INCREF (Py_None); return Py_None; } static PyObject * set_auto_notch(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &quisk_auto_notch)) return NULL; dAutoNotch(NULL, 0, 0, 0); Py_INCREF (Py_None); return Py_None; } static PyObject * set_noise_blanker(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &quisk_noise_blanker)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_rx_mode(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &rxMode)) return NULL; quisk_set_tx_mode(); Py_INCREF (Py_None); return Py_None; } static PyObject * set_split_rxtx(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &split_rxtx)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_tune(PyObject * self, PyObject * args) { /* Change the tuning frequency */ if (!PyArg_ParseTuple (args, "ii", &rx_tune_freq, &quisk_tx_tune_freq)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_sidetone(PyObject * self, PyObject * args) { double delay; // play extra silence after key-up, in milliseconds if (!PyArg_ParseTuple (args, "iid", &quisk_sidetoneCtrl, &rit_freq, &delay)) return NULL; //printf("Sidetone control times 5 = %d\n", quisk_sidetoneCtrl * 5); // Simulate log taper pot sidetoneVolume = (exp(quisk_sidetoneCtrl * 0.006908) - 1) / 1000.0; sidetonePhase = cexp((I * 2.0 * M_PI * abs(rit_freq)) / quisk_sound_state.playback_rate); keyupDelay = (int)(quisk_sound_state.playback_rate *1e-3 * delay + 0.5); if (rxMode == 0 || rxMode == 1) dAutoNotch(NULL, 0, 0, 0); // for CW, changing the RIT affects autonotch Py_INCREF (Py_None); return Py_None; } static PyObject * set_squelch(PyObject * self, PyObject * args) { /* Change the squelch parameter */ if (!PyArg_ParseTuple (args, "d", &squelch_level)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_volume(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "d", &quisk_audioVolume)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_key_down(PyObject * self, PyObject * args) { int down; if (!PyArg_ParseTuple (args, "i", &down)) return NULL; quisk_set_key_down(down); Py_INCREF (Py_None); return Py_None; } static PyObject * get_graph(PyObject * self, PyObject * args) { int i, j, k, n; fft_data * ptFft; PyObject * tuple2; double d2, scale, zoom, deltaf; complex c; static double meter = 0; // RMS s-meter static int use_fft = 1; // Use the FFT, or return raw data if (!PyArg_ParseTuple (args, "idd", &k, &zoom, &deltaf)) return NULL; if (k != use_fft) { // change in data return type; re-initialize use_fft = k; count_fft = 0; } // Look for an fft ready to run. for (i = 0, ptFft = ptWriteFft; i < 3; i++, ptFft = ptFft->next) { if (ptFft->status == READY) break; } if (i >= 3) { // no fft was ready Py_INCREF(Py_None); return Py_None; } if ( ! use_fft) { // return raw data, not FFT use_remove_dc = 0; // No DC removal when returning raw data tuple2 = PyTuple_New(data_width); for (i = 0; i < data_width; i++) PyTuple_SetItem(tuple2, i, PyComplex_FromDoubles(creal(ptFft->samples[i]), cimag(ptFft->samples[i]))); ptFft->status = EMPTY; return tuple2; } use_remove_dc = 1; // Continue with FFT calculation for (i = 0; i < fft_size; i++) // multiply by window ptFft->samples[i] *= fft_window[i]; fftw_execute(ptFft->plan); // Calculate FFT // Create RMS s-meter value at known bandwidth // d2 is the number of FFT bins required for the bandwidth // i is the starting bin number from - sample_rate / 2 to + sample_rate / 2 d2 = (double)filter_bandwidth * fft_size / sample_rate; n = (int)(floor(d2) + 0.01); // number of whole bins to add switch(rxMode) { case 0: // CWL: signal centered in bandwidth case 1: // CWU case 4: // AM case 5: // FM case 9: // DGT-IQ default: i = (int)((double)quisk_tx_tune_freq * fft_size / sample_rate - d2 / 2 + 0.5); break; case 2: // LSB: bandwidth is below tx frequency case 8: i = (int)((double)quisk_tx_tune_freq * fft_size / sample_rate - d2 + 0.5); break; case 3: // USB: bandwidth is above tx frequency case 7: i = (int)((double)quisk_tx_tune_freq * fft_size / sample_rate + 0.5); break; } if (i > - fft_size / 2 && i + n + 1 < fft_size / 2) { // too close to edge? for (j = 0; j < n; i++, j++) { if (i < 0) c = ptFft->samples[fft_size + i]; // negative frequencies else c = ptFft->samples[i]; // positive frequencies meter += c * conj(c); // add square of amplitude } if (i < 0) // add fractional next bin c = ptFft->samples[fft_size + i]; else c = ptFft->samples[i]; meter += c * conj(c) * (d2 - n); // fractional part of next bin } // Average the fft data into the graph in order of frequency k = 0; for (i = fft_size / 2; i < fft_size; i++) // Negative frequencies fft_avg[k++] += cabs(ptFft->samples[i]); for (i = 0; i < fft_size / 2; i++) // Positive frequencies fft_avg[k++] += cabs(ptFft->samples[i]); ptFft->status = EMPTY; if (++count_fft < average_count) { Py_INCREF(Py_None); // No data yet return Py_None; } // We have averaged enough fft's to return the graph data. // Average the fft data of size fft_size into the size of data_width. n = (int)(zoom * (double)fft_size / data_width + 0.5); if (n < 1) n = 1; for (i = 0; i < data_width; i++) { // For each graph pixel // find k, the starting index into the FFT data k = (int)(fft_size * ( deltaf / sample_rate + zoom * ((double)i / data_width - 0.5) + 0.5) + 0.1); d2 = 0.0; for (j = 0; j < n; j++, k++) if (k >= 0 && k < fft_size) d2 += fft_avg[k]; fft_avg[i] = d2; } scale = 1.0 / 2147483647.0 / fft_size; Smeter = meter * scale * scale / average_count; // record the new s-meter value meter = 0; if (Smeter > 0) Smeter = 10.0 * log10(Smeter); else Smeter = -140.0; // This correction is for a -40 dB strong signal, and is caused by FFT leakage // into adjacent bins. It is the amplitude that is spread out, not the squared amplitude. Smeter += 4.25969; count_fft = 0; tuple2 = PyTuple_New(data_width); // scale = 1.0 / average_count / fft_size; // Divide by sample count // scale /= pow(2.0, 31); // Normalize to max == 1 scale = log10(average_count) + log10(fft_size) + 31.0 * log10(2.0); scale *= 20.0; for (i = 0; i < data_width; i++) { d2 = 20.0 * log10(fft_avg[i]) - scale; if (d2 < -200) d2 = -200; current_graph[i] = d2; PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(d2)); } for (i = 0; i < fft_size; i++) fft_avg[i] = 0; return tuple2; } static PyObject * get_filter(PyObject * self, PyObject * args) { int i, j, k, n; int freq, time; PyObject * tuple2; complex cx; double d2, scale, accI, accQ; double * average, * bufI, * bufQ; fft_data * FFT; fftw_complex * pt; double phase, delta; if (!PyArg_ParseTuple (args, "")) return NULL; // Create space for the fft of size data_width FFT = (fft_data *)malloc(sizeof(fft_data)); FFT->status = EMPTY; FFT->index = 0; pt = FFT->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * data_width); FFT->plan = fftw_plan_dft_1d(data_width, pt, pt, FFTW_FORWARD, FFTW_MEASURE); average = (double *) malloc(sizeof(double) * (data_width + sizeFilter)); bufI = (double *) malloc(sizeof(double) * sizeFilter); bufQ = (double *) malloc(sizeof(double) * sizeFilter); for (i = 0; i < data_width + sizeFilter; i++) average[i] = 0.5; // Value for freq == 0 for (freq = 1; freq < data_width / 2.0 - 10.0; freq++) { delta = 2 * M_PI / data_width * freq; phase = 0; // generate some initial samples to fill the filter pipeline for (time = 0; time < data_width + sizeFilter; time++) { average[time] += cos(phase); // current sample phase += delta; if (phase > 2 * M_PI) phase -= 2 * M_PI; } } // now filter the signal n = 0; for (time = 0; time < data_width + sizeFilter; time++) { d2 = average[time]; bufI[n] = d2; bufQ[n] = d2; accI = accQ = 0; j = n; for (k = 0; k < sizeFilter; k++) { accI += bufI[j] * cFilterI[k]; accQ += bufQ[j] * cFilterQ[k]; if (++j >= sizeFilter) j = 0; } cx = accI + I * accQ; // Filter output if (++n >= sizeFilter) n = 0; if (time >= sizeFilter) FFT->samples[time - sizeFilter] = cx; } for (i = 0; i < data_width; i++) // multiply by window FFT->samples[i] *= fft_window[i]; fftw_execute(FFT->plan); // Calculate FFT // Normalize and convert to log10 scale = 1. / data_width; for (k = 0; k < data_width; k++) { cx = FFT->samples[k]; average[k] = cabs(cx) * scale; if (average[k] <= 1e-7) // limit to -140 dB average[k] = -7; else average[k] = log10(average[k]); } // Return the graph data tuple2 = PyTuple_New(data_width); i = 0; // Negative frequencies: for (k = data_width / 2; k < data_width; k++, i++) PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k])); // Positive frequencies: for (k = 0; k < data_width / 2; k++, i++) PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k])); free(bufQ); free(bufI); free(average); fftw_destroy_plan(FFT->plan); fftw_free(FFT->samples); free(FFT); return tuple2; } static void measure_freq(complex * cSamples, int nSamples, int srate) { int i, k, center, ipeak; double dmax, c3, freq; complex cBuffer[SAMP_BUFFER_SIZE]; static int index = 0; // current index of samples static int fft_size=12000; // size of fft data static int fft_count=0; // number of ffts for the average static fftw_complex * samples; // complex data for fft static fftw_plan planA; // fft plan for fft static double * fft_window; // window function static double * fft_average; // average amplitudes static struct quisk_cHB45Filter HalfBand1 = {NULL, 0, 0}; static struct quisk_cHB45Filter HalfBand2 = {NULL, 0, 0}; static struct quisk_cHB45Filter HalfBand3 = {NULL, 0, 0}; if ( ! cSamples) { // malloc new space and initialize samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fft_size); planA = fftw_plan_dft_1d(fft_size, samples, samples, FFTW_FORWARD, FFTW_MEASURE); fft_window = (double *) malloc(sizeof(double) * (fft_size + 1)); fft_average = (double *) malloc(sizeof(double) * fft_size); memset(fft_average, 0, sizeof(double) * fft_size); for (i = 0; i < fft_size; i++) // Hanning fft_window[i] = 0.50 - 0.50 * cos(2. * M_PI * i / (fft_size - 1)); return; } memcpy(cBuffer, cSamples, nSamples * sizeof(complex)); // do not destroy cSamples nSamples = quisk_cDecim2HB45(cBuffer, nSamples, &HalfBand1); nSamples = quisk_cDecim2HB45(cBuffer, nSamples, &HalfBand2); nSamples = quisk_cDecim2HB45(cBuffer, nSamples, &HalfBand3); srate /= 8; // sample rate as decimated for (i = 0; i < nSamples && index < fft_size; i++, index++) samples[index] = cBuffer[i]; if (index < fft_size) return; // wait for a full array of samples for (i = 0; i < fft_size; i++) // multiply by window samples[i] *= fft_window[i]; fftw_execute(planA); // Calculate FFT index = 0; fft_count++; // Average the fft data into the graph in order of frequency k = 0; for (i = fft_size / 2; i < fft_size; i++) // Negative frequencies fft_average[k++] += cabs(samples[i]); for (i = 0; i < fft_size / 2; i++) // Positive frequencies fft_average[k++] += cabs(samples[i]); if (fft_count < measure_freq_mode / 2) return; // continue with average // time for a calculation fft_count = 0; dmax = 1.e-20; ipeak = 0; center = fft_size / 2 - rit_freq * fft_size / srate; k = 500; // desired +/- half-bandwidth to search for a peak k = k * fft_size / srate; // convert to index for (i = center - k; i <= center + k; i++) { // search for a peak near the RX freq if (fft_average[i] > dmax) { dmax = fft_average[i]; ipeak = i; } } c3 = 1.36 * (fft_average[ipeak+1] - fft_average[ipeak - 1]) / (fft_average[ipeak-1] + fft_average[ipeak] + fft_average[ipeak+1]); freq = srate * (2 * (ipeak + c3) - fft_size) / 2 / fft_size; freq += rx_tune_freq; // printf("\n%5d %.4lf %.2lf k=%d\n", ipeak, c3, freq, k); measured_frequency = freq; //for (i = ipeak - 10; i <= ipeak + 10 && i >= 0 && i < fft_size; i++) // printf("%4d %12.5f\n", i, fft_average[i] / dmax); memset(fft_average, 0, sizeof(double) * fft_size); } static PyObject * Xdft(PyObject * pyseq, int inverse, int window) { // Native spectral order is 0 Hz to (Fs - 1). Change this to // - (Fs - 1)/2 to + Fs/2. For even Fs==32, there are 15 negative // frequencies, a zero, and 16 positive frequencies. For odd Fs==31, // there are 15 negative and positive frequencies plus zero frequency. // Note that zero frequency is always index (Fs - 1) / 2. PyObject * obj; int i, j, size; static int fft_size = -1; // size of fft data static fftw_complex * samples; // complex data for fft static fftw_plan planF, planB; // fft plan for fftW static double * fft_window; // window function Py_complex pycx; // Python C complex value if (PySequence_Check(pyseq) != 1) { PyErr_SetString (QuiskError, "DFT input data is not a sequence"); return NULL; } size = PySequence_Size(pyseq); if (size <= 0) return PyTuple_New(0); if (size != fft_size) { // Change in previous size; malloc new space if (fft_size > 0) { fftw_destroy_plan(planF); fftw_destroy_plan(planB); fftw_free(samples); free (fft_window); } fft_size = size; // Create space for one fft samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fft_size); planF = fftw_plan_dft_1d(fft_size, samples, samples, FFTW_FORWARD, FFTW_MEASURE); planB = fftw_plan_dft_1d(fft_size, samples, samples, FFTW_BACKWARD, FFTW_MEASURE); fft_window = (double *) malloc(sizeof(double) * (fft_size + 1)); for (i = 0; i <= size/2; i++) { if (1) // Blackman window fft_window[i] = fft_window[size - i] = 0.42 + 0.50 * cos(2. * M_PI * i / size) + 0.08 * cos(4. * M_PI * i / size); else if (1) // Hamming fft_window[i] = fft_window[size - i] = 0.54 + 0.46 * cos(2. * M_PI * i / size); else // Hanning fft_window[i] = fft_window[size - i] = 0.50 + 0.50 * cos(2. * M_PI * i / size); } } j = (size - 1) / 2; // zero frequency in input for (i = 0; i < size; i++) { obj = PySequence_GetItem(pyseq, j); if (PyComplex_Check(obj)) { pycx = PyComplex_AsCComplex(obj); } else if (PyFloat_Check(obj)) { pycx.real = PyFloat_AsDouble(obj); pycx.imag = 0; } else if (PyInt_Check(obj)) { pycx.real = PyInt_AsLong(obj); pycx.imag = 0; } else { Py_XDECREF(obj); PyErr_SetString (QuiskError, "DFT input data is not a complex/float/int number"); return NULL; } samples[i] = pycx.real + I * pycx.imag; if (++j >= size) j = 0; Py_XDECREF(obj); } if (inverse) { // Normalize using 1/N fftw_execute(planB); // Calculate inverse FFT / N if (window) { for (i = 0; i < fft_size; i++) // multiply by window / N samples[i] *= fft_window[i] / size; } else { for (i = 0; i < fft_size; i++) // divide by N samples[i] /= size; } } else { if (window) { for (i = 0; i < fft_size; i++) // multiply by window samples[i] *= fft_window[i]; } fftw_execute(planF); // Calculate FFT } pyseq = PyList_New(fft_size); j = (size - 1) / 2; // zero frequency in input for (i = 0; i < fft_size; i++) { pycx.real = creal(samples[i]); pycx.imag = cimag(samples[i]); PyList_SetItem(pyseq, j, PyComplex_FromCComplex(pycx)); if (++j >= size) j = 0; } return pyseq; } static PyObject * dft(PyObject * self, PyObject * args) { PyObject * tuple2; int window; window = 0; if (!PyArg_ParseTuple (args, "O|i", &tuple2, &window)) return NULL; return Xdft(tuple2, 0, window); } static PyObject * is_key_down(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; return PyInt_FromLong(quisk_is_key_down()); } static PyObject * idft(PyObject * self, PyObject * args) { PyObject * tuple2; int window; window = 0; if (!PyArg_ParseTuple (args, "O|i", &tuple2, &window)) return NULL; return Xdft(tuple2, 1, window); } static PyObject * record_app(PyObject * self, PyObject * args) { // Record the Python object for the application instance, malloc space for fft's. int i, j; fftw_complex * pt; if (!PyArg_ParseTuple (args, "OOiiiil", &pyApp, &quisk_pyConfig, &data_width, &fft_size, &average_count, &sample_rate, &quisk_mainwin_handle)) return NULL; Py_INCREF(quisk_pyConfig); rx_udp_clock = QuiskGetConfigDouble("rx_udp_clock", 122.88e6); agcMaxGain = QuiskGetConfigDouble("agc_max_gain", 15000.0); agcOffGain = QuiskGetConfigDouble("agc_off_gain", 1400.0); quisk_sound_state.sample_rate = sample_rate; // also set by open_sound() is_little_endian = 1; // Test machine byte order if (*(char *)&is_little_endian == 1) is_little_endian = 1; else is_little_endian = 0; strncpy (quisk_sound_state.err_msg, CLOSED_TEXT, QUISK_SC_SIZE); count_fft = 0; // Create space for the fft if (FFT1) { fftw_destroy_plan(FFT1->plan); fftw_free(FFT1->samples); free(FFT1); } FFT1 = (fft_data *)malloc(sizeof(fft_data)); FFT1->status = EMPTY; pt = FFT1->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fft_size); FFT1->plan = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_MEASURE); ptWriteFft = FFT1; // Create space to write samples while the first fft is in use if (FFT2) { fftw_destroy_plan(FFT2->plan); fftw_free(FFT2->samples); free(FFT2); } FFT2 = (fft_data *)malloc(sizeof(fft_data)); FFT2->status = EMPTY; pt = FFT2->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fft_size); FFT2->plan = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_MEASURE); // Create space to write samples while the first and second fft is in use // WB4JFI ADD if (FFT3) { fftw_destroy_plan(FFT3->plan); fftw_free(FFT3->samples); free(FFT3); } FFT3 = (fft_data *)malloc(sizeof(fft_data)); FFT3->status = EMPTY; pt = FFT3->samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * fft_size); FFT3->plan = fftw_plan_dft_1d(fft_size, pt, pt, FFTW_FORWARD, FFTW_MEASURE); FFT1->next = FFT2; // create pointers to the next data block FFT2->next = FFT3; FFT3->next = FFT1; // Create space for the fft average and window if (fft_avg) free(fft_avg); if (fft_window) free(fft_window); fft_avg = (double *) malloc(sizeof(double) * fft_size); for (i = 0; i < fft_size; i++) fft_avg[i] = 0; fft_window = (double *) malloc(sizeof(double) * fft_size); for (i = 0, j = -fft_size / 2; i < fft_size; i++, j++) { if (0) // Hamming fft_window[i] = 0.54 + 0.46 * cos(2. * M_PI * j / fft_size); else // Hanning fft_window[i] = 0.5 + 0.5 * cos(2. * M_PI * j / fft_size); } if (current_graph) free(current_graph); current_graph = (double *) malloc(sizeof(double) * data_width); measure_freq(NULL, 0, 0); dAutoNotch(NULL, 0, 0, 0); quisk_process_decimate(NULL, 0, 0); quisk_process_demodulate(NULL, NULL, 0, 0); //calc_audio_graph(NULL, 0); #if DEBUG_IO QuiskPrintTime(NULL, 0); #endif Py_INCREF (Py_None); return Py_None; } static PyObject * record_graph(PyObject * self, PyObject * args) { /* record the Python object for the application instance */ if (!PyArg_ParseTuple (args, "iid", &graphX, &graphY, &graphScale)) return NULL; graphScale *= 2; Py_INCREF (Py_None); return Py_None; } static PyObject * test_1(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * test_2(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * test_3(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; Py_INCREF (Py_None); return Py_None; } static PyObject * set_fdx(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &isFDX)) return NULL; Py_INCREF (Py_None); return Py_None; } static PyMethodDef QuiskMethods[] = { {"add_tone", add_tone, METH_VARARGS, "Add a test tone to the data."}, {"dft", dft, METH_VARARGS, "Calculate the discrete Fourier transform."}, {"idft", idft, METH_VARARGS, "Calculate the inverse discrete Fourier transform."}, {"is_key_down", is_key_down, METH_VARARGS, "Check whether the key is down; return 0 or 1."}, {"get_state", get_state, METH_VARARGS, "Return a count of read and write errors."}, {"get_graph", get_graph, METH_VARARGS, "Return a tuple of graph data."}, {"get_filter", get_filter, METH_VARARGS, "Return the frequency response of the receive filter."}, {"get_filter_rate", get_filter_rate, METH_VARARGS, "Return the sample rate used for the filters."}, {"get_tx_filter", quisk_get_tx_filter, METH_VARARGS, "Return the frequency response of the transmit filter."}, {"get_audio_graph", get_audio_graph, METH_VARARGS, "Return a tuple of the audio graph data."}, {"measure_frequency", measure_frequency, METH_VARARGS, "Set the method, return the measured frequency."}, {"get_overrange", get_overrange, METH_VARARGS, "Return the count of overrange (clip) for the ADC."}, {"get_smeter", get_smeter, METH_VARARGS, "Return the S meter reading."}, {"invert_spectrum", invert_spectrum, METH_VARARGS, "Invert the input RF spectrum"}, {"record_app", record_app, METH_VARARGS, "Save the App instance."}, {"record_graph", record_graph, METH_VARARGS, "Record graph parameters."}, {"set_ampl_phase", quisk_set_ampl_phase, METH_VARARGS, "Set the sound card amplitude and phase corrections."}, {"set_agc", set_agc, METH_VARARGS, "Set the AGC parameters."}, {"set_squelch", set_squelch, METH_VARARGS, "Set the squelch parameter."}, {"get_squelch", get_squelch, METH_VARARGS, "Get the squelch state, 0 or 1."}, {"set_file_record", quisk_set_file_record, METH_VARARGS, "Set the state and names of the recording files."}, {"set_filters", set_filters, METH_VARARGS, "Set the receive audio I and Q channel filters."}, {"set_auto_notch", set_auto_notch, METH_VARARGS, "Set the auto notch on or off."}, {"set_noise_blanker", set_noise_blanker, METH_VARARGS, "Set the noise blanker level."}, {"set_record_state", set_record_state, METH_VARARGS, "Set the temp buffer record and playback state."}, {"set_rx_mode", set_rx_mode, METH_VARARGS, "Set the receive mode: CWL, USB, AM, etc."}, {"set_spot_level", quisk_set_spot_level, METH_VARARGS, "Set the spot mode: 0, 1, ... or -1 for no spot"}, {"set_sidetone", set_sidetone, METH_VARARGS, "Set the sidetone volume and frequency."}, {"set_volume", set_volume, METH_VARARGS, "Set the audio output volume."}, {"set_split_rxtx", set_split_rxtx, METH_VARARGS, "Set split for rx/tx."}, {"set_tune", set_tune, METH_VARARGS, "Set the tuning frequency."}, {"test_1", test_1, METH_VARARGS, "Test 1 function."}, {"test_2", test_2, METH_VARARGS, "Test 2 function."}, {"test_3", test_3, METH_VARARGS, "Test 3 function."}, {"set_fdx", set_fdx, METH_VARARGS, "Set full duplex mode; ignore the key status."}, {"sound_devices", quisk_sound_devices, METH_VARARGS, "Return a list of available sound device names."}, {"sound_errors", quisk_sound_errors, METH_VARARGS, "Return a list of text strings with sound devices and error counts"}, {"open_sound", open_sound, METH_VARARGS, "Open the the soundcard device."}, {"close_sound", close_sound, METH_VARARGS, "Stop the soundcard and release resources."}, {"capt_channels", quisk_capt_channels, METH_VARARGS, "Set the I and Q capture channel numbers"}, {"play_channels", quisk_play_channels, METH_VARARGS, "Set the I and Q playback channel numbers"}, {"micplay_channels", quisk_micplay_channels, METH_VARARGS, "Set the I and Q microphone playback channel numbers"}, {"change_rate", change_rate, METH_VARARGS, "Change to a new sample rate"}, {"read_sound", read_sound, METH_VARARGS, "Read from the soundcard."}, {"start_sound", start_sound, METH_VARARGS, "Start the soundcard."}, {"mixer_set", mixer_set, METH_VARARGS, "Set microphone mixer parameters such as volume."}, {"open_key", open_key, METH_VARARGS, "Open access to the state of the key (CW or PTT)."}, {"open_rx_udp", open_rx_udp, METH_VARARGS, "Open a UDP port for capture."}, {"close_rx_udp", close_rx_udp, METH_VARARGS, "Close the UDP port used for capture."}, {"set_key_down", set_key_down, METH_VARARGS, "Change the key up/down state for method \"\""}, {NULL, NULL, 0, NULL} /* Sentinel */ }; PyMODINIT_FUNC init_quisk (void) { PyObject * m; PyObject * c_api_object; static void * Quisk_API[] = QUISK_API_INIT; m = Py_InitModule ("_quisk", QuiskMethods); if (m == NULL) { printf("Py_InitModule of _quisk failed!\n"); return; } QuiskError = PyErr_NewException ("quisk.error", NULL, NULL); Py_INCREF (QuiskError); PyModule_AddObject (m, "error", QuiskError); #if ( (PY_VERSION_HEX < 0x02070000) || ((PY_VERSION_HEX >= 0x03000000) && (PY_VERSION_HEX < 0x03010000)) ) // Old Python interface using CObject /* Create CObjects for handing _quisk symbols to C extensions in other Python modules. */ c_api_object = PyCObject_FromVoidPtr(Quisk_API, NULL); if (c_api_object != NULL) PyModule_AddObject(m, "QUISK_C_API", c_api_object); #else // New Python interface using Capsule /* Create Capsules for handing _quisk symbols to C extensions in other Python modules. */ c_api_object = PyCapsule_New(Quisk_API, "_quisk.QUISK_C_API", NULL); if (c_api_object != NULL) PyModule_AddObject(m, "QUISK_C_API", c_api_object); #endif } quisk-3.6.11/setup.py0000666000175000017500000000635612142723023014042 0ustar jimjim00000000000000from distutils.core import setup, Extension import sys # You must define the version here. A title string including # the version will be written to __init__.py and read by quisk.py. Version = '3.6.11' fp = open("__init__.py", "w") # write title string fp.write("#QUISK version %s\n" % Version) fp.close() module1 = Extension ('quisk._quisk', #include_dirs = ['.'], #library_dirs = ['.'], libraries = ['asound', 'portaudio', 'fftw3', 'm'], sources = ['quisk.c', 'sound.c', 'sound_alsa.c', 'sound_portaudio.c', 'is_key_down.c', 'microphone.c', 'utility.c', 'filter.c', 'extdemod.c'], ) module2 = Extension ('quisk.sdriqpkg.sdriq', #libraries = [':_quisk.so', 'm'], libraries = ['m'], sources = ['import_quisk_api.c', 'sdriqpkg/sdriq.c'], include_dirs = ['.', '..'], #runtime_library_dirs = ['.'], ) modulew1 = Extension ('quisk._quisk', include_dirs = ['../fftw3', 'C:/Program Files (x86)/Microsoft DirectX SDK (February 2010)/Include', 'C:/Program Files/Microsoft DirectX SDK (February 2010)/Include',], #'C:/Program Files/Microsoft Visual Studio 8/VC/include'], library_dirs = ['../fftw3'], libraries = ['fftw3-3', 'WS2_32', 'Dxguid', 'Dsound'], sources = ['quisk.c', 'sound.c', 'sound_directx.c', 'is_key_down.c', 'microphone.c', 'utility.c', 'filter.c', 'extdemod.c'], ) modulew2 = Extension ('quisk.sdriqpkg.sdriq', #libraries = [':_quisk.pyd', ':ftd2xx.lib'], libraries = [':ftd2xx.lib'], library_dirs = ['../ftdi/i386'], sources = ['import_quisk_api.c', 'sdriqpkg/sdriq.c'], include_dirs = ['.', '../ftdi'], #extra_link_args = ['--enable-auto-import'], ) if sys.platform == "win32": Modules = [modulew1, modulew2] else: Modules = [module1, module2] setup (name = 'quisk', version = Version, scripts = ['quisk'], description = 'QUISK, which rhymes with "brisk", is a Software Defined Radio (SDR).', long_description = """QUISK is a Software Defined Radio (SDR). You supply a complex (I/Q) mixer to convert radio spectrum to an intermediate frequency (IF) and send that IF to the left and right inputs of the sound card in your computer. The QUISK software will read the sound card data, tune it, filter it, demodulate it, and send the audio to the same sound card for output to external headphones or speakers. Quisk can also control and demodulate data from the SDR-IQ from RfSpace. Quisk works with the quisk_lppan_k3 package by Leigh, WA5ZNU, to control the N8LP LP-PAN panadapter and the Elecraft K3. """, author = 'James C. Ahlstrom', author_email = 'jahlstr@gmail.com', url = 'http://james.ahlstrom.name/quisk/', download_url = 'http://james.ahlstrom.name/quisk/', packages = ['quisk', 'quisk.sdriqpkg', 'quisk.n2adr', 'quisk.softrock', 'quisk.usb'], package_dir = {'quisk' : '.'}, package_data = {'quisk' : ['*.txt', '*.html']}, ext_modules = Modules, classifiers = [ 'Development Status :: 6 - Mature', 'Environment :: X11 Applications', 'Environment :: Win32 (MS Windows)', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Natural Language :: English', 'Operating System :: POSIX :: Linux', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', 'Programming Language :: C', 'Topic :: Communications :: Ham Radio', ], ) quisk-3.6.11/n2adr/0000775000175000017500000000000012164330433013325 5ustar jimjim00000000000000quisk-3.6.11/n2adr/quisk_hardware.py0000666000175000017500000000510112132346634016714 0ustar jimjim00000000000000# This is the hardware file from my shack, which controls various hardware. # The files to control my 2010 transceiver and for the improved version HiQSDR # are in the package directory HiQSDR. from hiqsdr.quisk_hardware import Hardware as BaseHw from n2adr import station_hardware class Hardware(BaseHw): def __init__(self, app, conf): BaseHw.__init__(self, app, conf) self.use_sidetone = 1 self.vfo_frequency = 0 # current vfo frequency self.rf_gain_labels = ('RF 0 dB', 'RF +16', 'RF -20', 'RF -10') self.rf_gain = 0 # Preamp or attenuation in dB; changed via app.Hardware # Other hardware self.anttuner = station_hardware.AntennaTuner(app, conf) # Control the antenna tuner self.lpfilter = station_hardware.LowPassFilter(app, conf) # Control LP filter box self.hpfilter = station_hardware.HighPassFilter(app, conf) # Control HP filter box def open(self): self.anttuner.open() return BaseHw.open(self) def close(self): self.anttuner.close() return BaseHw.close(self) def OnAntTuner(self, text): # One of the tuner buttons was pressed self.anttuner.OnAntTuner(text) def ChangeFilterFrequency(self, tx_freq): # Change the filters but not the receiver; used for panadapter if tx_freq and tx_freq > 0: self.anttuner.SetTxFreq(tx_freq) self.lpfilter.SetTxFreq(tx_freq) self.hpfilter.SetTxFreq(tx_freq) def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None): self.ChangeFilterFrequency(tx_freq) return BaseHw.ChangeFrequency(self, tx_freq, vfo_freq, source, band, event) def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. self.anttuner.ChangeBand(band) self.lpfilter.ChangeBand(band) self.hpfilter.ChangeBand(band) ret = BaseHw.ChangeBand(self, band) self.CorrectSmeter() return ret def HeartBeat(self): # Called at about 10 Hz by the main self.anttuner.HeartBeat() self.lpfilter.HeartBeat() self.hpfilter.HeartBeat() return BaseHw.HeartBeat(self) def OnSpot(self, level): self.anttuner.OnSpot(level) return BaseHw.OnSpot(self, level) def OnButtonRfGain(self, event): self.hpfilter.OnButtonRfGain(event) self.CorrectSmeter() def CorrectSmeter(self): # S-meter correction can change with band or RF gain if self.band == '40': # Basic S-meter correction by band self.correct_smeter = 20.5 else: self.correct_smeter = 20.5 self.correct_smeter -= self.rf_gain / 6.0 # Correct S-meter for RF gain self.application.waterfall.ChangeRfGain(self.rf_gain) # Waterfall colors are constant quisk-3.6.11/n2adr/conf5.py0000664000175000017500000000047412075616035014724 0ustar jimjim00000000000000import sys #hamlib_port = 4575 # Standard port for Quisk control. Set the port in Hamlib to 4575 too. hamlib_port = 4532 # Default port for rig 2. Use this if you can not set the Hamlib port. if sys.platform != "win32": digital_input_name = 'hw:Loopback,0' digital_output_name = digital_input_name quisk-3.6.11/n2adr/conf2.py0000666000175000017500000000170212147211241014704 0ustar jimjim00000000000000# This is a second config file that I use to test various hardware configurations. import sys if sys.platform == "win32": name_of_sound_capt = "Primary" name_of_sound_play = 'Primary' latency_millisecs = 150 data_poll_usec = 20000 else: name_of_sound_capt = 'alsa:CODEC USB' name_of_sound_play = 'alsa:CODEC USB' latency_millisecs = 150 data_poll_usec = 5000 sdriq_name = "/dev/ttyUSB1" # Name of the SDR-IQ device to open mic_clip = 3.0 mic_preemphasis = 0.6 default_screen = 'WFall' waterfall_y_scale = 80 waterfall_y_zero = 40 waterfall_graph_y_scale = 40 waterfall_graph_y_zero = 90 waterfall_graph_size = 160 display_fraction = 1.00 # The edges of the full bandwidth are not valid if microphone_name: mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] quisk-3.6.11/n2adr/quisk_conf.py0000666000175000017500000000433312162640333016046 0ustar jimjim00000000000000# This is the config file from my shack, which controls various hardware. # The files to control my 2010 transceiver and for the improved version HiQSDR # are in the package directory HiQSDR. #from quisk_conf_defaults import * import sys from n2adr import quisk_hardware from n2adr import quisk_widgets if sys.platform == "win32": name_of_sound_play = 'Primary' microphone_name = "USB Audio Device" latency_millisecs = 150 data_poll_usec = 20000 favorites_file_path = "C:/pub/quisk_favorites.txt" elif 0: # portaudio devices name_of_sound_play = 'portaudio:CODEC USB' microphone_name = "portaudio:AK5370" latency_millisecs = 150 data_poll_usec = 5000 favorites_file_path = "/home/jim/pub/quisk_favorites.txt" else: # alsa devices name_of_sound_play = 'alsa:CODEC USB' microphone_name = "alsa:AK5370" latency_millisecs = 150 data_poll_usec = 5000 favorites_file_path = "/home/jim/pub/quisk_favorites.txt" mic_clip = 2.0 # 3.0 mic_preemphasis = 0.6 # 0.6 mic_sample_rate = 48000 playback_rate = 48000 agc_off_gain = 80 tx_level = {None:100, '60':100, '40':110, '30':100, '20':90, '15':150, '12':170, '10':130} default_screen = 'WFall' waterfall_y_scale = 80 waterfall_y_zero = 40 waterfall_graph_y_scale = 40 waterfall_graph_y_zero = 90 waterfall_graph_size = 160 station_display_lines = 1 # DX cluster telent login data, thanks to DJ4CM. dxClHost = '' #dxClHost = 'dxc.w8wts.net' dxClPort = 7373 user_call_sign = 'n2adr' add_imd_button = 1 add_fdx_button = 1 use_rx_udp = 1 # Get ADC samples from UDP rx_udp_ip = "192.168.2.196" # Sample source IP address rx_udp_port = 0xBC77 # Sample source UDP port rx_udp_clock = 122880000 # ADC sample rate in Hertz rx_udp_decimation = 8 * 8 * 8 # Decimation from clock to UDP sample rate sample_rate = int(float(rx_udp_clock) / rx_udp_decimation + 0.5) # Don't change this name_of_sound_capt = "" # We do not capture from the soundcard data_poll_usec = 10000 playback_rate = 48000 display_fraction = 1.00 tx_ip = "192.168.2.196" tx_audio_port = 0xBC79 mic_out_volume = 1.0 mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] quisk-3.6.11/n2adr/conf4.py0000664000175000017500000000305412147211303014705 0ustar jimjim00000000000000# This is a config file to test the microphone by sending filtered # microphone sound to the FFT. The PTT button and the FDX button must be pressed. # Set mic_sample_rate to 8000 or 48000. # To test mic filtering and UDP, set DEBUG_MIC to one in sound.c, and sample_rate to 48000. # To test mic playback, set DEBUG_MIC to two in sound.c, and sample_rate to 48k, 96k or 192k. import sys from quisk_hardware_model import Hardware as BaseHardware import _quisk as QS if sys.platform == "win32": name_of_sound_capt = "Primary" name_of_sound_play = '' microphone_name = "Microphone" name_of_mic_play = 'Primary' latency_millisecs = 150 data_poll_usec = 10000 else: name_of_sound_capt = 'alsa:CODEC USB' name_of_sound_play = '' microphone_name = "alsa:AK5370" name_of_mic_play = 'alsa:CODEC USB' latency_millisecs = 50 data_poll_usec = 5000 graph_y_scale = 160 sample_rate = 192000 mic_sample_rate = 48000 mic_playback_rate = sample_rate mic_out_volume = 0.6 mic_clip = 2.0 mic_preemphasis = 1.0 add_fdx_button = 1 if microphone_name: mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.use_sidetone = 1 def OnButtonPTT(self, event): if event.GetEventObject().GetValue(): QS.set_key_down(1) else: QS.set_key_down(0) quisk-3.6.11/n2adr/station_hardware.py0000666000175000017500000006736712155345275017274 0ustar jimjim00000000000000# This file supports various hardware boxes at my shack from __future__ import print_function import sys, struct, math, socket, select, thread, time, traceback, os import cPickle import serial import _quisk as QS import wx DEBUG = 0 gatewayTime = 0 # time of last gateway command gatewayLimit = 0.2 # minimum time between gateway commands class LowPassFilter: # Control my low pass filter box address = ('192.168.2.194', 0x3A00 + 39) # Filters are numbered 1 thru 8 for bands: 80, 15, 60, 40, 30, 20, 17, short lpfnum = (1, 1, 1, 1, 1, 3, # frequency 0 thru 5 MHz 4, 4, 5, 5, 5, # 6 thru 10 6, 6, 6, 6, 7, # 11 thru 15 7, 7, 7, 2, 2, # 16 thru 20 2, 2, 8, 8, 8) # 21 thru 25; otherwise the filter is 8 def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setblocking(0) self.socket.connect(self.address) self.have_data = None self.want_data = '\00' self.old_tx_freq = 0 self.timer = 0 def ChangeBand(self, band): pass def SetTxFreq(self, tx_freq): if not self.socket: return # Filters are numbered 1 thru 8 if abs(self.old_tx_freq - tx_freq) < 100000: return # Ignore small tuning changes self.old_tx_freq = tx_freq try: # Look up filter number based on MHz num = self.lpfnum[tx_freq / 1000000] except IndexError: num = 8 self.want_data = chr(num) self.timer = 0 def HeartBeat(self): global gatewayTime if not self.socket: return try: # The HP filter box echoes its commands self.have_data = self.socket.recv(50) except socket.error: pass except socket.timeout: pass if self.have_data != self.want_data and time.time() - gatewayTime > gatewayLimit: gatewayTime = time.time() if self.timer <= 10: self.timer += 1 if self.timer == 10: print ('Low pass filter error') try: self.socket.send(self.want_data) except socket.error: pass except socket.timeout: pass class HighPassFilter: # Control my high pass filter box address = ('192.168.2.194', 0x3A00 + 21) def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.preamp = 0 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setblocking(0) self.socket.connect(self.address) self.have_data = None self.want_data = '\00\00\00' self.old_tx_freq = 0 self.timer = 0 def ChangeBand(self, band): btn = self.application.BtnRfGain freq = self.application.VFO + self.application.txFreq if self.conf.use_sdriq: if btn: if freq < 5000000: btn.SetLabel('RF -10', True) elif freq < 13000000: btn.SetLabel('RF 0 dB', True) else: btn.SetLabel('RF +16', True) elif self.conf.use_rx_udp: if btn: if freq < 5000000: btn.SetLabel('RF 0 dB', True) elif freq < 13000000: btn.SetLabel('RF 0 dB', True) else: btn.SetLabel('RF +16', True) def OnButtonRfGain(self, event): """Set my High Pass Filter Box preamp gain and attenuator state.""" btn = event.GetEventObject() n = btn.index if n == 0: # 0dB self.preamp = 0x00 self.application.Hardware.rf_gain = 0 elif n == 1: # +16 self.preamp = 0x02 self.application.Hardware.rf_gain = 16 elif n == 2: # -20 self.preamp = 0x0C self.application.Hardware.rf_gain = -20 elif n == 3: # -10 self.preamp = 0x04 self.application.Hardware.rf_gain = -10 else: print ('Unknown RfGain') self.application.Hardware.rf_gain = 0 self.SetTxFreq(None) def SetTxFreq(self, tx_freq): """Set high pass filter and preamp/attenuator state""" # Filter cutoff in MHz: 0.0, 2.7, 3.95, 5.7, 12.6, 18.2, 22.4 # Frequency MHz Bits Hex Band # ============= ==== === ==== # 0 to 2.70 PORTD, 0 0x01 160 # 2.7 to 3.95 PORTB, 1 0x02 80 # 3.95 to 5.70 PORTD, 7 0x80 60 # 5.70 to 12.60 PORTB, 0 0x01 40, 30 # 12.60 to 18.20 PORTD, 6 0x40 20, 17 # 18.20 to 22.40 PORTB, 7 0x80 15 # 22.40 to 99.99 PORTB, 6 0x40 12, 10 # Other bits: Preamp PORTD 0x02, Atten1 PORTD 0x04, Atten2 PORTD 0x08 if not self.socket: return if tx_freq is None: tx_freq = self.old_tx_freq elif abs(self.old_tx_freq - tx_freq) < 100000: return # Ignore small tuning changes self.old_tx_freq = tx_freq portb = portc = portd = 0 if self.conf.use_sdriq: if tx_freq < 15000000: # Turn preamp on/off self.preamp = 0x00 else: self.preamp = 0x02 elif self.conf.use_rx_udp: pass # self.preamp is already set else: # turn preamp off self.preamp = 0x00 if tx_freq < 12600000: if tx_freq < 3950000: if tx_freq < 2700000: portd = 0x01 else: portb = 0x02 elif tx_freq < 5700000: portd = 0x80 else: portb = 0x01 elif tx_freq < 18200000: portd = 0x40 elif tx_freq < 22400000: portb = 0x80 else: portb = 0x40 portd |= self.preamp self.want_data = chr(portb) + chr(portc) + chr(portd) self.timer = 0 def HeartBeat(self): global gatewayTime if not self.socket: return try: # The HP filter box echoes its commands self.have_data = self.socket.recv(50) except socket.error: pass except socket.timeout: pass if self.have_data != self.want_data and time.time() - gatewayTime > gatewayLimit: gatewayTime = time.time() if self.timer <= 10: self.timer += 1 if self.timer == 10: print ('High pass filter error') try: self.socket.send(self.want_data) except socket.error: pass except socket.timeout: pass class AntennaControl: # Control my KI8BV dipole AntCtrlAddress = ('192.168.2.194', 0x3A00 + 33) def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setblocking(0) self.socket.connect(self.AntCtrlAddress) self.have_data = None self.want_data = '\00' self.timer = 0 def SetTxFreq(self, tx_freq): self.timer = 0 if tx_freq < 19000000: self.want_data = '\03' elif tx_freq < 22000000: self.want_data = '\02' elif tx_freq < 26500000: self.want_data = '\01' else: self.want_data = '\00' def HeartBeat(self): global gatewayTime try: # The antenna control box echoes its commands self.have_data = self.socket.recv(50) except socket.error: pass except socket.timeout: pass if self.have_data != self.want_data and time.time() - gatewayTime > gatewayLimit: gatewayTime = time.time() self.timer += 1 if self.timer == 10: print ('Antenna control error') self.timer = 0 try: self.socket.send(self.want_data) # print ("Change dipole to ord %d" % ord(self.want_data)) except socket.error: pass except socket.timeout: pass class AntennaTuner: # Control my homebrew antenna tuner and my KI8BV dipole address = ('192.168.2.194', 0x3A00 + 47) def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.socket = None self.GUI = None # Control window self.have_data = chr(255) * 3 self.tx_freq = 0 self.tune_freq = 0 # Frequency we last tuned self.disable_freq_control = False self.timer = 0 self.set_L = 0 self.set_C = 0 self.set_HighZ = 0 self.antnum = 0 # Antenna number 0 or 1 self.fix_antnum = False # Fix the antenna number self.dipole2 = AntennaControl(app, conf) # Control the KI8BV dipole if sys.platform == "win32": path = 'C:/pub/TunerLCZ.pkl' else: path = '/home/jim/pub/TunerLCZ.pkl' try: fp = open(path, "r") self.TunerLC = cPickle.load(fp) fp.close() except IOError: self.TunerLC = {} if hasattr(self.application, 'is_vna_program'): self.is_vna = True else: self.is_vna = False self.WantData() def WantData(self): if self.set_HighZ: flags = 0x00 else: flags = 0x08 if self.antnum: flags |= 0x04 self.want_data = chr(self.set_C) + chr(self.set_L) + chr(flags) if self.set_HighZ: hilo = 'HiZ' else: hilo = 'LoZ' text = "L %3d, C %3d, %s, Antenna %d" % (self.set_L, self.set_C, hilo, self.antnum) if self.GUI: self.GUI.sliderL.SetValue(self.set_L) self.GUI.sliderC.SetValue(self.set_C) self.GUI.UpdateText(text) elif self.application.bottom_widgets: self.application.bottom_widgets.UpdateText(text) def open(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.setblocking(0) self.socket.connect(self.address) if self.is_vna: self.GUI = AntTunerGUI(self, self.application) self.GUI.Show() def close(self): pass def OnSpot(self, level): pass def ChangeBand(self, band): pass def SetTxFreq(self, tx_freq): self.tx_freq = tx_freq if tx_freq is None: return if not self.fix_antnum: if tx_freq < 17000000: self.antnum = 0 else: self.antnum = 1 if self.antnum == 1: self.dipole2.SetTxFreq(tx_freq) if not self.socket: return if self.disable_freq_control: return freq = (tx_freq + 5000) / 10000 * 10000 # rounded frequency try: newL, newC, newH = self.TunerLC[freq] except KeyError: newL, newC, newH = (0, 0, 0) if newH != self.set_HighZ or self.set_C != newC or self.set_L != newL: # if not VNA, ignore small changes in frequency if self.is_vna or abs(self.tune_freq - tx_freq) > 5000: self.tune_freq = tx_freq self.set_HighZ = newH self.set_C = newC self.set_L = newL self.WantData() def OnAntTuner(self, text): # One of the tuner buttons was pressed if text == 'Antenna': self.fix_antnum = False elif text == 'Ant 0': self.fix_antnum = True self.antnum = 0 elif text == 'Ant 1': self.fix_antnum = True self.antnum = 1 self.SetTxFreq(self.tx_freq) self.WantData() def HeartBeat(self): global gatewayTime if not self.socket: return try: # The tuner echoes its command self.have_data = data = self.socket.recv(50) except socket.error: data = '' except socket.timeout: data = '' if self.have_data != self.want_data and time.time() - gatewayTime > gatewayLimit: gatewayTime = time.time() self.Send() self.timer += 1 if self.timer == 10: print ('Antenna tuner error') self.timer = 0 else: self.timer = 0 self.dipole2.HeartBeat() if self.GUI: self.GUI.HeartBeat() def Send(self): try: self.socket.send(self.want_data) except socket.error: pass except socket.timeout: pass class AntTunerGUI(wx.Frame): # Display a control window for my antenna tuner def __init__(self, anttuner, app): wx.Frame.__init__(self, app.main_frame, title="Antenna Tuner Control", style=wx.STAY_ON_TOP|wx.CAPTION) self.anttuner = anttuner self.application = app self.data_saving = False self.SetBackgroundColour('white') sizer = wx.GridBagSizer(hgap=5, vgap=3) font = wx.Font(12, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) is_vna = anttuner.is_vna b = wx.StaticText(self, -1, "Adjust L", style=wx.ALIGN_CENTER) b.SetFont(font) sizer.Add(b, pos=(0, 0)) b = self.sliderL = wx.Slider(self, -1, 0, 0, 255, size=(700, -1), style=wx.SL_HORIZONTAL|wx.SL_LABELS) b.Enable(is_vna) b.Bind(wx.EVT_SCROLL, self.OnSliderL) sizer.Add(b, pos=(0,1)) b = wx.Button(self, -1, "HiLo") b.SetFont(font) b.Enable(is_vna) self.Bind(wx.EVT_BUTTON, self.OnButtonHiLo, b) sizer.Add(b, pos=(0,2)) b = wx.StaticText(self, -1, "Adjust C") b.SetFont(font) sizer.Add(b, pos=(1, 0)) b = self.sliderC = wx.Slider(self, -1, 0, 0, 255, size=(700, -1), style=wx.SL_HORIZONTAL|wx.SL_LABELS) b.Enable(is_vna) b.Bind(wx.EVT_SCROLL, self.OnSliderC) sizer.Add(b, pos=(1,1)) b = wx.Button(self, -1, "Save") b.SetFont(font) b.Enable(is_vna) self.Bind(wx.EVT_BUTTON, self.OnButtonSave, b) sizer.Add(b, pos=(1,2)) b = wx.StaticText(self, -1, "Status", style=wx.ALIGN_CENTER) b.SetFont(font) sizer.Add(b, pos=(3, 0)) self.status = b = wx.StaticText(self, -1, "Ready", style=wx.ST_NO_AUTORESIZE) b.SetFont(font) sizer.Add(b, pos=(3, 1), flag=wx.EXPAND) b = wx.ToggleButton(self, -1, "Disable") b.SetFont(font) b.Enable(is_vna) self.Bind(wx.EVT_TOGGLEBUTTON, self.OnBtnDisable, b) sizer.Add(b, pos=(3, 2)) self.SetSizer(sizer) self.Fit() def OnButtonHiLo(self, event): anttuner = self.anttuner if anttuner.set_HighZ: anttuner.set_HighZ = 0 else: anttuner.set_HighZ = 1 anttuner.WantData() def OnButtonSave(self, event): self.data = [] self.data.append(tuple(self.application.graph.data_freq)) self.data_lcz = [] self.data_avg_freq = (self.application.graph.data_freq[0] + self.application.graph.data_freq[-1]) / 2 self.data_avg_freq = f = (self.data_avg_freq + 500000) / 1000000 # frequency rounded to megahertz if f == 5: # try to limit the number of L/C combinations for HighZ in (0, ): for L in range(0, 4): for C in range(0, 61): self.data_lcz.append((L, C, HighZ)) elif f == 7: for HighZ in (0, ): for L in range(0, 21): for C in range(0, 91): self.data_lcz.append((L, C, HighZ)) elif f == 10: for HighZ in (0, ): for L in range(0, 8): for C in range(0, 91): self.data_lcz.append((L, C, HighZ)) elif f == 14: for HighZ in (0, ): for L in range(0, 11): for C in range(0, 21): self.data_lcz.append((L, C, HighZ)) elif f == 18: for HighZ in (0, ): for L in range(0, 11): for C in range(0, 11): self.data_lcz.append((L, C, HighZ)) elif f == 21: for HighZ in (0, ): for L in range(0, 11): for C in range(0, 11): self.data_lcz.append((L, C, HighZ)) elif f == 25: for HighZ in (0, 1): for L in range(0, 11): for C in range(0, 11): self.data_lcz.append((L, C, HighZ)) elif 28 <= f <= 30: for HighZ in (0, 1): for L in range(0, 11): for C in range(0, 15): self.data_lcz.append((L, C, HighZ)) anttuner = self.anttuner anttuner.set_L, anttuner.set_C, anttuner.set_HighZ = self.data_lcz[0] del self.data_lcz[0] anttuner.WantData() self.data_saving = True self.data_count = 0 def OnButtonSaveJIM(self, event): anttuner = self.anttuner freq = anttuner.tx_freq freq = (freq + 5000) / 10000 * 10000 # round LC = anttuner.TunerLC[anttuner.antnum] for i in range(len(LC)): # Record new freq and L/C if abs(LC[i][0] - freq) < 1000: LC[i] = (freq, anttuner.set_L, anttuner.set_C, anttuner.set_HighZ) break else: LC.append((freq, anttuner.set_L, anttuner.set_C, anttuner.set_HighZ)) LC.sort() self.WriteFile() def UpdateText(self, text): self.status.SetLabel(text) def OnSliderL(self, event): self.anttuner.set_L = event.GetEventObject().GetValue() self.anttuner.WantData() def OnSliderC(self, event): self.anttuner.set_C = event.GetEventObject().GetValue() self.anttuner.WantData() def OnBtnDisable(self, event): self.anttuner.disable_freq_control = event.GetEventObject().GetValue() def WriteFile(self): anttuner = self.anttuner fp = open(anttuner.TunerLC_fname, 'w') for i in (0, 1): # antenna number lst = anttuner.TunerLC[i] # freq, L, C, IsHi for each antenna for f, l, c, ishi in lst: fp.write("%d %9d %4d %4d %1d\n" % (i, f, l, c, ishi)) fp.close() def HeartBeat(self): gr = self.application.graph if self.data_saving: anttuner = self.anttuner if anttuner.have_data == anttuner.want_data: self.data_count += 1 if self.data_count > 4: self.data_count = 0 self.data.append(((anttuner.set_L, anttuner.set_C, anttuner.set_HighZ), tuple(self.application.graph.data_mag))) #print ('record 500', (anttuner.set_L, anttuner.set_C, anttuner.set_HighZ), self.application.graph.data_mag[500]) if self.data_lcz: anttuner.set_L, anttuner.set_C, anttuner.set_HighZ = self.data_lcz[0] #print (self.data_lcz[0]) del self.data_lcz[0] anttuner.WantData() else: self.data_saving = False fp = open("/home/jim/pub/Tuner/data%2d.pkl" % self.data_avg_freq, "w") cPickle.dump(self.data, fp) fp.close() class AT200PC: # Control an AT-200PC autotuner made by LDG def __init__(self, app, conf): self.application = app # Application instance (to provide attributes) self.conf = conf # Config file module self.serial = None self.rx_state = 0 self.is_standby = None self.tx_freq = 0 self.old_tx_freq = 0 self.set_L = -9 self.set_C = -9 self.set_HiLoZ = -9 self.tuning_F1 = 0 self.tuning_F2 = 0 self.tuning_diff = 0 self.param1 = [None] * 20 # Parameters returned by the AT-200PC self.param2 = [None] * 20 self.param1[5] = self.param2[5] = self.param2[6] = 0 # power and SWR self.param1[7] = self.param2[7] = 1 # Frequency self.param1[1] = self.param1[2] = 0 # Inductor, Capacitor self.req_swr = 50 # Requested SWR: 50 thru 56 for 1.1, 1.3, 1.5, 1.7, 2.0, 2.5, 3.0 self.live_update = 0 # Request live update 1 or 0 self.antenna = 2 # Select antenna 1 or 2 self.standby = 0 # Set standby mode 1 or 0 self.timer = 0 self.error = "AT-200PC serial port is not open" self.TunerLC_change = False if sys.platform == "win32": self.TunerLC_fname = 'C:/pub/TunerLC.txt' else: self.TunerLC_fname = '/home/jim/pub/TunerLC.txt' def UpdateSwr(self): if not self.application.bottom_widgets: return if self.error: self.application.bottom_widgets.UpdateText(self.error) else: power = (self.param1[5] * 256 + self.param2[5]) / 100.0 swr = self.param2[6] # swr code = 256 * p**2 if power >= 2.0: freq = self.param1[7] * 256 + self.param2[7] freq = 20480000.0 / freq ftext = "Tx freq" swr = math.sqrt(swr / 256.0) swr = (1.0 + swr) / (1.0 - swr) if swr > 99.9: swr = 99.9 else: freq = self.tuning_diff / 1000.0 ftext = "Tune delta" swr = 0.0 if self.param1[3] == 0: # HiLoZ relay value t = "Zh" # High else: t = "Zl" # Low text = "Watts %.0f SWR %.1f %s Ind %d Cap %d %s %.0f kHz" % ( power, swr, t, self.param1[1], self.param1[2], ftext, freq) self.application.bottom_widgets.UpdateText(text) def HeartBeat(self): if not self.serial: self.UpdateSwr() return self.Read() # Receive from the AT-200PC # Call main application with new SWR data self.UpdateSwr() if self.error: # Send a couple parameters, see if we get a response if self.req_swr - 50 != self.param1[16]: self.Write(chr(self.req_swr)) # Send threshold SWR elif self.param1[17] != 0: self.Write(chr(59)) # Turn off AutoTune else: self.error = '' return if self.param1[4] != self.antenna - 1: # Check correct antenna self.Write(chr(9 + self.antenna)) elif self.is_standby != self.standby: # Check standby state self.Write(chr(45 - self.standby)) elif self.param1[19] != self.live_update: # Check live update state self.Write(chr(64 - self.live_update)) elif self.set_L >= 0 and self.set_HiLoZ >= 0 and ( # Check L and Hi/Lo relay self.param1[1] != self.set_L or self.param1[3] != self.set_HiLoZ): if self.set_HiLoZ: self.Write(chr(65) + chr(self.set_L + 128)) else: self.Write(chr(65) + chr(self.set_L)) elif self.param1[2] != self.set_C and self.set_C >= 0: # Set C self.Write(chr(66) + chr(self.set_C)) elif self.live_update: # If our window shows, request an update self.timer += 1 if self.timer > 20: self.timer = 0 self.Write(chr(40)) # Request ALLUPDATE def Write(self, s): # Write a command string to the AT-200PC if DEBUG: print ('Send', ord(s[0])) if self.serial: self.serial.setRTS(1) # Wake up the AT-200PC time.sleep(0.003) # Wait 3 milliseconds self.serial.write(s) self.serial.setRTS(0) def Read(self): # Receive characters from the AT-200PC chars = self.serial.read(1024) for ch in chars: if self.rx_state == 0: # Read first of 4 characters; must be decimal 165 if ord(ch) == 165: self.rx_state = 1 elif self.rx_state == 1: # Read second byte self.rx_state = 2 self.rx_byte1 = ord(ch) elif self.rx_state == 2: # Read third byte self.rx_state = 3 self.rx_byte2 = ord(ch) elif self.rx_state == 3: # Read fourth byte self.rx_state = 0 byte3 = ord(ch) byte1 = self.rx_byte1 byte2 = self.rx_byte2 if DEBUG: print ('Received', byte1, byte2, byte3) if byte1 > 19: # Impossible command value continue if byte1 == 1 and self.set_L < 0: # reported inductor value self.set_L = byte2 if byte1 == 2 and self.set_C < 0: # reported capacitor value self.set_C = byte2 if byte1 == 3 and self.set_HiLoZ < 0: # reported Hi/Lo relay self.set_HiLoZ = byte2 if byte1 == 13: # Start standby self.is_standby = 1 elif byte1 == 14: # Start active self.is_standby = 0 self.param1[byte1] = byte2 self.param2[byte1] = byte3 def OpenPort(self): if sys.platform == "win32": tty_list = ("COM7", "COM8", "COM10", "COM11") else: tty_list = ("/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2") for tty_name in tty_list: try: port = serial.Serial(port=tty_name, baudrate=9600, timeout=0) except: #traceback.print_exc() pass else: port.setRTS(0) time.sleep(0.1) for i in range(3): port.setRTS(1) time.sleep(0.003) # Wait 3 milliseconds port.write(chr(41)) port.setRTS(0) time.sleep(0.1) chars = port.read(1024) #print 'Got', tty_name, len(chars), repr(chars) if chars == '?\r\n': # Wrong port break if "\xA5\x0B\x01\x20" in chars: self.serial = port break if self.serial: break else: port.close() def open(self): self.OpenPort() if self.serial: self.error = "Waiting for AT200PC" # TunerLC is a list of (freq, L, C). Use -L for Low Z, +L for High Z. # The first and last entry must have frequency 0 and 99999999. self.TunerLC = [] fp = open(self.TunerLC_fname, 'r') for line in fp: line = line.split() f = int(line[0]) l = int(line[1]) c = int(line[2]) self.TunerLC.append((f, l, c)) fp.close() def close(self): if self.serial: self.serial.close() self.serial = None if self.TunerLC_change: fp = open(self.TunerLC_fname, 'w') for f, l, c in self.TunerLC: fp.write("%9d %4d %4d\n" % (f, l, c)) fp.close() def xxReqSetFreq(self, tx_freq): # Set relays for this frequency. The frequency must exist in the tuner. if self.serial and not self.standby and tx_freq > 1500000: ticks = int(20480.0 / tx_freq * 1e6 + 0.5) self.Write(chr(67) + chr((ticks & 0xFF00) >> 8) + chr(ticks & 0xFF)) def SetTxFreq(self, tx_freq): if tx_freq is None: self.set_C = 0 self.set_L = 0 self.set_HiLoZ = 0 return self.tx_freq = tx_freq if abs(self.old_tx_freq - tx_freq) < 20000: d1 = tx_freq - self.tuning_F1 d2 = tx_freq - self.tuning_F2 if abs(d1) <= abs(d2): self.tuning_diff = d1 else: self.tuning_diff = d2 return # Ignore small tuning changes self.old_tx_freq = tx_freq i1 = 0 i2 = len(self.TunerLC) - 1 while 1: # binary partition i = (i1 + i2) / 2 if self.TunerLC[i][0] < tx_freq: i1 = i else: i2 = i if i2 - i1 <= 1: break # The correct setting is between i1 and i2; interpolate F1 = self.TunerLC[i1][0] F2 = self.TunerLC[i2][0] L1 = self.TunerLC[i1][1] L2 = self.TunerLC[i2][1] C1 = self.TunerLC[i1][2] C2 = self.TunerLC[i2][2] frac = (float(tx_freq) - F1) / (F2 - F1) C = C1 + (C2 - C1) * frac self.set_C = int(C + 0.5) L = L1 + (L2 - L1) * frac if L < 0: L = -L self.set_HiLoZ = 1 else: self.set_HiLoZ = 0 self.set_L = int(L + 0.5) # Report the frequency difference self.tuning_F1 = F1 self.tuning_F2 = F2 d1 = tx_freq - F1 d2 = tx_freq - F2 if abs(d1) <= abs(d2): self.tuning_diff = d1 else: self.tuning_diff = d2 def ChangeBand(self, band): pass ##self.ReqSetFreq(self.tx_freq) def OnSpot(self, level): # level 0 == OFF, else the level 10 to 1000 if self.serial: if level == 0: self.live_update = 0 elif not self.live_update: self.live_update = 1 self.timer = 999 def OnAntTuner(self, text): # One of the tuner buttons was pressed if self.serial: if text == 'Tune': if not self.standby: #self.Write(chr(5)) # Request memory tune self.Write(chr(6)) # Request full tune self.set_C = -9 self.set_L = -9 self.set_HiLoZ = -9 elif text == 'Save': self.Write(chr(46)) if self.set_HiLoZ == 0: # High Z L = self.set_L else: # Low Z L = -self.set_L for i in range(len(self.TunerLC)): # Record new freq and L/C if abs(self.TunerLC[i][0] - self.tx_freq) < 1000: self.TunerLC[i] = (self.tx_freq, L, self.set_C) break else: self.TunerLC.append((self.tx_freq, L, self.set_C)) self.TunerLC.sort() self.TunerLC_change = True elif text == 'L+': self.set_L += 1 elif text == 'L-': self.set_L -= 1 elif text == 'C+': self.set_C += 1 elif text == 'C-': self.set_C -= 1 quisk-3.6.11/n2adr/quisk_widgets.py0000666000175000017500000000413512132605626016572 0ustar jimjim00000000000000# Please do not change this widgets module for Quisk. Instead copy # it to your own quisk_widgets.py and make changes there. # # This module is used to add extra widgets to the QUISK screen. from __future__ import print_function import wx, time import _quisk as QS class BottomWidgets: # Add extra widgets to the bottom of the screen def __init__(self, app, hardware, conf, frame, gbs, vertBox): self.config = conf self.hardware = hardware self.application = app row = 4 # The next available row b = app.QuiskCycleCheckbutton(frame, self.OnAntTuner, ('Antenna', 'Ant 0', 'Ant 1')) bw, bh = b.GetMinSize() gbs.Add(b, (row, 0), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, self.OnAntTuner, 'L+') b.Enable(0) gbs.Add(b, (row, 2), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, self.OnAntTuner, 'L-') b.Enable(0) gbs.Add(b, (row, 4), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, self.OnAntTuner, 'C+') b.Enable(0) gbs.Add(b, (row, 6), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, self.OnAntTuner, 'C-') b.Enable(0) gbs.Add(b, (row, 8), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, self.OnAntTuner, 'Save') b.Enable(0) gbs.Add(b, (row, 10), (1, 2), flag=wx.EXPAND) self.swr_label = app.QuiskText(frame, 'Watts 000 SWR 10.1 Zh Ind 22 Cap 33 Freq 28100 (7777)', bh) gbs.Add(self.swr_label, (row, 15), (1, 10), flag=wx.EXPAND) b = app.QuiskCheckbutton(frame, None, text='') gbs.Add(b, (row, 25), (1, 2), flag=wx.EXPAND) # Example of a horizontal slider: # lab = wx.StaticText(frame, -1, 'Preamp', style=wx.ALIGN_CENTER) # gbs.Add(lab, (5,0), flag=wx.EXPAND) # sl = wx.Slider(frame, -1, 1024, 0, 2048) # parent, -1, initial, min, max # gbs.Add(sl, (5,1), (1, 5), flag=wx.EXPAND) # sl.Bind(wx.EVT_SCROLL, self.OnPreamp) # def OnPreamp(self, event): # print event.GetPosition() def OnAntTuner(self, event): btn = event.GetEventObject() text = btn.GetLabel() self.hardware.OnAntTuner(text) def UpdateText(self, text): self.swr_label.SetLabel(text) quisk-3.6.11/n2adr/conf3.py0000666000175000017500000000264712147211225014720 0ustar jimjim00000000000000# This is a config file to test the microphone by playing microphone # sound instead of radio sound. # The PTT button must be pressed, and the tune must be at zero. import sys from quisk_hardware_model import Hardware as BaseHardware import _quisk as QS if sys.platform == "win32": name_of_sound_capt = "Primary" name_of_sound_play = '' microphone_name = "Microphone" name_of_mic_play = "Primary" latency_millisecs = 150 data_poll_usec = 10000 elif 1: name_of_sound_capt = 'portaudio:Analog' name_of_sound_play = '' microphone_name = "portaudio:AK5370" name_of_mic_play = 'portaudio:CODEC USB' latency_millisecs = 150 data_poll_usec = 5000 else: name_of_sound_capt = 'alsa:CODEC USB' name_of_sound_play = '' microphone_name = "alsa:AK5370" name_of_mic_play = 'alsa:CODEC USB' latency_millisecs = 50 data_poll_usec = 5000 add_fdx_button = 1 sample_rate = 48000 mic_playback_rate = 48000 mic_sample_rate = 48000 mic_out_volume = 0.7 mic_clip = 3.0 mic_preemphasis = 0.6 if microphone_name: mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] class Hardware(BaseHardware): def OnButtonPTT(self, event): if event.GetEventObject().GetValue(): QS.set_key_down(1) else: QS.set_key_down(0) quisk-3.6.11/n2adr/quisk_conf_8600.py0000666000175000017500000001617512133543241016530 0ustar jimjim00000000000000# These are the configuration parameters for receiving the # 10.7 MHz IF output of the AOR AR8600 receiver with my # transceiver. This results in a 100 kHz to 3 GHz # wide range receiver with pan adapter. # # Due to noise starting at 11.18 MHz when tuned to 449.0 MHz, we tune to 10.5 MHz center. # # Note: The AR8600 IF output in WFM mode seems to tune in 10kHz increments # no matter what the step size, even though the display reads a # different frequency. # The AR8600 inverts the spectrum of these bands: 10, 2, 220, 440, 900 # The AR8600 does not invert these bands: 1240 # The change from inverted to non-inverted is about 1040 MHz. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. import time, traceback, os import _quisk as QS import serial # From the pyserial package from n2adr.quisk_conf import * from n2adr import scanner_widgets as quisk_widgets bandLabels = [ ('60',) * 5, '40', '20', '15', '12', '10', '2', '220', '440', '900', '1240', ('Time',) * len(bandTime)] # Define the Hardware class in this config file instead of a separate file. from hiqsdr.quisk_hardware import Hardware as BaseHardware class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.ar8600_frequency = 0 # current AR8600 tuning frequency self.hware_frequency = 0 # current hardware VFO frequency self.vfo_frequency = 0 # current Quisk VFO frequency self.invert = 1 # The frequency spectrum is backwards self.serial = None # the open serial port self.timer = 0.02 # time between AR8600 commands in seconds self.time0 = 0 # time of last AR8600 command self.serial_out = [] # send commands slowly self.offset = 10700000 # frequency offset from AR8600 tuning freq to IF output self.tx_freq = 0 # current frequency conf.BandEdge['220'] = (222000000, 225000000) conf.BandEdge['440'] = (420000000, 450000000) conf.BandEdge['900'] = (902000000, 928000000) conf.BandEdge['1240'] = (1240000000, 1300000000) rpt_file = os.path.normpath(os.path.join(os.getcwd(), '..')) rpt_file = os.path.join(rpt_file, 'MetroCor.txt') fp = open(rpt_file, 'r') self.repeaters = {} for line in fp: line = line.strip() if line and line[0] != '#': line = line.split('\t') fout = int(float(line[0]) * 1000000 + 0.1) text = "%s %s, %s" % (line[2], line[3], line[5]) if fout in self.repeaters: self.repeaters[fout] = "%s ; %s" % (self.repeaters[fout], text) else: self.repeaters[fout] = text fp.close() rpt_file = os.path.normpath(os.path.join(os.getcwd(), '..')) rpt_file = os.path.join(rpt_file, 'ARCC.csv') fp = open(rpt_file, 'r') for line in fp: line = line.strip() if line and line[0] != '#': line = line.split(',') fout = float(line[3]) if fout >= 2000.0: continue fout = int(fout * 1000000 + 0.1) text = "%s %s, %s" % (line[5], line[2], line[0]) if fout in self.repeaters: self.repeaters[fout] = "%s ; %s" % (self.repeaters[fout], text) else: self.repeaters[fout] = text fp.close() rpt_file = os.path.normpath(os.path.join(os.getcwd(), '..')) rpt_file = os.path.join(rpt_file, 'Repeaters.csv') fp = open(rpt_file, 'r') for line in fp: line = line.strip() if line and line[0] != '#': line = line.split(',') fout = float(line[3]) if fout >= 2000.0: continue fout = int(fout * 1000000 + 0.1) if line[0]: text = "%s %s, %s" % (line[5], line[2], line[0]) else: text = line[5] if fout in self.repeaters: self.repeaters[fout] = "%s ; %s" % (self.repeaters[fout], text) else: self.repeaters[fout] = text fp.close() for freq, text in self.repeaters.items(): if len(text) > 80: t ='' stations = text.split(';') for s in stations: s = s.strip() t = t + s.split()[0] + ' ' + s.split(',')[1] + '; ' self.repeaters[freq] = t self.rpt_freq_list = self.repeaters.keys() self.rpt_freq_list.sort() def OpenPort(self): if sys.platform == "win32": tty_list = ("COM7", "COM8") else: tty_list = ("/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2") for tty_name in tty_list: try: port = serial.Serial(port=tty_name, baudrate=9600, stopbits=serial.STOPBITS_TWO, xonxoff=1, timeout=0) except: #traceback.print_exc() pass else: time.sleep(0.1) for i in range(3): port.write('VR\r') time.sleep(0.1) chars = port.read(1024) if "VR0101" in chars: self.serial = port port.write('MD0\r') # set WFM mode so the IF output is available break if self.serial: break else: port.close() def open(self): self.OpenPort() QS.invert_spectrum(self.invert) t = BaseHardware.open(self) # save the message return t def close(self): BaseHardware.close(self) if self.serial: self.serial.write('EX\r') time.sleep(1) # wait for output to drain, but don't block self.serial.close() self.serial = None def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None): self.tx_freq = tx_freq try: rpt = self.repeaters[tx_freq] except KeyError: self.application.bottom_widgets.UpdateText('') else: self.application.bottom_widgets.UpdateText(rpt) if vfo_freq != self.vfo_frequency and vfo_freq >= 10000: self.vfo_frequency = vfo_freq # Calculate new AR8600 and hardware frequencies ar8600 = (vfo_freq + 50000) / 100000 * 100000 - 200000 if self.ar8600_frequency != ar8600: self.ar8600_frequency = ar8600 self.SendAR8600('RF%010d\r' % ar8600) if ar8600 < 1040000000: self.invert = 1 else: self.invert = 0 QS.invert_spectrum(self.invert) if self.invert: hware = self.offset - vfo_freq + self.ar8600_frequency else: hware = self.offset + vfo_freq - self.ar8600_frequency if self.hware_frequency != hware: self.hware_frequency = hware BaseHardware.ChangeFrequency(self, 0, hware) #print 'AR8600 Hware', self.ar8600_frequency, self.hware_frequency return tx_freq, vfo_freq def SendAR8600(self, msg): # Send commands to the AR8600, but not too fast if self.serial: if time.time() - self.time0 > self.timer: self.serial.write(msg) # send message now self.time0 = time.time() else: self.serial_out.append(msg) # send message later def HeartBeat(self): # Called at about 10 Hz by the main BaseHardware.HeartBeat(self) if self.serial: chars = self.serial.read(1024) #if chars: # print chars if self.serial_out and time.time() - self.time0 > self.timer: self.serial.write(self.serial_out[0]) self.time0 = time.time() del self.serial_out[0] quisk-3.6.11/n2adr/conf6.py0000664000175000017500000000177612150134362014723 0ustar jimjim00000000000000# This is a second config file to test the softrock radios. import sys if sys.platform == "win32": name_of_sound_capt = "Primary" name_of_sound_play = 'Primary' latency_millisecs = 150 data_poll_usec = 20000 else: name_of_sound_capt = 'alsa:ALC888-VD' name_of_sound_play = 'alsa:CODEC USB' latency_millisecs = 150 data_poll_usec = 5000 mic_clip = 3.0 mic_preemphasis = 0.6 default_screen = 'WFall' waterfall_y_scale = 80 waterfall_y_zero = 40 waterfall_graph_y_scale = 40 waterfall_graph_y_zero = 90 waterfall_graph_size = 160 display_fraction = 1.00 sample_rate = 96000 playback_rate = 48000 # Microphone capture: microphone_name = "alsa:AK5370" name_of_mic_play = name_of_sound_capt mic_playback_rate = sample_rate mic_out_volume = 0.6 if microphone_name: mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] quisk-3.6.11/n2adr/old_hardware.py0000644000175000017500000006223012124355212016331 0ustar jimjim00000000000000# This is the hardware module used at my shack. It is a complicated module # that controls various hardware. The files to control my 2010 transceiver # and for the improved version HiQSDR are in the package directory HiQSDR. from __future__ import print_function import sys, struct, math, socket, select, thread, time import _quisk as QS DEBUG = 0 from quisk_hardware_model import Hardware as BaseHardware UseSdriq = None UseRxudp = None Application = None Config = None # This hardware file controls my station. There are several # possible transmitters and receivers that can be selected. class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) global UseSdriq, UseRxudp, Application, Config Application = app Config = conf UseSdriq = conf.use_sdriq UseRxudp = conf.use_rx_udp self.use_sidetone = 1 self.vfo_frequency = 0 # current vfo frequency # Select receiver if conf.use_rx_udp: from hiqsdr import quisk_hardware as hw self.receiver = hw.Hardware(app, conf) self.rf_gain_labels = ('RF 0 dB', 'RF +16', 'RF -20', 'RF -10') elif UseSdriq: from sdriqpkg import quisk_hardware as quisk_hardware_sdriq self.receiver = quisk_hardware_sdriq.Hardware(app, conf) self.rf_gain_labels = self.receiver.rf_gain_labels else: self.receiver = HwRxEthVfo() self.rf_gain_labels = ('RF 0 dB', 'RF +16', 'RF -20', 'RF -10') # Select transmitter if conf.use_rx_udp: self.transmitter = self.receiver # this is a transceiver elif Config.tx_ip: self.transmitter = HwTx2007() else: self.transmitter = BaseHardware(app, conf) # Other hardware self.anttuner = AntennaTuner() # Control the antenna tuner self.lpfilter = LowPassFilter() # Control LP filter box self.hpfilter = HighPassFilter() # Control HP filter box #self.antenna = AntennaControl(self.AntCtrlAddress) # Control antenna def open(self): if self.transmitter is not self.receiver: self.transmitter.open() self.anttuner.open() return self.receiver.open() def close(self): if self.transmitter is not self.receiver: self.transmitter.close() self.anttuner.close() self.receiver.close() def ReturnFrequency(self): # Return the current tuning and VFO frequency return None, None # frequencies have not changed def ChangeFilterFrequency(self, tx_freq): # Change the filters but not the receiver; used for panadapter if tx_freq and tx_freq > 0: self.anttuner.SetTxFreq(tx_freq) self.lpfilter.SetTxFreq(tx_freq) self.hpfilter.SetTxFreq(tx_freq) #self.antenna.SetTxFreq(tx_freq) def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None): self.receiver.ChangeFrequency(tx_freq, vfo_freq, source, band, event) if self.transmitter is not self.receiver: self.transmitter.ChangeFrequency(tx_freq, vfo_freq, source, band, event) if tx_freq and tx_freq > 0: self.anttuner.SetTxFreq(tx_freq) self.lpfilter.SetTxFreq(tx_freq) self.hpfilter.SetTxFreq(tx_freq) #self.antenna.SetTxFreq(tx_freq) return tx_freq, vfo_freq def ChangeMode(self, mode): # mode is a string: "USB", "AM", etc. #if mode[0:3] == 'IMD': # QS.set_fdx(1) #else: # QS.set_fdx(0) self.receiver.ChangeMode(mode) self.transmitter.ChangeMode(mode) def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. self.receiver.ChangeBand(band) self.transmitter.ChangeBand(band) self.anttuner.ChangeBand(band) self.lpfilter.ChangeBand(band) self.hpfilter.ChangeBand(band) #self.antenna.ChangeBand(band) if band == '40': self.correct_smeter = 20.5 else: self.correct_smeter = 20.5 def HeartBeat(self): # Called at about 10 Hz by the main self.receiver.HeartBeat() if self.transmitter != self.receiver: self.transmitter.HeartBeat() self.anttuner.HeartBeat() self.lpfilter.HeartBeat() self.hpfilter.HeartBeat() #self.antenna.HeartBeat() def OnSpot(self, level): self.anttuner.OnSpot(level) if hasattr(self.transmitter, 'OnSpot'): self.transmitter.OnSpot(level) def OnButtonRfGain(self, event): if UseSdriq: self.receiver.OnButtonRfGain(event) else: if self.hpfilter: self.hpfilter.OnButtonRfGain(event) def GetFirmwareVersion(self): if UseRxudp: return self.receiver.firmware_version return 0 def VarDecimGetChoices(self): return self.receiver.VarDecimGetChoices() def VarDecimGetLabel(self): return self.receiver.VarDecimGetLabel() def VarDecimGetIndex(self): return self.receiver.VarDecimGetIndex() def VarDecimSet(self, index=None): return self.receiver.VarDecimSet(index) def SetVNA(self, key_down=None, freq=None): if hasattr(self.transmitter, 'SetVNA'): self.transmitter.SetVNA(key_down, freq) class HwTx2007: tx_program_port = 0x553A tx_dds_clock = 89999784.E0 def __init__(self): self.vfo_frequency = 0 self.tx_frequency = 0 self.mode = None self.thread_running = 0 self.want_prog_num = 0 self.got_ack = None # last received ACK number self.got_status = None # last received status self.thread_msg = '' def open(self): self.tx_program_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.tx_program_socket.setblocking(0) self.tx_program_socket.connect((Config.tx_ip, self.tx_program_port)) def close(self): self.tx_program_socket.close() def RequestStatus(self, wait=1): # Request status self.got_status = None while 1: # Get all status responses if not self.RecvTx(0.0): break if wait: # wait for a response self.got_status = None # Get the new status if self.SendTx('\001s') != 2: return # Failure self.RecvTx(0.500) if not self.got_status: self.RecvTx(0.500) if not self.got_status: return # Failure return 1 # Success else: if self.SendTx('\001s') == 2: return 1 # Success def RecvTx(self, seconds): # receive data, wait seconds (e.g. 0.400) s = self.tx_program_socket if not s: return '' try: r, w, x = select.select([s], [], [], seconds) except: return '' if r: try: data = s.recv(1024) except: return '' else: return '' if data: if data[0] == '\003' and len(data) >= 10 and data[1] == '\001': # got Status self.got_status = map(ord, data[2:]) elif data[0] == '\004': # got ACK self.got_ack = ord(data[1]) return data def SendTx(self, msg): s = self.tx_program_socket if not s: return 0 try: return s.send(msg) except: return 0 def ProgramTx(self, prog_num): # Send an FGPA program to the transmitter BLOCK_SIZE = 512 # data size s = self.tx_program_socket if not s: return 0 if sys.platform[0:3] == 'win': FILE1 = "C:/Documents and Settings/jim/My Documents/Altera/duc1cw/duc1cw.rbf" FILE2 = "C:/Documents and Settings/jim/My Documents/Altera/fpga2tone/fpga2tone.rbf" FILE3 = "C:/Documents and Settings/jim/My Documents/Altera/duc1/duc1.rbf" else: FILE1 = "/C/Documents and Settings/jim/My Documents/Altera/duc1cw/duc1cw.rbf" FILE2 = "/C/Documents and Settings/jim/My Documents/Altera/fpga2tone/fpga2tone.rbf" FILE3 = "/C/Documents and Settings/jim/My Documents/Altera/duc1/duc1.rbf" if prog_num == 0: # Remove FPGA program self.SendTx('\002p\000') self.SendTx('\003\001') return 1 elif prog_num == 1: fp = file(FILE1, "rb") elif prog_num == 2: fp = file(FILE2, "rb") elif prog_num == 3: fp = file(FILE3, "rb") else: return 0 block = 0 while 1: # Throw away any pending data if not self.RecvTx(0.0): break self.got_ack = None data = '\002p%c' % chr(prog_num) self.SendTx(data) # WRQ program number theend = 0 while 1: if self.want_prog_num != prog_num: # Change in program return 0 self.RecvTx(0.500) if self.got_ack != block: self.SendTx(data) self.RecvTx(0.500) if self.got_ack != block: fp.close() return 0 self.RecvTx(0.100) if theend: break block = (block + 1) % 256 data = '\003' + chr(block) + fp.read(BLOCK_SIZE) self.SendTx(data) # send DATA if len(data) < BLOCK_SIZE + 2: theend = 1 fp.close() # Success; send frequency if self.tx_frequency: self.ChangeFrequency(self.tx_frequency, self.vfo_frequency) return 1 def ChangeProgNum(self): # status[6] is the current program number. # status[7] is a flag field and 0x3 must be set to indicate successful programming. # prog_num zero means no program and then status[7] is irrelevant. try: for i in range(0, 5): if self.RequestStatus(): if self.got_status[6] == 0: self.thread_msg = 'Program number is zero' if self.want_prog_num == 0 and self.got_status[6] == 0: break # Success if self.want_prog_num == self.got_status[6] and self.got_status[7] & 0x3 == 0x3: break # Success self.ProgramTx(self.want_prog_num) # Re-program else: self.ProgramTx(0) return 1 # Failure finally: self.thread_running = 0 def ChangeFrequency(self, tx_freq, vfo_freq, source='', band='', event=None): self.vfo_frequency = vfo_freq if tx_freq and tx_freq > 0: self.tx_frequency = tx_freq # Make two frequencies. The first is the primary. delta1 = float(tx_freq) / self.tx_dds_clock * 4294967296 delta2 = (tx_freq + 1000.0) / self.tx_dds_clock * 4294967296 s = struct.pack("= 0 and self.set_HiLoZ >= 0 and ( # Check L and Hi/Lo relay self.param1[1] != self.set_L or self.param1[3] != self.set_HiLoZ): if self.set_HiLoZ: self.Write(chr(65) + chr(self.set_L + 128)) else: self.Write(chr(65) + chr(self.set_L)) elif self.param1[2] != self.set_C and self.set_C >= 0: # Set C self.Write(chr(66) + chr(self.set_C)) elif self.live_update: # If our window shows, request an update self.timer += 1 if self.timer > 20: self.timer = 0 self.Write(chr(40)) # Request ALLUPDATE def Write(self, s): # Write a command string to the AT-200PC if DEBUG: print ('Send', ord(s[0])) if self.serial: self.serial.setRTS(1) # Wake up the AT-200PC time.sleep(0.003) # Wait 3 milliseconds self.serial.write(s) self.serial.setRTS(0) def Read(self): # Receive characters from the AT-200PC chars = self.serial.read(1024) for ch in chars: if self.rx_state == 0: # Read first of 4 characters; must be decimal 165 if ord(ch) == 165: self.rx_state = 1 elif self.rx_state == 1: # Read second byte self.rx_state = 2 self.rx_byte1 = ord(ch) elif self.rx_state == 2: # Read third byte self.rx_state = 3 self.rx_byte2 = ord(ch) elif self.rx_state == 3: # Read fourth byte self.rx_state = 0 byte3 = ord(ch) byte1 = self.rx_byte1 byte2 = self.rx_byte2 if DEBUG: print ('Received', byte1, byte2, byte3) if byte1 > 19: # Impossible command value continue if byte1 == 1 and self.set_L < 0: # reported inductor value self.set_L = byte2 if byte1 == 2 and self.set_C < 0: # reported capacitor value self.set_C = byte2 if byte1 == 3 and self.set_HiLoZ < 0: # reported Hi/Lo relay self.set_HiLoZ = byte2 if byte1 == 13: # Start standby self.is_standby = 1 elif byte1 == 14: # Start active self.is_standby = 0 self.param1[byte1] = byte2 self.param2[byte1] = byte3 def open(self): # TunerLC is a list of (freq, L, C). Use -L for Low Z, +L for High Z. if not hasattr(Application, 'TunerLC'): Application.TunerLC = [(0, 0, 0), (4900000, 0, 0), (6000000, 0, 0), (99999999, 0, 0)] def close(self): if self.serial: self.serial.close() self.serial = None def xxReqSetFreq(self, tx_freq): # Set relays for this frequency. The frequency must exist in the tuner. if self.serial and not self.standby and tx_freq > 1500000: ticks = int(20480.0 / tx_freq * 1e6 + 0.5) self.Write(chr(67) + chr((ticks & 0xFF00) >> 8) + chr(ticks & 0xFF)) def SetTxFreq(self, tx_freq): if tx_freq is None: self.set_C = 0 self.set_L = 0 self.set_HiLoZ = 0 return self.tx_freq = tx_freq if abs(self.old_tx_freq - tx_freq) < 20000: return # Ignore small tuning changes self.old_tx_freq = tx_freq i1 = 0 i2 = len(Application.TunerLC) - 1 while 1: # binary partition i = (i1 + i2) / 2 if Application.TunerLC[i][0] < tx_freq: i1 = i else: i2 = i if i2 - i1 <= 1: break # The correct setting is between i1 and i2; interpolate F1 = Application.TunerLC[i1][0] F2 = Application.TunerLC[i2][0] L1 = Application.TunerLC[i1][1] L2 = Application.TunerLC[i2][1] C1 = Application.TunerLC[i1][2] C2 = Application.TunerLC[i2][2] frac = (float(tx_freq) - F1) / (F2 - F1) C = C1 + (C2 - C1) * frac self.set_C = int(C + 0.5) L = L1 + (L2 - L1) * frac if L < 0: L = -L self.set_HiLoZ = 1 else: self.set_HiLoZ = 0 self.set_L = int(L + 0.5) def ChangeBand(self, band): pass ##self.ReqSetFreq(self.tx_freq) def OnSpot(self, level): # level 0 == OFF, else the level 10 to 1000 if self.serial: if level == 0: self.live_update = 0 elif not self.live_update: self.live_update = 1 self.timer = 999 def OnAntTuner(self, event): # A button was pressed #for t in Application.TunerLC: # print t if self.serial: btn = event.GetEventObject() text = btn.GetLabel() if text == 'Tune': if not self.standby: #self.Write(chr(5)) # Request memory tune self.Write(chr(6)) # Request full tune self.set_C = -9 self.set_L = -9 self.set_HiLoZ = -9 elif text == 'Save': self.Write(chr(46)) if self.set_HiLoZ == 0: # High Z L = self.set_L else: # Low Z L = -self.set_L for i in range(len(Application.TunerLC)): # Record new freq and L/C if abs(Application.TunerLC[i][0] - self.tx_freq) < 1000: Application.TunerLC[i] = (self.tx_freq, L, self.set_C) break else: Application.TunerLC.append((self.tx_freq, L, self.set_C)) Application.TunerLC.sort() elif text == 'L+': self.set_L += 1 elif text == 'L-': self.set_L -= 1 elif text == 'C+': self.set_C += 1 elif text == 'C-': self.set_C -= 1 quisk-3.6.11/n2adr/__init__.py0000644000175000017500000000000211632372224015427 0ustar jimjim00000000000000# quisk-3.6.11/n2adr/old_conf.py0000644000175000017500000000627511643315036015475 0ustar jimjim00000000000000# This is the config file from my shack, which controls various hardware. It is # a complicated file. The files to control my 2010 transceiver # and for the improved version HiQSDR are in the package directory HiQSDR. import sys #dev = 'SoftRock' #dev = 'SoftRockTx' dev = 'Transceiver' #dev = 'SDR-IQ' #dev = 'SoundCard' if sys.platform == "win32": name_of_sound_capt = "Primary" name_of_sound_play = 'Primary' microphone_name = "AK5370" latency_millisecs = 150 data_poll_usec = 20000 else: name_of_sound_capt = 'hw:0' #'alsa:Audiophile' name_of_sound_play = 'hw:0' #"alsa:USB Audio CODEC" microphone_name = "alsa:AK5370" latency_millisecs = 50 data_poll_usec = 5000 mic_clip = 3.0 # 3.0 mic_preemphasis = 0.6 # 0.6 playback_rate = 48000 default_screen = 'WFall' waterfall_y_scale = 80 waterfall_y_zero = 40 waterfall_graph_y_scale = 40 waterfall_graph_y_zero = 90 waterfall_graph_size = 160 add_imd_button = 1 add_fdx_button = 1 if dev[0:8] == 'SoftRock': from softrock import hardware_usb as quisk_hardware usb_vendor_id = 0x16c0 usb_product_id = 0x05dc softrock_model = "RxEnsemble2" sample_rate = 48000 # ADC hardware sample rate in Hertz if dev == 'SoftRockTx': from softrock import widgets_tx as quisk_widgets softrock_model = "RxTxEnsemble" name_of_mic_play = name_of_sound_capt mic_playback_rate = sample_rate mic_out_volume = 0.6 # Test transmit audio # name_of_mic_play = name_of_sound_play # mic_playback_rate = playback_rate # name_of_sound_play = "" else: microphone_name = "" if dev == 'Transceiver': from n2adr import quisk_hardware from n2adr import quisk_widgets use_rx_udp = 1 # Get ADC samples from UDP rx_udp_ip = "192.168.2.196" # Sample source IP address rx_udp_port = 0xBC77 # Sample source UDP port rx_udp_clock = 122880000 # ADC sample rate in Hertz rx_udp_decimation = 8 * 8 * 8 # Decimation from clock to UDP sample rate sample_rate = int(float(rx_udp_clock) / rx_udp_decimation + 0.5) # Don't change this name_of_sound_capt = "" # We do not capture from the soundcard data_poll_usec = 10000 playback_rate = 48000 display_fraction = 0.96 tx_ip = "192.168.2.196" tx_audio_port = 0xBC79 mic_out_volume = 1.0 if dev == 'SDR-IQ': use_sdriq = 1 # Use the SDR-IQ sdriq_name = "/dev/ft2450" # Name of the SDR-IQ device to open sdriq_clock = 66666667.0 # actual sample rate (66666667 nominal) sdriq_decimation = 600 # Must be 360, 500, 600, or 1250 sample_rate = int(float(sdriq_clock) / sdriq_decimation + 0.5) # Don't change this name_of_sound_capt = "" # We do not capture from the soundcard display_fraction = 0.85 microphone_name = "" if dev == 'SoundCard': from n2adr import quisk_hardware from n2adr import quisk_widgets sample_rate = 48000 playback_rate = 48000 microphone_name = "" ## SSB exciter # tx_ip = "192.168.2.195" # key_method = "192.168.2.195" # Use UDP from this address # tx_audio_port = 0x553B # mic_out_volume = 0.6772 if microphone_name: mixer_settings = [ (microphone_name, 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; (microphone_name, 1, 1.0) # numid of capture on/off control, turn on with 1.0; ] quisk-3.6.11/n2adr/startup.py0000666000175000017500000000527012147212034015404 0ustar jimjim00000000000000#! /usr/bin/python # All QUISK software is Copyright (C) 2006-2011 by James C. Ahlstrom. # This free software is licensed for use under the GNU General Public # License (GPL), see http://www.opensource.org. # Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!! "Select the desired hardware, and start Quisk" import sys, wx, subprocess, os Choices = [ (' My Transceiver', 'n2adr/quisk_conf.py', ''), (' Softrock Rx Ensemble', 'softrock/conf_rx_ensemble2.py', 'n2adr/conf2.py'), (' Softrock Rx/Tx Ensemble', 'softrock/conf_rx_tx_ensemble.py', 'n2adr/conf6.py'), (' Plain Sound Card, Rx only', 'n2adr/conf2.py', ''), (' Test microphone sound', 'n2adr/conf3.py', ''), (' SDR-IQ, receive only, antenna to RF input', 'quisk_conf_sdriq.py', 'n2adr/conf2.py'), (' AOR AR8600 with IF to my hardware', 'n2adr/quisk_conf_8600.py', ''), (' AOR AR8600 with IF to SDR-IQ', 'quisk_conf_sdr8600.py', 'n2adr/conf2.py'), (' Fldigi with my transceiver', 'n2adr/quisk_conf.py', 'n2adr/conf5.py'), ] if sys.platform == 'win32': os.chdir('C:\\pub\\quisk') exe = "C:\\python27\\pythonw.exe" else: os.chdir('/home/jim/pub/quisk') exe = "/usr/bin/python" class ListBoxFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, 'Select Hardware') font = wx.Font(14, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL) self.SetFont(font) charx = self.GetCharWidth() chary = self.GetCharHeight() width = 0 height = chary * 2 tlist = [] for txt, conf1, conf2 in Choices: text = "%s, %s" % (txt, conf1) if conf2: text = "%s, %s" % (text, conf2) tlist.append(text) w, h = self.GetTextExtent(text) width = max(width, w) height += h width += 3 * chary lb = wx.ListBox(self, -1, (0, 0), (width, height), tlist, wx.LB_SINGLE) lb.SetSelection(0) lb.SetFont(font) lb.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClick, lb) lb.Bind(wx.EVT_KEY_DOWN, self.OnChar) self.SetClientSize((width, height)) def OnDClick(self, event): lb = event.GetEventObject() index = lb.GetSelection() text, conf1, conf2 = Choices[index] cmd = [exe, 'quisk.py', '-c', conf1] if conf2: cmd = cmd + ['--config2', conf2] subprocess.Popen(cmd) self.Destroy() def OnChar(self, event): if event.GetKeyCode() == 13: self.OnDClick(event) else: event.Skip() class App(wx.App): def __init__(self): if sys.stdout.isatty(): wx.App.__init__(self, redirect=False) else: wx.App.__init__(self, redirect=True) def OnInit(self): frame = ListBoxFrame() frame.Show() return True app = App() app.MainLoop() quisk-3.6.11/n2adr/scanner_widgets.py0000664000175000017500000001232412132573742017067 0ustar jimjim00000000000000# Please do not change this widgets module for Quisk. Instead copy # it to your own quisk_widgets.py and make changes there. # # This module is used to add extra widgets to the QUISK screen. from __future__ import print_function import wx, time import _quisk as QS class BottomWidgets: # Add extra widgets to the bottom of the screen def __init__(self, app, hardware, conf, frame, gbs, vertBox): self.config = conf self.hardware = hardware self.application = app row = 4 # The next available row b = app.QuiskPushbutton(frame, None, 'Tune') bw, bh = b.GetMinSize() b.Enable(0) gbs.Add(b, (row, 0), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, None, '') gbs.Add(b, (row, 2), (1, 2), flag=wx.EXPAND) b = app.QuiskPushbutton(frame, None, '') gbs.Add(b, (row, 4), (1, 2), flag=wx.EXPAND) b = self.btnScanner = app.QuiskCheckbutton(frame, self.OnBtnScanner, text='Scanner', use_right=True) self.scan_timer = wx.Timer(b) # timed events for the scanner b.Bind(wx.EVT_TIMER, self.OnTimerEvent) gbs.Add(b, (row, 6), (1, 2), flag=wx.EXPAND) b = self.btnNext = app.QuiskPushbutton(frame, self.OnBtnNext, 'Next', True) gbs.Add(b, (row, 8), (1, 2), flag=wx.EXPAND) b = app.QuiskCheckbutton(frame, self.OnBtnRptr, text='Rptr') b.SetValue(True, True) gbs.Add(b, (row, 10), (1, 2), flag=wx.EXPAND) self.swr_label = app.QuiskText(frame, 'Watts 000 SWR 10.1 Zh Ind 22 Cap 33 Freq 28100 (7777)', bh) gbs.Add(self.swr_label, (row, 15), (1, 12), flag=wx.EXPAND) # Example of a horizontal slider: # lab = wx.StaticText(frame, -1, 'Preamp', style=wx.ALIGN_CENTER) # gbs.Add(lab, (5,0), flag=wx.EXPAND) # sl = wx.Slider(frame, -1, 1024, 0, 2048) # parent, -1, initial, min, max # gbs.Add(sl, (5,1), (1, 5), flag=wx.EXPAND) # sl.Bind(wx.EVT_SCROLL, self.OnPreamp) # def OnPreamp(self, event): # print event.GetPosition() def UpdateText(self, text): self.swr_label.SetLabel(text) def OnBtnRptr(self, event): btn = event.GetEventObject() if btn.GetValue(): self.config.freq_spacing = 5000 else: self.config.freq_spacing = 0 def OnBtnNext(self, event): self.direction = self.btnNext.direction # +1 for left -> go up; -1 for down self.keep_going = wx.GetKeyState(wx.WXK_SHIFT) # if Shift is down, move to next band self.scanner = False if self.keep_going: if not self.ScanScreen(event): self.MoveVfo(event) self.scan_timer.Start(500) else: self.ScanScreen(event) def ScanScreen(self, event): # Look for signals on the current screen lst = self.hardware.rpt_freq_list app = self.application vfo = app.VFO tx_freq = vfo + app.txFreq sample_rate = app.sample_rate limit = int(sample_rate / 2.0 * self.config.display_fraction * 0.95) # edge of screen self.scan_n1 = None self.scan_n = None for n in range(len(lst)): if lst[n] > vfo - limit and self.scan_n1 is None: self.scan_n1 = n # inclusive if lst[n] >= tx_freq and self.scan_n is None: self.scan_n = n if lst[n] > vfo + limit: break self.scan_n2 = n # inclusive if self.scan_n is None: self.scan_n = self.scan_n1 if self.direction > 0: # left click; go up seq = range(self.scan_n + 1, self.scan_n2 + 1) if not self.keep_going: seq += range(self.scan_n1, self.scan_n) else: # right click; go down seq = range(self.scan_n - 1, self.scan_n1 - 1, -1) if not self.keep_going: seq += range(self.scan_n2, self.scan_n, -1) for n in seq: freq = lst[n] if not QS.get_squelch(freq - vfo): app.ChangeHwFrequency(freq - vfo, vfo, 'Repeater', event) return True # frequency was changed return False # frequency was not changed def MoveVfo(self, event): # Move the VFO to look for further signals lst = self.hardware.rpt_freq_list app = self.application vfo = app.VFO tx_freq = vfo + app.txFreq sample_rate = app.sample_rate if self.direction > 0: # left click; go up n = self.scan_n2 + 1 if n >= len(lst): n = 0 freq = lst[n] vfo = freq + sample_rate * 4 / 10 app.ChangeHwFrequency(freq - vfo, vfo, 'Repeater', event) else: # right click; go down n = self.scan_n1 - 1 if n < 0: n = len(lst) - 1 freq = lst[n] vfo = freq - sample_rate * 4 / 10 app.ChangeHwFrequency(freq - vfo, vfo, 'Repeater', event) def OnBtnScanner(self, event): self.direction = self.btnScanner.direction # +1 for left -> go up; -1 for down self.keep_going = wx.GetKeyState(wx.WXK_SHIFT) # if Shift is down, move to next band self.scanner = True if self.btnScanner.GetValue(): self.btnNext.Enable(0) if self.keep_going: if not self.ScanScreen(event): self.MoveVfo(event) else: self.ScanScreen(event) self.scan_timer.Start(500) else: self.btnNext.Enable(1) self.scan_timer.Stop() def OnTimerEvent(self, event): if QS.get_squelch(self.application.txFreq): if self.keep_going: if not self.ScanScreen(event): self.MoveVfo(event) else: self.ScanScreen(event) elif not self.scanner: self.scan_timer.Stop() quisk-3.6.11/filter.h0000666000175000017500000000557212122662252013771 0ustar jimjim00000000000000struct quisk_cFilter { double * dCoefs; // filter coefficients complex * cpxCoefs; // make the complex coefficients from dCoefs int nBuf; // dimension of cBuf int nTaps; // dimension of dSamples, cSamples, dCoefs and cpxCoefs int counter; // used to count samples for decimation complex * cSamples; // storage for old samples complex * ptcSamp; // next available position in cSamples complex * cBuf; // auxillary buffer for interpolation } ; struct quisk_dFilter { double * dCoefs; // filter coefficients complex * cpxCoefs; // make the complex coefficients from dCoefs int nBuf; // dimension of dBuf int nTaps; // dimension of dSamples, cSamples, dCoefs and cpxCoefs int counter; // used to count samples for decimation double * dSamples; // storage for old samples double * ptdSamp; // next available position in dSamples double * dBuf; // auxillary buffer for interpolation } ; struct quisk_cHB45Filter { // Complex half band decimate by 2 filter with 45 coefficients complex * cBuf; // auxillary buffer for interpolation int nBuf; // dimension of cBuf int toggle; complex samples[22]; complex center[11]; } ; struct quisk_dHB45Filter { // Real half band decimate by 2 filter with 45 coefficients double * dBuf; // auxillary buffer for interpolation int nBuf; // dimension of dBuf int toggle; double samples[22]; double center[11]; } ; void quisk_filt_cInit(struct quisk_cFilter *, double *, int); void quisk_filt_dInit(struct quisk_dFilter *, double *, int); void quisk_filt_tune(struct quisk_dFilter *, double, int); complex quisk_dC_out(double, struct quisk_dFilter *); int quisk_cInterpolate(complex *, int, struct quisk_cFilter *, int); int quisk_dInterpolate(double *, int, struct quisk_dFilter *, int); int quisk_cDecimate(complex *, int, struct quisk_cFilter *, int); int quisk_dDecimate(double *, int, struct quisk_dFilter *, int); int quisk_cDecim2HB45(complex *, int, struct quisk_cHB45Filter *); int quisk_dInterp2HB45(double *, int, struct quisk_dHB45Filter *); int quisk_cInterp2HB45(complex *, int, struct quisk_cHB45Filter *); int quisk_dFilter(double *, int, struct quisk_dFilter *); extern double quiskMicFilt48Coefs[325]; extern double quiskMicFilt8Coefs[93]; extern double quiskLpFilt48Coefs[144]; extern double quiskFilt12_19Coefs[64]; extern double quiskFilt185D3Coefs[188]; extern double quiskFilt133D2Coefs[136]; extern double quiskFilt167D3Coefs[173]; extern double quiskFilt111D2Coefs[114]; extern double quiskFilt53D1Coefs[55]; extern double quiskFilt240D5Coefs[114]; extern double quiskFilt240D5CoefsSharp[246]; extern double quiskFilt48dec24Coefs[98]; extern double quiskAudio24p6Coefs[36]; extern double quiskAudio48p6Coefs[71]; extern double quiskAudio96Coefs[11]; extern double quiskAudio24p4Coefs[47]; extern double quiskAudioFmHpCoefs[309]; extern double quiskAudio24p3Coefs[93]; quisk-3.6.11/charleston/0000775000175000017500000000000012164330433014461 5ustar jimjim00000000000000quisk-3.6.11/charleston/__init__.py0000644000175000017500000000000211632372222016561 0ustar jimjim00000000000000# quisk-3.6.11/windows.txt0000644000175000017500000000140511632372222014551 0ustar jimjim00000000000000Windows USB Driver ================== You don't need to install a USB driver unless your hardware is controlled by USB. If you have recent SoftRock hardware controlled by USB, you must install a USB driver. Quisk uses the same driver as other SoftRock programs, namely the PE0FKO driver package. This driver is based on libusb-win32, which in turn is based on libusb-0.1. http://home.ict.nl/~fredkrom/pe0fko/SR-V9-Si570/#install A newer version of libusb called libusb-1.0 will soon be available, and the SoftRock community may start using the newer software and a newer driver. Quisk will always follow any changes the SoftRock community makes, so just install whatever libusb driver is most current. If it doesn't work with Quisk, I will fix Quisk. quisk-3.6.11/quisk_conf_model.py0000644000175000017500000000176111632372224016220 0ustar jimjim00000000000000# This is a sample quisk_conf.py configuration file for a soundcard. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. # The default hardware module was already imported. Import a different one here. # import quisk_hardware_fixed as quisk_hardware # In ALSA, soundcards have these names. The "hw" devices are the raw # hardware devices, and should be used for soundcard capture. #name_of_sound_capt = "hw:0" #name_of_sound_capt = "hw:1" #name_of_sound_capt = "plughw" #name_of_sound_capt = "plughw:1" #name_of_sound_capt = "default" sample_rate = 96000 # ADC hardware sample rate in Hertz name_of_sound_capt = "hw:0" # Name of soundcard capture hardware device. name_of_sound_play = name_of_sound_capt # Use the same device for play back channel_i = 0 # Soundcard index of in-phase channel: 0, 1, 2, ... channel_q = 1 # Soundcard index of quadrature channel: 0, 1, 2, ... quisk-3.6.11/quisk_hardware_fixed.py0000644000175000017500000000175311632372222017066 0ustar jimjim00000000000000# Please do not change this hardware control module for Quisk. # This hardware module is for receivers with a fixed VFO, such as # the SoftRock. Change your VFO frequency below. # If you want to use this hardware module, specify it in quisk_conf.py. # import quisk_hardware_fixed as quisk_hardware # See quisk_hardware_model.py for documentation. from quisk_hardware_model import Hardware as BaseHardware class Hardware(BaseHardware): def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.vfo = self.conf.fixed_vfo_freq # Fixed VFO frequency in Hertz self.tune = self.vfo + 10000 # Current tuning frequency in Hertz def ChangeFrequency(self, tune, vfo, source='', band='', event=None): # Change and return the tuning and VFO frequency. See quisk_hardware_model.py. self.tune = tune return tune, self.vfo def ReturnFrequency(self): # Return the current tuning and VFO frequency. See quisk_hardware_model.py. return self.tune, self.vfo quisk-3.6.11/softrock/0000775000175000017500000000000012164330433014151 5ustar jimjim00000000000000quisk-3.6.11/softrock/hardware_usb.py0000644000175000017500000002102412150203021017151 0ustar jimjim00000000000000# Please do not change this hardware control module for Quisk. # It provides USB control of SoftRock hardware. from __future__ import print_function import struct, threading, time, traceback, math from quisk_hardware_model import Hardware as BaseHardware import _quisk as QS # All USB access is through control transfers using pyusb. # byte_array = dev.ctrl_transfer (IN, bmRequest, wValue, wIndex, length, timout) # len(string_msg) = dev.ctrl_transfer (OUT, bmRequest, wValue, wIndex, string_msg, timout) import usb.core, usb.util DEBUG = 0 # I2C-address of the SI570; Thanks to Joachim Schneider, DB6QS si570_i2c_address = 0x55 # Thanks to Ethan Blanton, KB8OJH, for this patch for the Si570 (many SoftRocks): # These are used by SetFreqByDirect(); see below. # The Si570 DCO must be clamped between these values SI570_MIN_DCO = 4.85e9 SI570_MAX_DCO = 5.67e9 # The Si570 has 6 valid HSDIV values. Subtract 4 from HSDIV before # stuffing it. We want to find the highest HSDIV first, so start # from 11. SI570_HSDIV_VALUES = [11, 9, 7, 6, 5, 4] IN = usb.util.build_request_type(usb.util.CTRL_IN, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) OUT = usb.util.build_request_type(usb.util.CTRL_OUT, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) UBYTE2 = struct.Struct(' 128: continue if dco < SI570_MIN_DCO or dco > SI570_MAX_DCO: # This really shouldn't happen continue if not dco_new or dco < dco_new: dco_new = dco hsdiv_new = hsdiv n1_new = n1 if not dco_new: # For some reason, we were unable to calculate a frequency. # Probably because the frequency requested is outside the range # of our device. return False # Failure rfreq = dco_new / self.conf.si570_xtal_freq rfreq_int = int(rfreq) rfreq_frac = int(round((rfreq - rfreq_int) * 2**28)) # It looks like the DG8SAQ protocol just passes r7-r12 straight # To the Si570 when given command 0x30. Easy enough. # n1 is stuffed as n1 - 1, hsdiv is stuffed as hsdiv - 4. hsdiv_new = hsdiv_new - 4 n1_new = n1_new - 1 s = struct.Struct('>BBL').pack((hsdiv_new << 5) + (n1_new >> 2), ((n1_new & 0x3) << 6) + (rfreq_int >> 4), ((rfreq_int & 0xf) << 28) + rfreq_frac) self.usb_dev.ctrl_transfer(OUT, 0x30, si570_i2c_address + 0x700, 0, s) return True # Success class KeyThread(threading.Thread): """Create a thread to monitor the key state.""" def __init__(self, dev, poll_secs): self.usb_dev = dev self.poll_secs = poll_secs self.ptt = 0 self.key_down = 0 threading.Thread.__init__(self) self.doQuit = threading.Event() self.doQuit.clear() def run(self): while not self.doQuit.isSet(): try: if self.ptt: key_down = 1 else: # read key state ret = self.usb_dev.ctrl_transfer(IN, 0x51, 0, 0, 1) # bit 0x20 is the tip, bit 0x02 is the ring if ret[0] & 0x20: # Tip: key is up key_down = 0 else: # key is down key_down = 1 if key_down != self.key_down: self.key_down = key_down self.usb_dev.ctrl_transfer(IN, 0x50, key_down, 0, 3) QS.set_key_down(key_down) except usb.core.USBError: QS.set_key_down(0) if DEBUG: traceback.print_exc() time.sleep(self.poll_secs) def stop(self): """Set a flag to indicate that the thread should end.""" self.doQuit.set() def OnPTT(self, ptt): self.ptt = ptt quisk-3.6.11/softrock/conf_rx_tx_ensemble.py0000644000175000017500000000354512150130774020554 0ustar jimjim00000000000000# This is a sample quisk_conf.py configuration file for a SoftRock Rx/Tx Ensemble. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. # Attach your SoftRock Rx/Tx Ensemble to the line in and line out of a high quality # sound card. Set name_of_sound_capt and name_of_mic_play to this card. You need # a second (lower quality) sound card to play radio audio named name_of_sound_play. # This is sufficient for CW. To transmit SSB, you need a capture sound card named # microphone_name. The microphone_name and name_of_sound_play can be the same device. from softrock import hardware_usb as quisk_hardware from softrock import widgets_tx as quisk_widgets # In Linux, ALSA soundcards have these names. The "hw" devices are the raw # hardware devices, and should be used for soundcard capture. #name_of_sound_capt = "hw:0" #name_of_sound_capt = "hw:1" #name_of_sound_capt = "plughw" #name_of_sound_capt = "plughw:1" #name_of_sound_capt = "default" # Vendor and product ID's for the SoftRock usb_vendor_id = 0x16c0 usb_product_id = 0x05dc softrock_model = "RxTxEnsemble" # If you want to monitor the hardware key state, enter a poll time in milliseconds. key_poll_msec = 0 #sample_rate = 96000 # ADC hardware sample rate in Hertz #name_of_sound_capt = "hw:0" # Name of soundcard capture hardware device. #name_of_sound_play = "" # Name of soundcard playback hardware device. # Microphone capture: #microphone_name = "hw:1" # Name of microphone capture device #name_of_mic_play = name_of_sound_capt # Name of play device if CW or mic I/Q is sent to a sound card #mic_playback_rate = sample_rate # Playback rate must be a multiple 1, 2, ... of mic_sample_rate #mic_out_volume = 0.6 # Transmit sound output volume (after all processing) as a fraction 0.0 to 1.0 quisk-3.6.11/softrock/widgets_tx.py0000644000175000017500000000102112146140631016673 0ustar jimjim00000000000000# Please do not change this widgets module for Quisk. Instead copy # it to your own quisk_widgets.py and make changes there. # # This module is used to add extra widgets to the QUISK screen. import wx import _quisk as QS import math class BottomWidgets: # Add extra widgets to the bottom of the screen def __init__(self, app, hardware, conf, frame, gbs, vertBox): self.hardware = hardware self.info_text = app.QuiskText(frame, 'Info', app.button_height) gbs.Add(self.info_text, (4, 0), (1, 14), flag=wx.EXPAND) quisk-3.6.11/softrock/conf_fixed.py0000644000175000017500000000210711632372230016625 0ustar jimjim00000000000000# This is a sample quisk_conf.py configuration file for a SoftRock or # other hardware with a fixed VFO frequency. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. import quisk_hardware_fixed as quisk_hardware # In ALSA, soundcards have these names. The "hw" devices are the raw # hardware devices, and should be used for soundcard capture. #name_of_sound_capt = "hw:0" #name_of_sound_capt = "hw:1" #name_of_sound_capt = "plughw" #name_of_sound_capt = "plughw:1" #name_of_sound_capt = "default" softrock_model = "fixed" # Fixed frequency SoftRock fixed_vfo_freq = 7056000 # This is the fixed VFO frequency in Hertz sample_rate = 96000 # ADC hardware sample rate in Hertz name_of_sound_capt = "hw:0" # Name of soundcard capture hardware device. name_of_sound_play = name_of_sound_capt # Use the same device for play back channel_i = 0 # Soundcard index of in-phase channel: 0, 1, 2, ... channel_q = 1 # Soundcard index of quadrature channel: 0, 1, 2, ... quisk-3.6.11/softrock/hardware_usb_new.py0000666000175000017500000002056412150175270020054 0ustar jimjim00000000000000# Please do not change this hardware control module for Quisk. # It provides USB control of SoftRock hardware. from __future__ import print_function import struct, threading, time, traceback, math from quisk_hardware_model import Hardware as BaseHardware import _quisk as QS # All USB access is through control transfers using pyusb. # byte_array = dev.ctrl_transfer (IN, bmRequest, wValue, wIndex, length, timout) # len(string_msg) = dev.ctrl_transfer (OUT, bmRequest, wValue, wIndex, string_msg, timout) import usb.core, usb.util DEBUG = 0 # I2C-address of the SI570; Thanks to Joachim Schneider, DB6QS si570_i2c_address = 0x55 # Thanks to Ethan Blanton, KB8OJH, for this patch for the Si570 (many SoftRocks): # These are used by SetFreqByDirect(); see below. # The Si570 DCO must be clamped between these values SI570_MIN_DCO = 4.85e9 SI570_MAX_DCO = 5.67e9 # The Si570 has 6 valid HSDIV values. Subtract 4 from HSDIV before # stuffing it. We want to find the highest HSDIV first, so start # from 11. SI570_HSDIV_VALUES = [11, 9, 7, 6, 5, 4] IN = usb.util.build_request_type(usb.util.CTRL_IN, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) OUT = usb.util.build_request_type(usb.util.CTRL_OUT, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) UBYTE2 = struct.Struct(' 128: continue if dco < SI570_MIN_DCO or dco > SI570_MAX_DCO: # This really shouldn't happen continue if not dco_new or dco < dco_new: dco_new = dco hsdiv_new = hsdiv n1_new = n1 if not dco_new: # For some reason, we were unable to calculate a frequency. # Probably because the frequency requested is outside the range # of our device. return False # Failure rfreq = dco_new / self.conf.si570_xtal_freq rfreq_int = int(rfreq) rfreq_frac = int(round((rfreq - rfreq_int) * 2**28)) # It looks like the DG8SAQ protocol just passes r7-r12 straight # To the Si570 when given command 0x30. Easy enough. # n1 is stuffed as n1 - 1, hsdiv is stuffed as hsdiv - 4. hsdiv_new = hsdiv_new - 4 n1_new = n1_new - 1 s = struct.Struct('>BBL').pack((hsdiv_new << 5) + (n1_new >> 2), ((n1_new & 0x3) << 6) + (rfreq_int >> 4), ((rfreq_int & 0xf) << 28) + rfreq_frac) self.usb_dev.ctrl_transfer(OUT, 0x30, si570_i2c_address + 0x700, 0, s) return True # Success class KeyThread(threading.Thread): """Create a thread to monitor the key state.""" def __init__(self, dev, poll_secs): self.usb_dev = dev self.poll_secs = poll_secs self.ptt = 0 self.key_down = 0 threading.Thread.__init__(self) self.doQuit = threading.Event() self.doQuit.clear() def run(self): while not self.doQuit.isSet(): try: if self.ptt: key_down = 1 else: # read key state ret = self.usb_dev.ctrl_transfer(IN, 0x51, 0, 0, 1) # bit 0x20 is the tip, bit 0x02 is the ring if ret[0] & 0x20: # Tip: key is up key_down = 0 else: # key is down key_down = 1 if key_down != self.key_down: self.key_down = key_down self.usb_dev.ctrl_transfer(IN, 0x50, key_down, 0, 3) QS.set_key_down(key_down) except usb.core.USBError: QS.set_key_down(0) if DEBUG: traceback.print_exc() time.sleep(self.poll_secs) def stop(self): """Set a flag to indicate that the thread should end.""" self.doQuit.set() def OnPTT(self, ptt): self.ptt = ptt quisk-3.6.11/softrock/README.txt0000644000175000017500000000267211632372230015654 0ustar jimjim00000000000000This directory has config, hardware and widget files for several models of SoftRock. An alternative is to use the VK6JBL hardware file. It controls the SoftRock using the usbsoftrock program. If your SoftRock has a fixed frequency crystal, use config_fixed, and enter the crystal frequency divided by four as fixed_vfo_freq. Recent SoftRock hardware is controlled by USB. Our USB access is provided by Python's pyusb module version 1.0, and that is based on libusb. Check the config screen for error messages. If you get "USB device not found" then the SoftRock is not connected to USB, or the vendor or product ID's are not correct. If you get "No permission", then you don't have permission to access libusb. Quisk will probably run as root, but running as root is a bad idea. Instead try adding this: SUBSYSTEM=="usb", ATTR{idVendor}=="16c0" , ATTR{idProduct}=="05dc", MODE="0666", GROUP="dialout" to a file /etc/udev/local.rules and re-booting. This works on my Debian system. Take a look at libusb.txt; or ask Google. If your SoftRock model is not listed, try the closest model. I don't have every SoftRock available to test, but I will try to help if you send me an email. Please provide your firmware version, which is shown on the config screen. On both Debian and Windows, if I unplug my RxTxEnsemble and plug it in again, it is not recognized. The vendor and product ID's are both zero. I guess the workaround is to leave it plugged in. quisk-3.6.11/softrock/__init__.py0000644000175000017500000000000211632372230016250 0ustar jimjim00000000000000# quisk-3.6.11/softrock/conf_rx_ensemble2.py0000644000175000017500000000163511632372230020120 0ustar jimjim00000000000000# This is a sample quisk_conf.py configuration file for a SoftRock Rx Ensemble II. # Please do not change this sample file. # Instead copy it to your own .quisk_conf.py and make changes there. # See quisk_conf_defaults.py for more information. from softrock import hardware_usb as quisk_hardware # In ALSA, soundcards have these names. The "hw" devices are the raw # hardware devices, and should be used for soundcard capture. #name_of_sound_capt = "hw:0" #name_of_sound_capt = "hw:1" #name_of_sound_capt = "plughw" #name_of_sound_capt = "plughw:1" #name_of_sound_capt = "default" # Vendor and product ID's for the SoftRock usb_vendor_id = 0x16c0 usb_product_id = 0x05dc softrock_model = "RxEnsemble2" #sample_rate = 48000 # ADC hardware sample rate in Hertz #name_of_sound_capt = "hw:0" # Name of soundcard capture hardware device. #name_of_sound_play = name_of_sound_capt # Use the same device for play back quisk-3.6.11/sdriqpkg/0000775000175000017500000000000012164330433014143 5ustar jimjim00000000000000quisk-3.6.11/sdriqpkg/sdriq.pyd0000666000175000017500000004500012162640501016002 0ustar jimjim00000000000000MZ@ !L!This program cannot be run in DOS mode. $PEL AAQ# F04h FH8.text,`P`.data0"@`.rdataP4@0@.eh_fram`8@0.bssp`.edataF:@0@.idata<@0.CRTB@0.tls D@0.relocHF@0BUED$p4hD$p4h$[Í'UED$p4hD$p4h$+ɃÐ&USp4ht4p4h9wtЋp4h9v$p4h$[]É'U8]] uu}}tC|$\$4$3 up4hEVE]u}] t&$hp4htbp4hR4ht|$D$4$Ѓ ^|$D$4$ u1낐t&1v 1dU$P4hRteD$P4h$tD$ p4h$`4hЋ A4ht1$)P4hRt*D$7P4h$t $A4hø말U$P4hNQt%D$KP4h$At $`4hÍvUD$$dP4hX6hlq6hu$wP4h pq6hÐUD$@4hD$P4hE $T6ht d6hUD$ @4hD$@4hD$P4hE $T6ht d6hUD$@4hD$P4hE $T6ht d6hUD$P4hE $T6ht3@4ht @p4h$86h@4hd6hUVS Ɖӡ@4htsUT$$<6htpq6h V;]s]EtBUT$ D$t$@4h$@6huEpq6h  e[^UWVSX\p4hu1p4h)ʁ~~Wp4hp4hEp4h9K)‰Ӂ~p4h9u p4h ~p4hp4hp4h9~(J)ʁ~~p4hp4hDž`p4hp4h9~ ))‹ p4h9p4h@=~1p4h |p4h p4hp4hAp4h |p4hp4h p4h@p4h=~ p4h~up4h 3p4hp4hyp4h upp4hXtD2~=p4h =|p4hu = up4hxp4h9p4hu;p4hgp4h~ p4hu6=|p4hu-p4htp4h@p4h=p4h=|p4hyp4h@=~5p4h p4h#p4h @p4h=~ p4h p4h~6p4h p4hhB~@9ۉp4h$P4hD$hD$$Pp4h _p4hD$hT$$`p4h op4hih Уp6hhtji Уp6haji Уp6hGhЉp6h< u4pq6h,'i@p4hp4h=~ -p4hp4h}v xp4hdo\9`P`XR4hTp4h@=~5p4h p4hTp4h ލx~p4hp4h øCp4hG~p4h ø p4h ÍG=҉!TS $4$ $d$ R4hY`dTأp4hd xp4hFduأp4hdxp4h5`9\أp4hd xp4h=xp4hp4h pq6h p4hAup4h.t$lq6hPۃ=p4h u=p4hup4h 뽠p4h/ &}!oN?,k%,6M;] -H:UDY p6V34u#}?,uUue-}zi_:r>>r_:iz}-euUu,?#}u34V6pY DUH:-] M;6,k%,?No}!&/ >Ht%6/ "A 8] 13v KD\0 2KEF5)kc! 5NT = s- # W]5j KlU g nk?%  ; WyN('iLB0M96.@ɼ- q4MMt0nGk0f-|fK)uf_kKf Qlq$$qlQ fKkf_uK)f-|f0kGnt0MMq4- ɼ@6.M9B0Li'N(yW ;  %?kng  UlK  j5]W #- s = TN5Q4h_4hQ4hQ4hr4hR4hR4h<4h(R4hHR4h4hSR4hnR4h4hR4hh +n(,4hlibgcc_s_dw2-1.dll__register_frame_infolibgcj-11.dll_Jv_RegisterClasses__deregister_frame_info_quisk.QUISK_C_APIFailure to import Quisk_APIiii4h4h4h4h/4hl4h4h4h4h4h4h4h4h4h4h4h4h4h4h4h4h4h4h4h4hNoNamesdriq_namesdriq_clockSDR-IQOpen SDR-IQ failedSet Timeouts failedCapture from %s serial %s.No response from SDR-IQsdriqPy_InitModule failed!Failure to import pointers from _quiskopen_samplesOpen the RfSpace SDR-IQ.close_samplesClose the RfSpace SDR-IQ.freq_sdriqSet the frequency of the SDR-IQgain_sdriqSet the gain of the SDR-IQset_decimationSet the decimation of the SDR-IQG$tIzDmingwm10.dll__mingwthr_remove_key_dtor__mingwthr_key_dtor$4hMingw runtime failure: VirtualQuery failed for %d bytes at address %p Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. AAQ2(,0#<sdriq.pydinitsdriq8T(lXđ.@Rjƒ *:HR^hpzƓ.@Rjƒ *:HR^hpzƓFTD2XX.dllPyArg_ParseTuple>PyCapsule_ImportPyString_FromStringVPy_InitModule4_Py_NoneStructDeleteCriticalSectionEnterCriticalSection`FreeLibraryGetLastErrorGetModuleHandleAAGetProcAddressInitializeCriticalSection.LeaveCriticalSection1LoadLibraryATlsGetValueVirtualProtectVirtualQuery8__dllonexit_errno_snprintffflushfreemallocputsstrncpy _iob_winmajorGabortScallocyfwritememcpyvfprintfpython27.dll((((((((((((KERNEL32.dll<<<<<<<<msvcr90.dllPPPPPPPmsvcrt.dll$4h#4h6h6hp6h6h 00=0E0i0s0000/1<1A11111112$2E2W2m2222222222333$3-3F3N3Z3c3|3333333333(414B44444444455&515@5F5\5t555555555555 66626V6e6u66666666666 7$737>7K7V7c7p7z77777778&8L8f8w8888888 99'939A9X9_9r999999::::F:L:Y:p:::::::::::: ;3;P;;;< <<17>>>E>L>S>R?W?m?y?????????????? (0$0B0K0b0v0000000#11111112*2B2P2Y2_2h2222222222222?3F3L3W3n3~333333334'404X4c4r4444444444 55(575G5M5d5x5555666667 777'7N7U77777)8]8w88888889999K9V99999: :#:H:c:m::::: ;;";/;v;~;;;;;;;;;;;;;;;; <<@(0000000000000001P<00000000000000000000000002 00000 0quisk-3.6.11/sdriqpkg/quisk_hardware.py0000644000175000017500000000547012124355757017546 0ustar jimjim00000000000000# Please do not change this hardware control module. # It provides support for the SDR-IQ by RfSpace. from __future__ import print_function import _quisk as QS import sdriq from quisk_hardware_model import Hardware as BaseHardware class Hardware(BaseHardware): decimations = [1250, 600, 500, 360] def __init__(self, app, conf): BaseHardware.__init__(self, app, conf) self.use_sidetone = 1 self.clock = conf.sdriq_clock self.rf_gain_labels = ('RF +30', 'RF +20', 'RF +10', 'RF 0 dB') if conf.fft_size_multiplier == 0: conf.fft_size_multiplier = 3 # Set size needed by VarDecim def open(self): return sdriq.open_samples() # Return a config message def close(self): sdriq.close_samples() def OnButtonRfGain(self, event): """Set the SDR-IQ preamp gain and attenuator state. sdriq.gain_sdriq(gstate, gain) gstate == 0: Gain must be 0, -10, -20, or -30 gstate == 1: Attenuator is on and gain is 0 to 127 (7 bits) gstate == 2: Attenuator is off and gain is 0 to 127 (7 bits) gain for 34, 24, 14, 4 db is 127, 39, 12, 4. """ btn = event.GetEventObject() n = btn.index if n == 0: sdriq.gain_sdriq(2, 127) elif n == 1: sdriq.gain_sdriq(2, 39) elif n == 2: sdriq.gain_sdriq(2, 12) elif n == 3: sdriq.gain_sdriq(1, 12) else: print ('Unknown RfGain') def ChangeFrequency(self, tune, vfo, source='', band='', event=None): if vfo: sdriq.freq_sdriq(vfo) return tune, vfo def ChangeBand(self, band): # band is a string: "60", "40", "WWV", etc. btn = self.application.BtnRfGain if btn: if band in ('160', '80', '60', '40'): btn.SetLabel('RF +10', True) elif band in ('20',): btn.SetLabel('RF +20', True) else: btn.SetLabel('RF +20', True) def VarDecimGetChoices(self): # return text labels for the control l = [] # a list of sample rates for dec in self.decimations: l.append(str(int(float(self.clock) / dec / 1e3 + 0.5))) return l def VarDecimGetLabel(self): # return a text label for the control return "Sample rate ksps" def VarDecimGetIndex(self): # return the current index return self.index def VarDecimSet(self, index=None): # set decimation, return sample rate if index is None: # initial call to set decimation before the call to open() rate = self.application.vardecim_set # May be None or from different hardware try: dec = int(float(self.clock / rate + 0.5)) self.index = self.decimations.index(dec) except: try: self.index = self.decimations.index(self.conf.sdriq_decimation) except: self.index = 0 else: self.index = index dec = self.decimations[self.index] sdriq.set_decimation(dec) return int(float(self.clock) / dec + 0.5) quisk-3.6.11/sdriqpkg/sdriq.h0000644000175000017500000001610311632372230015435 0ustar jimjim00000000000000// These are decimation factors, scale factors and filter coefficients for the SDR-IQ. // They are used to program the AD6620 chip. struct ad6620 { int Mcic2; int Mcic5; int Mrcf; int Scic2; int Scic5; int Sout; int coef[256]; } ; struct ad6620 dec360 = { 4, 18, 5, // decimation factors 4, 13, 6, // scale factors {131, -230, -38, -304, -235, -346, -237, -181, 12, 149, 310, 349, 320, 154, -60, -310, -480, -540, -423, -169, 187, 523, 749, 762, 543, 117, -394, -851, -1093, -1025, -621, 22, 737, 1300, 1522, 1288, 625, -309, -1245, -1893, -2013, -1515, -489, 793, 1957, 2623, 2533, 1640, 149, -1533, -2893, -3475, -3023, -1584, 480, 2582, 4063, 4405, 3401, 1246, -1484, -3986, -5455, -5345, -3557, -509, 2951, 5776, 7030, 6193, 3355, -760, -4970, -7969, -8722, -6815, -2628, 2712, 7632, 10563, 10431, 7033, 1169, -5529, -11037, -13543, -12021, -6623, 1287, 9443, 15320, 16896, 13319, 5269, -5122, -14811, -20711, -20642, -14088, -2504, 10961, 22272, 27682, 24909, 13986, -2524, -20051, -33214, -37378, -30153, -12380, 11742, 35506, 51387, 53179, 38008, 7662, -31208, -68176, -91255, -89756, -57102, 7096, 96306, 197916, 295555, 372388, 414662, 414662, 372388, 295555, 197916, 96306, 7096, -57102, -89756, -91255, -68176, -31208, 7662, 38008, 53179, 51387, 35506, 11742, -12380, -30153, -37378, -33214, -20051, -2524, 13986, 24909, 27682, 22272, 10961, -2504, -14088, -20642, -20711, -14811, -5122, 5269, 13319, 16896, 15320, 9443, 1287, -6623, -12021, -13543, -11037, -5529, 1169, 7033, 10431, 10563, 7632, 2712, -2628, -6815, -8722, -7969, -4970, -760, 3355, 6193, 7030, 5776, 2951, -509, -3557, -5345, -5455, -3986, -1484, 1246, 3401, 4405, 4063, 2582, 480, -1584, -3023, -3475, -2893, -1533, 149, 1640, 2533, 2623, 1957, 793, -489, -1515, -2013, -1893, -1245, -309, 625, 1288, 1522, 1300, 737, 22, -621, -1025, -1093, -851, -394, 117, 543, 762, 749, 523, 187, -169, -423, -540, -480, -310, -60, 154, 320, 349, 310, 149, 12, -181, -237, -346, -235, -304, -38, -230, 131}}; struct ad6620 dec500 = { 4, 25, 5, 4, 16, 5, {-197, 356, -153, 176, -101, 34, -125, -46, -106, -7, 12, 115, 129, 157, 86, 12, -116, -197, -251, -203, -97, 80, 242, 364, 367, 259, 33, -228, -461, -565, -504, -255, 106, 488, 756, 813, 604, 172, -377, -868, -1139, -1066, -639, 53, 807, 1390, 1584, 1288, 537, -470, -1439, -2046, -2060, -1406, -232, 1143, 2290, 2820, 2496, 1339, -366, -2120, -3369, -3659, -2808, -976, 1340, 3448, 4652, 4486, 2873, 198, -2785, -5152, -6095, -5184, -2546, 1137, 4785, 7240, 7613, 5604, 1641, -3190, -7438, -9701, -9091, -5546, 69, 6163, 10849, 12519, 10373, 4745, -2905, -10342, -15198, -15692, -11253, -2807, 7368, 16229, 20838, 19296, 11436, -946, -14436, -24891, -28637, -23657, -10406, 8025, 26518, 39215, 41181, 30008, 6896, -23122, -51997, -70364, -69788, -44995, 4465, 73600, 152608, 228689, 288639, 321648, 321648, 288639, 228689, 152608, 73600, 4465, -44995, -69788, -70364, -51997, -23122, 6896, 30008, 41181, 39215, 26518, 8025, -10406, -23657, -28637, -24891, -14436, -946, 11436, 19296, 20838, 16229, 7368, -2807, -11253, -15692, -15198, -10342, -2905, 4745, 10373, 12519, 10849, 6163, 69, -5546, -9091, -9701, -7438, -3190, 1641, 5604, 7613, 7240, 4785, 1137, -2546, -5184, -6095, -5152, -2785, 198, 2873, 4486, 4652, 3448, 1340, -976, -2808, -3659, -3369, -2120, -366, 1339, 2496, 2820, 2290, 1143, -232, -1406, -2060, -2046, -1439, -470, 537, 1288, 1584, 1390, 807, 53, -639, -1066, -1139, -868, -377, 172, 604, 813, 756, 488, 106, -255, -504, -565, -461, -228, 33, 259, 367, 364, 242, 80, -97, -203, -251, -197, -116, 12, 86, 157, 129, 115, 12, -7, -106, -46, -125, 34, -101, 176, -153, 356, -197}}; struct ad6620 dec600 = { 5, 30, 4, // decimation factors 5, 17, 5, // scale factors { 436, -1759, 99, -1281, 0, -280, 619, 409, 553, -71, -344, -753, -537, -203, 453, 782, 838, 325, -326, -949, -1037, -628, 230, 991, 1330, 923, 10, -1032, -1569, -1324, -299, 956, 1822, 1739, 716, -809, -2000, -2212, -1212, 520, 2123, 2678, 1823, -111, -2124, -3143, -2509, -463, 2002, 3548, 3279, 1188, -1699, -3877, -4088, -2087, 1206, 4069, 4920, 3137, -478, -4094, -5720, -4343, -493, 3887, 6454, 5669, 1741, -3412, -7052, -7096, -3266, 2607, 7462, 8573, 5084, -1425, -7602, -10058, -7187, -193, 7400, 11481, 9579, 2301, -6756, -12777, -12244, -4971, 5569, 13854, 15181, 8285, -3699, -14613, -18387, -12369, 966, 14920, 21888, 17412, 2905, -14598, -25744, -23754, -8362, 13363, 30114, 32035, 16259, -10708, -35362, -43638, -28445, 5493, 42387, 62053, 49891, 5603, -53825, -99044, -99811, -38467, 80479, 229234, 365232, 446270, 446270, 365232, 229234, 80479, -38467, -99811, -99044, -53825, 5603, 49891, 62053, 42387, 5493, -28445, -43638, -35362, -10708, 16259, 32035, 30114, 13363, -8362, -23754, -25744, -14598, 2905, 17412, 21888, 14920, 966, -12369, -18387, -14613, -3699, 8285, 15181, 13854, 5569, -4971, -12244, -12777, -6756, 2301, 9579, 11481, 7400, -193, -7187, -10058, -7602, -1425, 5084, 8573, 7462, 2607, -3266, -7096, -7052, -3412, 1741, 5669, 6454, 3887, -493, -4343, -5720, -4094, -478, 3137, 4920, 4069, 1206, -2087, -4088, -3877, -1699, 1188, 3279, 3548, 2002, -463, -2509, -3143, -2124, -111, 1823, 2678, 2123, 520, -1212, -2212, -2000, -809, 716, 1739, 1822, 956, -299, -1324, -1569, -1032, 10, 923, 1330, 991, 230, -628, -1037, -949, -326, 325, 838, 782, 453, -203, -537, -753, -344, -71, 553, 409, 619, -280, 0, -1281, 99, -1759, 436}}; struct ad6620 dec1250 = { 10, 25, 5, // decimation factors 7, 15, 6, // scale factors {-378, 13756, -14444, 8014, -7852, 3556, -3779, 2733, -909, 2861, 208, 1827, -755, -243, -2134, -1267, -1705, 20, 492, 2034, 1885, 1993, 535, -459, -2052, -2387, -2454, -1112, 246, 2053, 2832, 3019, 1774, 133, -1973, -3220, -3654, -2546, -683, 1769, 3531, 4330, 3431, 1417, -1400, -3730, -5013, -4428, -2350, 831, 3780, 5669, 5520, 3489, -23, -3635, -6252, -6689, -4839, -1057, 3245, 6715, 7904, 6403, 2443, -2555, -6998, -9129, -8175, -4172, 1504, 7033, 10318, 10147, 6281, -23, -6747, -11415, -12315, -8815, -1972, 6041, 12354, 14669, 11830, 4593, -4800, -13060, -17207, -15419, -7992, 2861, 13425, 19944, 19729, 12404, 21, -13318, -22930, -25017, -18239, -4245, 12519, 26289, 31789, 26259, 10571, -10635, -30306, -41114, -38121, -20661, 6795, 35686, 55688, 58124, 39093, 1561, -44548, -84372, -101901, -84500, -26969, 66196, 180937, 296484, 390044, 442339, 442339, 390044, 296484, 180937, 66196, -26969, -84500, -101901, -84372, -44548, 1561, 39093, 58124, 55688, 35686, 6795, -20661, -38121, -41114, -30306, -10635, 10571, 26259, 31789, 26289, 12519, -4245, -18239, -25017, -22930, -13318, 21, 12404, 19729, 19944, 13425, 2861, -7992, -15419, -17207, -13060, -4800, 4593, 11830, 14669, 12354, 6041, -1972, -8815, -12315, -11415, -6747, -23, 6281, 10147, 10318, 7033, 1504, -4172, -8175, -9129, -6998, -2555, 2443, 6403, 7904, 6715, 3245, -1057, -4839, -6689, -6252, -3635, -23, 3489, 5520, 5669, 3780, 831, -2350, -4428, -5013, -3730, -1400, 1417, 3431, 4330, 3531, 1769, -683, -2546, -3654, -3220, -1973, 133, 1774, 3019, 2832, 2053, 246, -1112, -2454, -2387, -2052, -459, 535, 1993, 1885, 2034, 492, 20, -1705, -1267, -2134, -243, -755, 1827, 208, 2861, -909, 2733, -3779, 3556, -7852, 8014, -14444, 13756, -378 }}; quisk-3.6.11/sdriqpkg/sdriq.c0000644000175000017500000005604111724231742015441 0ustar jimjim00000000000000#include #ifdef MS_WINDOWS #include #include "ftd2xx.h" #else #include #include #include #include #include #include #include #include #include #include #include #endif #include #define IMPORT_QUISK_API #include "quisk.h" #include "sdriq.h" // This module provides access to the SDR-IQ by RfSpace. It is the source // for the Python extension module sdriq. It can be used as a model for an // extension module for other hardware. Read the end of this file for more // information. This module was written by James Ahlstrom, N2ADR. // This module uses the Python interface to import symbols from the parent _quisk // extension module. It must be linked with import_quisk_api.c. See the documentation // at the start of import_quisk_api.c. // Start of SDR-IQ specific code: // #define DEBUG 0 #define SDRIQ_BLOCK 8194 #define SDRIQ_BUF_SIZE 131072 #define INC_IREAD if (++iread >= SDRIQ_BUF_SIZE) iread = 0; // Number of milliseconds to wait for SDR-IQ data on each read #define SDRIQ_MSEC 4 // Timeout for SDR-IQ as a multiple of SDRIQ_MSEC #define SDRIQ_TIMEOUT 50 // Type field for the message block header; upper 3 bits of byte #define TYPE_HOST_SET 0 #define TYPE_HOST_GET (1 << 5) #define NAME_SIZE 16 static double sdriq_clock; static int sdr_ack; // got ACK static int sdr_nak; // got NAK static char sdr_name[NAME_SIZE]; // control item 1 static char sdr_serial[NAME_SIZE]; // item 2 static int sdr_interface; // item 3 static int sdr_firmware; // item 4 static int sdr_bootcode; // item 4 static int sdr_status; // item 5 static int sdr_idle; // item 0x18, 1==idle, 2==run static int sdriq_freq=7220000; // set SDR-IQ to this frequency static int sdriq_gstate=2, sdriq_gain=127; // set SDR-IQ gain to this value static int sdriq_decimation = 360; // set SDR-IQ decimation to this value static int cur_freq, cur_gstate, cur_gain; // current value of frequency and gain static int cur_decimation; // current value of decimation #ifdef MS_WINDOWS static FT_HANDLE quisk_sdriq_fd = INVALID_HANDLE_VALUE; static int Read(void * buf, int bufsize) { DWORD bytes, rx_bytes; if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return 0; if (FT_GetQueueStatus(quisk_sdriq_fd, &rx_bytes) != FT_OK) { pt_quisk_sound_state->read_error++; return 0; } if (rx_bytes > bufsize) rx_bytes = bufsize; if (rx_bytes == 0) { return 0; } else if (FT_Read(quisk_sdriq_fd, buf, rx_bytes, &bytes) == FT_OK) { return bytes; } else { pt_quisk_sound_state->read_error++; return 0; } } static int Write(void * buf, int length) { DWORD bytes; if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return 0; if (FT_Write(quisk_sdriq_fd, buf, length, &bytes) == FT_OK) { return bytes; } else { return 0; } } #else #define INVALID_HANDLE_VALUE -1 static int quisk_sdriq_fd = INVALID_HANDLE_VALUE; static int Read(void * buf, int bufsize) { int res; if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return 0; res = read(quisk_sdriq_fd, buf, bufsize); if (res < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { pt_quisk_sound_state->read_error++; } return 0; } return res; } static int Write(void * buf, int length) { int res; if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return 0; res = write(quisk_sdriq_fd, buf, length); if (res <= 0) return 0; return res; } #endif static void update_item(int item, const unsigned char * data) { switch(item) { case 1: strncpy(sdr_name, (char *)data, NAME_SIZE); sdr_name[NAME_SIZE - 1] = 0; break; case 2: strncpy(sdr_serial, (char *)data, NAME_SIZE); sdr_serial[NAME_SIZE - 1] = 0; break; case 3: sdr_interface = (data[1] << 8) | data[0]; break; case 4: if (data[0]) sdr_firmware = (data[2] << 8) | data[1]; else sdr_bootcode = (data[2] << 8) | data[1]; break; case 5: sdr_status = data[0]; if (data[0] == 0x20) pt_quisk_sound_state->overrange++; #if DEBUG if (data[0] == 0x20) printf ("Got overrange (clip)\n"); else printf ("Got status 0x%X\n", data[0]); #endif break; case 0x18: sdr_idle = data[1]; #if DEBUG if (sdr_idle == 1) printf ("Got idle code IDLE\n"); else if (sdr_idle == 2) printf ("Got idle code RUN\n"); else printf ("Got idle code UNKNOWN\n"); #endif break; } } static void get_item( // Host sends a request for a control item int item, // the item number int nparams, // the length of params char * params) // byte array of parameters, or NULL iff nparams==0 { int length; // length of message block char buf[64]; // message block header and control item and data length = 4 + nparams; if (length > 60) return; // error buf[0] = length & 0xFF; // length LSB buf[1] = TYPE_HOST_GET | ((length >> 8) & 0x1F); // 3-bit type and 5-bit length MSB buf[2] = item & 0xFF; // item LSB buf[3] = (item >> 8) & 0xFF; // item MSB if (nparams) memcpy(buf + 4, params, nparams); if (Write(buf, length) != length) { pt_quisk_sound_state->read_error++; #if DEBUG printf("get_item write error\n"); #endif } #if DEBUG > 1 printf ("get_item 0x%X\n", item); #endif return; } static void set_item( // host command to set a control item int item, // the item number int nparams, // the length of params char * params) // byte array of parameters, or NULL iff nparams==0 { int length; char buf[64]; // message block header and control item and data length = 4 + nparams; // total length if (length > 60) return; // error buf[0] = length & 0xFF; // length LSB buf[1] = TYPE_HOST_SET | ((length >> 8) & 0x1F); // 3-bit type and 5-bit length MSB buf[2] = item & 0xFF; // item LSB buf[3] = (item >> 8) & 0xFF; // item MSB if (nparams) memcpy(buf + 4, params, nparams); if (Write(buf, length) != length) { pt_quisk_sound_state->read_error++; #if DEBUG printf("set_item write error\n"); #endif } #if DEBUG > 1 printf ("set_item 0x%X\n", item); #endif } // The ft245 driver does not have a circular buffer for input; bytes are just appended // to the buffer. When all bytes are read and the buffer goes empty, the pointers are reset to zero. // Be sure to empty out the ft245 frequently so its buffer does not overflow. static int sdr_recv(complex * samp, int sampsize) { // Read all data from the SDR-IQ and process it. // Return the number >= 0 of I/Q data samples that are available in samp. int k, res, item, navail, nSamples; short ii, qq; unsigned char buf128[128]; static unsigned char buf[SDRIQ_BUF_SIZE]; static int iread=0; static int iwrite=0; static int state=0; static int length; static int type; static int sample_count; nSamples = 0; // number of samples added to samp // first read all characters from the ft245 driver into our large buffer if (iread == 0) { k = SDRIQ_BUF_SIZE - iwrite - 1; if (k > 65536) // maximum read for ft245 k = 65536; if (k > 0) { res = Read(buf + iwrite, k); iwrite += res; } } else if (iread <= iwrite) { k = SDRIQ_BUF_SIZE - iwrite; if (k > 65536) // maximum read for ft245 k = 65536; res = Read(buf + iwrite, k); if (res == k) iwrite = 0; else if (res > 0) iwrite += res; } if (iread > iwrite) { k = iread - iwrite - 1; if (k > 65536) // maximum read for ft245 k = 65536; if (k > 0) { res = Read(buf + iwrite, k); iwrite += res; } } // Now process the data we have in buf start_here: if (iread > iwrite) // calculate number of available bytes: navail navail = SDRIQ_BUF_SIZE - iread + iwrite; else navail = iwrite - iread; if (state == 0) { // starting state; we need to read the first two bytes for length and type if (navail < 2) return nSamples; // no more data available // we have the first two bytes length = buf[iread]; INC_IREAD type = (buf[iread] >> 5) & 0x7; // 3-bit type length |= (buf[iread] & 0x1F) << 8; // length including header INC_IREAD #if DEBUG > 1 if (length != 0 && !(type == 3 && length == 3)) printf("Got message type %d length %d\n", type, length); #endif if (type > 3 && length == 0) // data block with zero length length = 8194; // special data length length -= 2; // we read two bytes; length is the remaining bytes if (length < 0) { state = 9; // bad length; attempt resync } else if (length == 0) { // NAK sdr_nak = 1; #if DEBUG printf("Got NAK\n"); #endif // state remains at zero } else if (samp && length > 50 && length < 8192) { // No such message; we are out of sync state = 9; } else if (samp && type == 4 && length == 8192) { // ADC samples data block state = 5; sample_count = 2048; } else if (navail >= length) { state = 3; } else { state = 2; } goto start_here; // process the next state } else if (state == 2) { // waiting for all "length" bytes to be read if (navail < length) return nSamples; // partially read block state = 3; goto start_here; // process the next state } else if (state == 3) { // we have all the bytes of the record available if (length == 1 && type == 3) { // ACK sdr_ack = buf[iread]; INC_IREAD #if DEBUG > 1 printf("Got ACK for 0x%X\n", sdr_ack); #endif } else if ((type == 0 || type == 1) && length >= 2) { // control item item = buf[iread]; INC_IREAD item |= buf[iread] << 8; // control item number INC_IREAD length -= 2; for (k = 0; k < length; k++) { if (k < 128) buf128[k] = buf[iread]; INC_IREAD } update_item(item, buf128); } else { iread += length; // discard block if (iread >= SDRIQ_BUF_SIZE) iread -= SDRIQ_BUF_SIZE; } state = 0; goto start_here; // we read a whole block } else if (state == 5) { // read available samples into samp //ptimer(4096); while (navail >= 4 && sample_count && nSamples < sampsize) { // samples are 16-bit little-endian ii = buf[iread]; // assumes a short is two bytes INC_IREAD ii |= buf[iread] << 8; INC_IREAD qq = buf[iread]; INC_IREAD qq |= buf[iread] << 8; INC_IREAD navail -= 4; // we read four bytes // convert 16-bit samples to 32-bit samples samp[nSamples++] = 65536.0 * ii + 65536.0 * qq * I; // return sample as complex number sample_count--; // we added one sample } //printf("State %d navail %d sample_count %d nSamples %d\n", state, navail, sample_count, nSamples); if (sample_count > 0) // no more samples available return nSamples; // return the available samples state = 0; // this block was completely read goto start_here; // process the next state } else if (state == 9) { // try to re-synchronize pt_quisk_sound_state->read_error++; #if DEBUG printf ("Lost sync: type %d length %d\n", type, length); #endif while (1) { // empty the buffer if (Read(buf, 1024) == 0) break; } #if DEBUG > 2 printf("Buffer is empty\n"); #endif while (1) { // look for the start of data blocks "\x00\x80" res = Read(buf, 1); if (res != 1) { QuiskSleepMicrosec(SDRIQ_MSEC * 1000); } else if (state == 9) { // look for 0x00 if (buf[0] == 0x00) state = 10; } else { // state 10: look for 0x80 if (buf[0] == 0x80) { state = 5; iread = iwrite = 0; sample_count = 2048; #if DEBUG printf("Regained sync\n"); #endif break; // we probably have a data block start } else if (buf[0] != 0x00) { state = 9; } } } goto start_here; // process the next state } return nSamples; // should not happen } static void set_ad6620( // host command to set an AD6620 register int address, // the register address int value) // the value; up to 4 bytes { char buf[12]; buf[0] = '\x09'; buf[1] = '\xA0'; buf[2] = address & 0xFF; // low byte buf[3] = (address >> 8) & 0xFF; // high byte buf[4] = value & 0xFF; // low byte value = value >> 8; buf[5] = value & 0xFF; value = value >> 8; buf[6] = value & 0xFF; value = value >> 8; buf[7] = value & 0xFF; buf[8] = 0; if (Write(buf, 9) != 9) { pt_quisk_sound_state->read_error++; #if DEBUG printf ("set_ad6620 write error\n"); #endif } #if DEBUG > 1 printf ("set_ad6620 address 0x%X\n", address); #endif } static void wset_ad6620(int address, int value) { // Set AD6620 register and wait for ACK int i; sdr_ack = -1; set_ad6620(address, value); for (i = 0; i < SDRIQ_TIMEOUT; i++) { sdr_recv(NULL, 0); if (sdr_ack != -1) break; QuiskSleepMicrosec(SDRIQ_MSEC * 1000); } #if DEBUG if (sdr_ack != 1) printf ("Failed to get ACK for AD6620 address 0x%X\n", address); #endif } static void set_freq_sdriq(void) // Set SDR-IQ frequency { char buf[8]; int freq; freq = sdriq_freq; buf[0] = 0; buf[1] = freq & 0xFF; // low byte freq = freq >> 8; buf[2] = freq & 0xFF; freq = freq >> 8; buf[3] = freq & 0xFF; freq = freq >> 8; buf[4] = freq & 0xFF; buf[5] = 1; set_item(0x0020, 6, buf); cur_freq = sdriq_freq; } static void set_gain_sdriq(void) { char buf[2]; switch (sdriq_gstate) { case 0: buf[0] = 0; buf[1] = sdriq_gain & 0xFF; break; case 1: buf[0] = 1; buf[1] = sdriq_gain & 0x7F; buf[1] |= 0x80; break; case 2: buf[0] = 1; buf[1] = sdriq_gain & 0x7F; break; } set_item(0x0038, 2, buf); cur_gstate = sdriq_gstate; cur_gain = sdriq_gain; } static void program_ad6620(void) // Set registers { int i; struct ad6620 *pt; switch (sdriq_decimation) { case 360: pt = &dec360; break; case 500: pt = &dec500; break; case 600: pt = &dec600; break; case 1250: pt = &dec1250; break; default: pt = &dec1250; break; } wset_ad6620(0x300, 1); // soft reset for (i = 0; i < 256; i++) wset_ad6620(i, pt->coef[i]); wset_ad6620(0x301, 0); wset_ad6620(0x302, -1); wset_ad6620(0x303, 0); wset_ad6620(0x304, 0); wset_ad6620(0x305, pt->Scic2); wset_ad6620(0x306, pt->Mcic2 - 1); wset_ad6620(0x307, pt->Scic5); wset_ad6620(0x308, pt->Mcic5 - 1); wset_ad6620(0x309, pt->Sout); wset_ad6620(0x30A, pt->Mrcf - 1); wset_ad6620(0x30B, 0); wset_ad6620(0x30C, 255); wset_ad6620(0x30D, 0); set_freq_sdriq(); set_gain_sdriq(); wset_ad6620(0x300, 0); cur_decimation = sdriq_decimation; } #ifdef MS_WINDOWS static void quisk_open_sdriq_dev(const char * name, char * buf, int bufsize) { #if DEBUG FT_STATUS ftStatus; FT_DEVICE_LIST_INFO_NODE *devInfo; DWORD numDevs; int i; // create the device information list ftStatus = FT_CreateDeviceInfoList(&numDevs); if (ftStatus == FT_OK) { printf("Number of devices is %d\n", (int)numDevs); } else { printf("Number of devices failed\n"); numDevs = 0; } if (numDevs > 0) { // allocate storage for list based on numDevs devInfo = (FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs); // get the device information list ftStatus = FT_GetDeviceInfoList(devInfo, &numDevs); if (ftStatus == FT_OK) { for (i = 0; i < numDevs; i++) { printf("Dev %d:\n",i); printf(" Flags=0x%x\n", (unsigned int)devInfo[i].Flags); printf(" Type=0x%x\n", (unsigned int)devInfo[i].Type); printf(" ID=0x%x\n", (unsigned int)devInfo[i].ID); printf(" LocId=0x%x\n", (unsigned int)devInfo[i].LocId); printf(" SerialNumber=%s\n", devInfo[i].SerialNumber); printf(" Description=%s\n", devInfo[i].Description); printf(" ftHandle=0x%x\n", (unsigned int)devInfo[i].ftHandle); } } free(devInfo); } #endif // DEBUG if (FT_OpenEx ("SDR-IQ", FT_OPEN_BY_DESCRIPTION, &quisk_sdriq_fd) != FT_OK) { strncpy(buf, "Open SDR-IQ failed", bufsize); quisk_sdriq_fd = INVALID_HANDLE_VALUE; return; } if (FT_SetTimeouts(quisk_sdriq_fd, 2, 100) != FT_OK) { strncpy(buf, "Set Timeouts failed", bufsize); return; } } #else static void quisk_open_sdriq_dev(const char * name, char * buf, int bufsize) { struct termios newtio; if (!strncmp(name, "/dev/ttyUSB", 11)) { // use ftdi_sio driver quisk_sdriq_fd = open(name, O_RDWR | O_NOCTTY); if (quisk_sdriq_fd < 0) { strncpy(buf, "Open SDR-IQ : ", bufsize); strncat(buf, strerror(errno), bufsize - strlen(buf) - 1); quisk_sdriq_fd = INVALID_HANDLE_VALUE; return; } bzero(&newtio, sizeof(newtio)); newtio.c_cflag = CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; cfsetispeed(&newtio, B230400); cfsetospeed(&newtio, B230400); newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; // specify non-blocking read newtio.c_cc[VMIN] = 0; tcflush(quisk_sdriq_fd, TCIFLUSH); tcsetattr(quisk_sdriq_fd, TCSANOW, &newtio); } else { // use ft245 or similar driver quisk_sdriq_fd = open(name, O_RDWR | O_NONBLOCK); if (quisk_sdriq_fd < 0) { strncpy(buf, "Open SDR-IQ: ", bufsize); strncat(buf, strerror(errno), bufsize - strlen(buf) - 1); quisk_sdriq_fd = INVALID_HANDLE_VALUE; return; } } return; } #endif static void quisk_open_sdriq(const char * name, char * buf, int bufsize) { char buf1024[1024]; int i, freq; quisk_open_sdriq_dev(name, buf, bufsize); if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return; // error sdr_name[0] = 0; sdr_serial[0] = 0; sdr_idle = -1; // unknown state set_item(0x0018, 4, "\x81\x01\x00\x00"); QuiskSleepMicrosec(1000000); while (1) { // read and discard any available output if (Read(buf1024, 1024) == 0) break; } set_item(0x0018, 4, "\x81\x01\x00\x00"); get_item(0x0002, 0, NULL); // request serial number get_item(0x0005, 0, NULL); // request status // set sample rate freq = sdriq_clock; buf1024[0] = 0; buf1024[1] = freq & 0xFF; // low byte freq = freq >> 8; buf1024[2] = freq & 0xFF; freq = freq >> 8; buf1024[3] = freq & 0xFF; freq = freq >> 8; buf1024[4] = freq & 0xFF; set_item(0x00B0, 5, buf1024); // set actual clock speed get_item(0x0001, 0, NULL); // request name // loop for input for (i = 0; i < SDRIQ_TIMEOUT; i++) { sdr_recv(NULL, 0); if (sdr_name[0] != 0) break; QuiskSleepMicrosec(SDRIQ_MSEC * 1000); } if (sdr_name[0]) { // we got a response snprintf(buf, bufsize, "Capture from %s serial %s.", sdr_name, sdr_serial); program_ad6620(); } else { snprintf(buf, bufsize, "No response from SDR-IQ"); } #if DEBUG printf ("%s\n", buf); #endif } static void WaitForPoll(void) { static double time0 = 0; // time in seconds double timer; // time remaining from last poll usec timer = pt_quisk_sound_state->data_poll_usec - (QuiskTimeSec() - time0) * 1e6; if (timer > 1000.0) // see if enough time has elapsed QuiskSleepMicrosec((int)timer); // wait for the remainder of the poll interval time0 = QuiskTimeSec(); // reset starting time value } // End of most SDR-IQ specific code. /////////////////////////////////////////////////////////////////////////// // The API requires at least two Python functions for Open and Close, plus // additional Python functions as needed. And it requires exactly three // C funcions for Start, Stop and Read samples. Quisk runs in two threads, // a GUI thread and a sound thread. You must not call the GUI or any Python // code from the sound thread. You must return promptly from functions called // by the sound thread. // // The calling sequence is Open, Start, then repeated calls to Read, then // Stop, then Close. // Start of Application Programming Interface (API) code: // Start sample capture; called from the sound thread. static void quisk_start_sdriq(void) { if (sdr_idle != 2) set_item(0x0018, 4, "\x81\x02\x00\x01"); } // Stop sample capture; called from the sound thread. static void quisk_stop_sdriq(void) { int msec; complex samples[2048]; for (msec = 0; msec < 1001; msec++) { if (msec % 100 == 0) set_item(0x0018, 4, "\x81\x01\x00\x00"); sdr_recv(samples, 2048); if (sdr_idle == 1) break; QuiskSleepMicrosec(1000); } #if DEBUG if (msec < 1001) printf("quisk_stop_sdriq succeeded\n"); else printf("quisk_stop_sdriq timed out\n"); #endif } // Called in a loop to read samples; called from the sound thread. static int quisk_read_sdriq(complex * cSamples) { int length; WaitForPoll(); if (quisk_sdriq_fd == INVALID_HANDLE_VALUE) return -1; // sdriq is closed length = sdr_recv(cSamples, SAMP_BUFFER_SIZE); // get all available samples if (cur_freq != sdriq_freq) // check frequency set_freq_sdriq(); if (cur_gstate != sdriq_gstate || cur_gain != sdriq_gain) // check gain set_gain_sdriq(); if (cur_decimation != sdriq_decimation) { // check decimation quisk_stop_sdriq(); program_ad6620(); quisk_start_sdriq(); } return length; // return number of samples } // Called to close the sample source; called from the GUI thread. static PyObject * close_samples(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "")) return NULL; if (quisk_sdriq_fd != INVALID_HANDLE_VALUE) { sdr_idle = -1; // unknown state #ifdef MS_WINDOWS FT_Close(quisk_sdriq_fd); #else close(quisk_sdriq_fd); #endif quisk_sdriq_fd = INVALID_HANDLE_VALUE; } Py_INCREF (Py_None); return Py_None; } // Called to open the sample source; called from the GUI thread. static PyObject * open_samples(PyObject * self, PyObject * args) { const char * name; char buf[128]; if (!PyArg_ParseTuple (args, "")) return NULL; name = QuiskGetConfigString("sdriq_name", "NoName"); sdriq_clock = QuiskGetConfigDouble("sdriq_clock", 66666667.0); // Record our C-language Start/Stop/Read functions for use by sound.c. quisk_sample_source(&quisk_start_sdriq, &quisk_stop_sdriq, &quisk_read_sdriq); ////////////// quisk_open_sdriq(name, buf, 128); // SDR-IQ specific return PyString_FromString(buf); // return a string message } // Miscellaneous functions needed by the SDR-IQ; called from the GUI thread as // a result of button presses. // Set the receive frequency; called from the GUI thread. static PyObject * freq_sdriq(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &sdriq_freq)) return NULL; Py_INCREF (Py_None); return Py_None; } // Set the preamp gain; called from the GUI thread. static PyObject * gain_sdriq(PyObject * self, PyObject * args) // Called from GUI thread { // gstate == 0: Gain must be 0, -10, -20, or -30 // gstate == 1: Attenuator is on and gain is 0 to 127 (7 bits) // gstate == 2: Attenuator is off and gain is 0 to 127 (7 bits) if (!PyArg_ParseTuple (args, "ii", &sdriq_gstate, &sdriq_gain)) return NULL; Py_INCREF (Py_None); return Py_None; } // Set the decimation; called from the GUI thread. static PyObject * set_decimation(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &sdriq_decimation)) return NULL; Py_INCREF (Py_None); return Py_None; } // Functions callable from Python are listed here: static PyMethodDef QuiskMethods[] = { {"open_samples", open_samples, METH_VARARGS, "Open the RfSpace SDR-IQ."}, {"close_samples", close_samples, METH_VARARGS, "Close the RfSpace SDR-IQ."}, {"freq_sdriq", freq_sdriq, METH_VARARGS, "Set the frequency of the SDR-IQ"}, {"gain_sdriq", gain_sdriq, METH_VARARGS, "Set the gain of the SDR-IQ"}, {"set_decimation", set_decimation, METH_VARARGS, "Set the decimation of the SDR-IQ"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; // Initialization, and registration of public symbol "initsdriq": PyMODINIT_FUNC initsdriq (void) { if (Py_InitModule ("sdriq", QuiskMethods) == NULL) { printf("Py_InitModule failed!\n"); return; } // Import pointers to functions and variables from module _quisk if (import_quisk_api()) { printf("Failure to import pointers from _quisk\n"); return; //Error } } quisk-3.6.11/sdriqpkg/sdriq.so0000775000175000017500000012524512164330111015635 0ustar jimjim00000000000000ELFP 4T4 (# ((.>>@/??$$Ptd$$$QtdRtd.>>GNUfD8ݵVzuh*A L !"#$%&{qX|+}y3CE)K7T$= Ѐ|$<(gD$=T$< Љ$AD$  AAA 40 AA CQxA AAh5AN dA,AA N0  CAD xANpp AA @KAA AAQ \ AA AAC ( sAN0N AB QALDAN  8"o8@  ?ooo@o?  & 6 F V f v   & 6 F `@ 5NT = s- # W]5j KlU g nk?%  ; WyN('iLB0M96.@ɼ- q4MMt0nGk0f-|fK)uf_kKf Qlq$$qlQ fKkf_uK)f-|f0kGnt0MMq4- ɼ@6.M9B0Li'N(yW ;  %?kng  UlK  j5]W #- s = TN5!ck)5FEK2 0\DKv 31 ]8A " /6%tH>/ &}!oN?,k%,6M;] -H:UDY p6V34u#}?,uUue-}zi_:r>>r_:iz}-euUu,?#}u34V6pY DUH:-] M;6,k%,?No}!&/ >Ht%6/ "A 8] 13v KD\0 2KEF5)kc!;dg" sV ;5Plo!3j-\5'n0*aw ;0<x ,9 1qHi}VEa*0( e?fQ`K,NŞ#ZYg/ݠ8u4$d=Pq TQ}gppgQ} Tq=Pd$48uݠ/gYZ#ŞN,`KfQe? (0a*EV}iHq19 ,x <0;  wa*0n'5\-j3!olP5; Vs "gd; K 6]@ YW uvq##? hm1 5I 4n v1 a C)(yg !$;B4%^8*W"lMa6$B~m7-xd 2xSS2x dx-7mB~$6Ma"lW*8^%4B;$! gy(C) a 1v n4I 5 1mh ? ##qvu WY @]6 Kh +n#'#@#p N#h# @$s# ~##p `$GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 Wzp cv"F g  0intZ8a<o$g_ Z#O##4# -#f###<#  #$!#( "#,.$#0&#4(Z#8,Z#<c.z#@2>#D3L#F\4#Go8#HgA#LJ#THK#XL#\&M#`-N%#dtPZ#hR#l  u  # B# 7Z#n  0g  0' C gZgIZ g z$,R%s(R/""Fp ! 0intZ8a<o Z(1$ }_ Z#O # #4 # - #f # # #< #  #$ !#(  "#,. $#0 &#4 (Z#8 ,Z#<c .z#@ 2>#D 3L#F\ 4#Go 8#Hg A#L J#TH K#X L#\& M#`- N%#dt PZ#h R#l  u   # B # 7 Z#  0}  0' g  0 # 0)    P jl k*# # kj# Dj E*## Ej# E*# F#  G*# G*# K2#D LP#0 M#  N#$A O#(m P#, T#0 U#4 V#8 Z#< [#@Q \#Dj ]#H! ^#L+ a#Py d#T{ f#Xh j@ #\ m#`R q'#d t*#h xS#l y_#p |?#t }K#x2 ~#|9 j# #t k#) w# *#F #[ # # # #7 # #D # # #@ 2# 0#l lC pX 9  Z %*5; @FZ[[[ lr* ** Z* Z ** Z8 OU*o*8 Ox **1 **> '4 buf #obj #len *# *#  Z# Z#  #  #  # #$  #( U #0 * 0 +  Z  Z     ]  Z  % + Z@  K Q Zk   ۩ 9 #  #  #  #  #  #  #  {#  {# {#$  #(  {#, #0 #4 #8 " #<  #@  5#D  {#H q {#L {#P v {#T 6 {#X M #\ #` ^ #d  #h #l #p #t #x #| #T # # # #G # {# k ( U  #8 # a# a# L # #\ #  # #   a#$N   ! q "#O ## $ # %a  ' (D# )o#N *z#B +#  , # - #M .  1 &2 2>DP 3\bZ||Z 4 5 6Z 7 8 c 9  :' ;39SZ <\ =' >i ? @H AjJ Bj* U   a  %? &#  '# ] (Z# R *#  E   #get #set #doc # Y #Q a ,  Z700 ~< '#  '# i !'#  "'# ## $# %#4 &#8  0  0 z|> u ?# 8@# AZ# D BZ# CZ# zDZ# |E0# }F0#  G0# pH0# IZ# JZ# SKZ# LZ# ` MZ# NZ# rOZ# X P#  Q# S# T#  U# VZ# @ WZ# dXZ# YZ# ZZ# [Z# \<#H   ^Z# dZ# l Z# yZ#  Z# 4  Z#  # Z 0vQv vv%7##Z# #%<sZbufsbsZresuZ *Z **Z< % `?``% Zrbuft ZresZ11 1#1% &Z6Z7ݤ!t Zbuf  0?"  K&Z6Z7!t Zbuf#~$) Z$Z%buf~  0 A >Z__s>__n>%>#E &<&<C gZ g#pJ$ p'bufp$bpZ&r2#f $ 'buf$bZ&l%iZ&Z (0)tTp P*T* T)H  (*H* H)-? g d*?* ?)) p ** + Q `',,-P.Q  y,z,o,d/6 E s06 E 122 K&ZKQ73Z` 1(44 4Z5kZ5resZ6&Z6 Z.6Z5iiS5qqSH7~8bufQ96ZQ9" ZQ9ZQ9t ZQ9&ZQ9ZQ:';'En,?,4 7 0 7<0=@,>) Z>Z?iZ;KQ(2e2Y@H-q`;?nhAP`B[ @-fPC?r,[,P0Df+0,8,KAD-E?N,[,P@-fPC?r,[,P0Df>.څ011222/r,Q,q,=)FbufdGZ=4' Fbufn # 0=@ @w Z?iZ ?ptZ == 2! G1 Z 9/ } (0+@u HXp)Z} :* Gt Zb ;@D -Q+ , I4-?B)B.?APB[0-fPC?r,[ ,P 0Df- /0141?2)22) )[!@ *)* )G + Fbuf,~;Je(7,d ,X @H-|vD1 DE ,p J ehq ,% , @-=,1 K , , JuC , , C !, ,),<CZ,R,h,L g`!!75<Q7!7ZQ7r8ZQ 079 Q7) : R7;ZR7 Z$R7I?ZQ7@ZQ7w AZP7>AZQ7BZP7-CZQ7sCZQ7jCZQ7}DZQ7arZQ " 09] " QMMNb FpMe`"M8Oq LOv#HO <DOS@% : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I.? : ; ' I 4 : ; I.? : ; ' I@< 4: ; I? < 4: ; I?  % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I&' II : ; I8 '  : ; : ;I : ;<  : ; .? : ; ' I 4 : ; I.: ; ' I : ; I4: ; I.? : ; ' 4  .: ; ' !4: ; I".: ;' #.: ;' $: ;I%4: ;I&4: ;I': ;I(!I/).: ;' I@*: ;I +.1@,1-41 .1X Y /1X Y 0 141213.: ; ' I@4: ; I54: ; I64: ; I74: ; I 84: ; I 94: ;I : : ;;1RUX Y: ;I?4: ;I@ UA1 B1 C1X YD41E1RUX Y F4: ;I G4: ;IH1X YI41 J1RUX YK1X YL.? : ;' @M4: ; I? < N4: ;I? < O4: ; I?   /usr/include/i386-linux-gnu/bits/usr/lib/gcc/i686-linux-gnu/4.6/include/usr/includeimport_quisk_api.cstdio2.hstddef.htypes.hlibio.hstdio.h -/2/XeR sdriqpkg/usr/include/i386-linux-gnu/bits/usr/lib/gcc/i686-linux-gnu/4.6/include/usr/include/usr/include/python2.7.sdriq.cunistd.hstring3.hfcntl2.hstdio2.hstddef.htypes.hstdio.hlibio.hpyport.hobject.hmethodobject.hdescrobject.htermios.hquisk.hsdriq.hp -L/o*-L/oX-L/SY-L/z.*Qzw+YJfgeuZ s. f/Y7fRGKgg/;=;/-gl ̃]G)ka ~փMׄ]ZkfY. r.X;gigr":Wg tt t. t伟hd/eg/~XJ~f;vvV?;u <uJ.-gqXɏYirvPx䭟䑃gf;!uZ=-gYש~[#;Y~Xu-ggyb&~ Xt~X.fLX:gIguWjKvYKY}JflO<}6.JX5<Kt5f0YYYY[xE{( Krt YXJJJ J-~f/i~<{-gfuu#rXYW&WLK0:?KGM!&đ{f<zt"z<XXy<{f.gl{tX{Jfg7#{fztz<8fzt|.Jz<XX|0z<{fzt{.Jz<X/4yyfimport_quisk_api__fmt_IO_read_end_IO_FILE_IO_write_base_IO_buf_end__pad2_IO_read_ptr_shortbuf_IO_write_ptr_modesound_conf_chainQuisk_APIlong long unsigned int_IO_save_baseunsigned charpt_quisk_sound_stateimport_quisk_api.cshort unsigned intstdin_IO_save_end_IO_lock_tGNU C 4.6.3_markers_pos__off64_t/home/jim/pub/quisk__quad_t_old_offset_lock_IO_marker_cur_column_fileno_IO_buf_base_flags2_next_vtable_offsetlong double__off_t_unused2long long intstdout_IO_write_endshort int_IO_backup_base__pad1__pad3__pad4__pad5_IO_read_base_sbufnewfunc_objectbinaryfuncreprfuncbuf1024set_decimationnb_inplace_powersample_countformatPyGetSetDefsetattrofuncselftp_deallocnb_inplace_xorreadonlytp_as_mappingsdr_interfacesdr_namebf_releasebufferupdate_itemtp_as_bufferdev_play_nametp_initbf_getsegcountobjobjproctp_traversetp_descr_getlenfuncnb_invertc_oflagstridessetattrfuncshapetp_weaklistcoefmic_dev_namegetattrfuncnb_nonzeroml_methdestructortp_weaklistoffset__oflagsq_itemsdriqpkg/sdriq.ctp_getattrcoerciontp_cachenb_inplace_addsq_ass_slicedescrsetfuncdec500cur_decimationnb_inplace_floor_dividebf_getwritebuffer__lennb_orsdriq_freqsmalltablenb_inplace_remainderbuf128nb_multiplymic_out_volumestrncpyinitprochashfunctp_descr_setireadstrncattp_printPyBufferProcstp_alloctx_audio_portsdr_naklatency_millisecsc_ispeednb_positivereleasebufferproc__destvaluecc_t__bufreadbufferprocsdr_statusmic_read_errortp_hashmic_sample_rate__nbytestp_iternexttp_setattrocur_freqnparamssdriq_gainsdr_idletp_richcomparequisk_sdriq_fdchan_maxScic2Scic5sdr_recvwset_ad6620ssizessizeargfuncmic_channel_Itime0gettertp_mromic_channel_Qsdriq_clocknb_coercetp_subclassesstart_herePy_ssize_tspeed_tsampsizebufferinfotp_getsetReadtp_comparesq_sliceinternalMcic2Mcic5tp_getattronb_octrate_maxnSamplessq_inplace_concatdatanb_negativenb_powerQuiskMethodsquisk_read_sdriqnb_inplace_rshifttp_iterwritebufferproc_typeobjectnb_inplace_dividesdr_ackset_freq_sdriqsq_concatbf_getcharbufferunderrun_errorbufsizecur_gaincur_gstatetermiosnewtiodec1250write_errorname_of_mic_playvisitprocPyMappingMethodstp_membersset_gain_sdriq__fdinquirynb_remainderPyObjectnb_rshiftchan_minnb_dividedescrgetfuncsamptp_basesnprintfallocfuncnb_inplace_or_Py_NoneStructmp_lengthtp_doctp_methodsPyCFunctionnb_andsdr_bootcodetp_itemsizeobjobjargprocsetterc_linedec600cSamplesnb_true_dividetp_basicsizeargs__ssize_tnb_floor_dividebf_getreadbuffercharbufferprocprogram_ad6620mp_subscriptiternextfuncc_cflagnb_longtp_flagsinitsdriqob_sizesq_lengthnb_inplace_subtractget_itemtp_call__pathcomplex doublelatencyPlayml_nametp_freendimob_refcnttp_version_tagc_lflagmic_ipiwriteclose_samplestp_basesmic_playback_rateml_docclosurePyMethodDeftp_reprdev_capt_namesq_containsoverrangesq_ass_itemopen_samplesfreefuncdata_poll_usecPy_bufferc_iflagmp_ass_subscriptWriteopennb_floatnb_interr_msgquisk_start_sdriqnb_xoraddressmsecnb_hexquisk_stop_sdriqPySequenceMethodslatencyCaptMrcfdec360segcountprocPyMemberDefPyNumberMethodsbzeronb_inplace_lshifttp_is_gcnb_indextp_as_sequence__srctraverseproctp_dictoffsettp_dictprintfuncsdr_firmwarenb_inplace_andsdr_serialSoutternaryfuncWaitForPolltp_strmsg1ml_flagsquisk_open_sdriqsdriq_gstatenavailsuboffsetsgetattrofunctp_clearrichcmpfunctp_as_numbertp_namec_ospeedbf_getbuffertp_newnb_lshiftnb_absolutenb_divmodsq_inplace_repeatmemcpyob_typegetbufferprocnb_addtp_delnb_inplace_true_dividenb_inplace_multiplyinteruptsrate_minset_itemc_cctp_setattrsq_repeattimernb_subtractunaryfuncquisk_open_sdriq_devsdriq_decimationssizessizeobjargproctcflag_tgetiterfunctt@t @AtABtBWt ttCt CFtFGtPQtQ_t_t ttttt tttt`t `ctcdtpstst tt tp{P{QpRRQQVVttt tt t t t t t  t tP ~7R7 ~9JRsR+4R4XVhmRRR0R? E Va g VVbP PB^PyPPP? G Pa m P^PW  P ? WX a Wt W}RRRRS RR R0~0? ~? X 0X a ~a t 0t ~UUS~xUU U ~U,W,S~W U W~4 ? ~X a ~t ~W4 ? WX a Wt W t t t t t0 t t t t t0 P  Ro | 0: [ 9: [ `R [ P t n tn p tp t  P  R g v|o R v| g Vo V R V V % % 4 P4 R  ! ? V! % % 4 P4 ? 5 ? Po R v|o o  t t  t0  t  t ! t0 Q R R r8&0 1 t1 ? t? t0 t t t0 t t t tt tt0t$&06VW%0@01t12t25t 5FtFttt tt0N0v~Vttt tttt t t0t tt t0PVVMS[tttttt&PLm4LmdmPttt ttt ttt ttt *PT~~Tv+Pxz0;@v@JRP\R\ar8&Ttvt   Q +PzwzPz~~"ttMt0MNtNPtPat0abtbct4 ? X a t    " o    " o  " % 8 V  " % 8 V  ?  ? chkrx  chkrx TTTT@V,24.symtab.strtab.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.ctors.dtors.jcr.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_str.debug_loc.debug_ranges$.o888 p@@@Ho@@NUod m  v.q|P P 8"8"X"X"H$$L%L%h>.>.?/?/?/(?/h`@`0  QA 0A*A@A6& h4Tm0)u&=1:?̛"h 8@@  P  8" X" $L%>>????`@Q >>(?5P  KQZQh  t>(?" p G P Q QP G Q%p d 3QBQK q P`  YQeQrQ|QQQQQQ$RRRRQ R @ 0  .Q7 FQQQZ@` iQx @5  Q K Q Q`J  q K      ->:`@G?P! g?}Q8"  "'8M]q (R`!s *0R/K\oQ{ H@D W L,R crtstuff.c__CTOR_LIST____DTOR_LIST____JCR_LIST____do_global_dtors_auxcompleted.6159dtor_idx.6161frame_dummy__CTOR_END____FRAME_END____JCR_END____do_global_ctors_auximport_quisk_api.csdriq.cset_decimationsdriq_decimationgain_sdriqsdriq_gainsdriq_gstatefreq_sdriqsdriq_freqclose_samplesquisk_sdriq_fdsdr_idleReadsdr_recviread.11234iwrite.11235buf.11233state.11236length.11237type.11238sdr_naksample_count.11239sdr_acksdr_statussdr_firmwaresdr_interfacesdr_serialsdr_namesdr_bootcodewset_ad6620set_itemset_freq_sdriqcur_freqset_gain_sdriqcur_gstatecur_gainprogram_ad6620cur_decimationquisk_stop_sdriqquisk_start_sdriqquisk_read_sdriqtime0.11326get_item.constprop.6open_samplessdriq_clockQuiskMethods.L93.L56.L57.L58.L59.L60.L61__i686.get_pc_thunk.bx__DTOR_END____dso_handle_DYNAMIC__stack_chk_fail_local_GLOBAL_OFFSET_TABLE___snprintf_chk@@GLIBC_2.3.4read@@GLIBC_2.0tcflush@@GLIBC_2.0_edatacfsetospeed@@GLIBC_2.0_fini__stack_chk_fail@@GLIBC_2.4Py_InitModule4__cxa_finalize@@GLIBC_2.1.3PyCapsule_Importtcsetattr@@GLIBC_2.0puts@@GLIBC_2.0PyString_FromStringstrerror@@GLIBC_2.0__memcpy_chk@@GLIBC_2.3.4__gmon_start__pt_quisk_sound_statewrite@@GLIBC_2.0cfsetispeed@@GLIBC_2.0initsdriqopen64@@GLIBC_2.2_Py_NoneStructsnprintf@@GLIBC_2.0_end__errno_location@@GLIBC_2.0PyArg_ParseTuplestrncpy@@GLIBC_2.0__bss_start_Jv_RegisterClassesdec500dec1250dec600import_quisk_api__strncat_chk@@GLIBC_2.3.4dec360Quisk_API_initclose@@GLIBC_2.0quisk-3.6.11/sdriqpkg/__init__.py0000644000175000017500000000000211632372230016242 0ustar jimjim00000000000000# quisk-3.6.11/docs.html0000644000175000017500000000054611632372224014143 0ustar jimjim00000000000000 Documentation file for Quisk quisk-3.6.11/winsound.txt0000644000175000017500000000131511632372224014727 0ustar jimjim00000000000000August 2010 Microsoft Sound Access Microsoft introduced "Windows Core Audio" and "Media Foundation" with Vista. Core Audio is a low level API useful for pro audio apps. Most sound apps would use either Direct Sound or Media Foundation; these use Core Audio for sound card access. Microsoft does not plan to make Core Audio available for Windows XP. Media Foundation requires Windows Vista or later. The ASIO driver by Steinberg provides low latency access to the sound card, but requires an ASIO driver on the PC. See http://www.steinberg.net/en/company/developer.html http://static.helge.net/2010/06/ASIO%20SDK%202.pdf See http://msdn.microsoft.com/en-us/library/dd370784(VS.85).aspx quisk-3.6.11/_quisk.so0000775000175000017500000107201212164330110014153 0ustar jimjim00000000000000ELF`B4( 4 (# xxh~hhop/|~||$$Ptd\\\QtdRtdh~hhGNUR UPC6F; TMQ@P@ R@(hH & H@d Yp I : 2 ((A} 1V ՟ץM~|ٰA-{' }k'RtX/x7X^g;0@Ľw]rFLy)Mk䦸prnOսB(ߠ +?&j&Ѻ{yr9,W;~X'NYCfHP?#\~9!k? 0!2A er9cl `+!iߧ-z"WA2A%XdM 7wm~N@"Cˍfgv;h{{F'qlhqX" 1}3-]c"/ +9_"ӈ_QEϠecCE[ֳ6hA#+-nBy+,"'o,Y K d } = o H  !   + 6  2  a  s\ c> cz  %e/   Q CH wA/  .$yT    { $r WY K 0 1 : Eav p tN3  62 .d GO W   B 3 RS  n #'  F"    \) }(  x~@/ 7a15a1J@^1|@+ \ ;C 7 6`X  G( F h(o I6   96   P.U jc  ?4^1$@* 2@* 4 ?' 1 . @h  $|  N    fpc   b  ,^13  \(^12  @( XZ@n7 r)a B W: 0^1  .  $^1 p0 +8   u H8/ ^1< p  +0 p)' @3 pN '1 N c: B 9 N  \ 0, $  ^1* nS a1 a1x   =" __gmon_start___init_fini__cxa_finalize_Jv_RegisterClassesdata_widthquisk_sound_staterxModePyArg_ParseTuple_Py_NoneStructquisk_tx_tune_freqquisk_audioVolumequisk_noise_blankerquisk_set_key_downshutdownsendQuiskSleepMicrosecquisk_using_udpquisk_open_keyPyInt_FromLongquisk_mixer_setPyString_FromStringquisk_start_soundPyEval_SaveThreadquisk_read_soundPyEval_RestoreThreadquisk_close_micquisk_close_soundquisk_close_keycexpquisk_set_tx_modequisk_record_stateQuiskGetConfigDoublePySequence_CheckPySequence_SizePySequence_GetItemPyFloat_AsDoublePyErr_SetString__snprintf_chk__memcpy_chkquisk_cDecim2HB45fftw_executecabsmemsetfftw_mallocfftw_plan_dft_1dcosPyFloat_FromDoublequisk_get_overrangelog10PyTuple_NewPyTuple_SetItemfftw_destroy_planfftw_freePyComplex_FromDoublesmic_max_displayPy_BuildValuequisk_is_key_downPyFloat_TypePyType_IsSubtypePyInt_AsLongPyComplex_TypePyComplex_AsCComplexPyList_NewPyComplex_FromCComplexPyList_SetItemputsquisk_cDecimatequiskFilt111D2Coefsquisk_filt_cInitquiskFilt53D1CoefsquiskFilt133D2CoefsquiskFilt167D3CoefsquiskFilt185D3CoefsquiskFilt240D5CoefsquiskFilt240D5CoefsSharpquiskFilt48dec24Coefssocketsetsockoptinet_atonconnect__sprintf_chkfftw_plan_dft_r2c_1dfftw_plan_dft_c2r_1dquisk_sidetoneCtrlquisk_dInterpolateatan2quisk_dDecimatequisk_dFilterquisk_dInterp2HB45quiskAudio24p3Coefsquisk_filt_dInitquiskAudio24p4CoefsquiskAudio24p6CoefsquiskAudioFmHpCoefsquisk_mainwin_handlequisk_pyConfigstrncpyQuiskGetConfigIntquisk_mic_preemphasisquisk_mic_clipquisk_open_soundquisk_open_micquisk_tmp_microphonequisk_process_samplesmemcpyquisk_cInterp2HB45realloc__printf_chkquisk_extern_demodquisk_read_rx_udp__fdelt_chkselectrecvinit_quiskPy_InitModule4PyErr_NewExceptionPyModule_AddObjectPyCapsule_Newquisk_get_tx_filterquisk_set_ampl_phasequisk_set_file_recordquisk_set_spot_levelquisk_sound_devicesquisk_sound_errorsquisk_capt_channelsquisk_play_channelsquisk_micplay_channelsQuiskGetConfigStringQuiskTimeSecQuiskPrintTimequisk_sample_sourcefopen64fwritefclosefseekPyList_Appendptimerquisk_play_portaudioquisk_read_portaudioquisk_process_microphonequisk_cInterpolatequisk_play_alsaquisk_read_alsaquiskFilt12_19Coefsquisk_close_sound_portaudioquisk_close_sound_alsaquisk_start_sound_portaudioquisk_start_sound_alsatansnd_ctl_card_info_sizeofsnd_pcm_info_sizeofsnd_card_nextsnd_ctl_opensnd_ctl_card_infosnd_ctl_pcm_next_devicesnd_pcm_info_set_devicesnd_pcm_info_set_subdevicesnd_pcm_info_set_streamsnd_ctl_card_info_get_namesnd_ctl_card_info_get_idsnd_ctl_pcm_infosnd_pcm_info_get_namesnd_pcm_info_get_idstrstrsnd_ctl_closesnd_strerrorsnd_pcm_hw_params_test_formatstrlensnd_pcm_hw_params_set_formatsnd_pcm_statesnd_pcm_delaysnd_pcm_readisnd_pcm_preparesnd_pcm_startsnd_pcm_writeisnd_pcm_opensnd_pcm_sw_params_mallocsnd_pcm_hw_params_mallocsnd_pcm_hw_params_anysnd_pcm_hw_params_get_rate_minsnd_pcm_hw_params_get_rate_maxsnd_pcm_hw_params_get_channels_minsnd_pcm_hw_params_get_channels_maxsnd_pcm_hw_params_set_ratesnd_pcm_hw_params_set_accesssnd_pcm_hw_params_set_channelssnd_pcm_hw_params_set_buffer_size_nearsnd_pcm_hw_paramssnd_pcm_sw_params_currentsnd_pcm_sw_params_set_start_thresholdsnd_pcm_sw_paramssnd_pcm_hw_params_freesnd_pcm_sw_params_freesnprintfsnd_pcm_dropsnd_pcm_closesnd_ctl_elem_info_sizeofsnd_ctl_elem_id_sizeofsnd_ctl_elem_value_sizeofsnd_ctl_elem_id_set_interfacesnd_ctl_elem_id_set_numidsnd_ctl_elem_info_set_idsnd_ctl_elem_infosnd_ctl_elem_info_get_idsnd_ctl_elem_info_get_typesnd_ctl_elem_value_set_idsnd_ctl_elem_writesnd_ctl_elem_info_get_minsnd_ctl_elem_info_get_maxsnd_ctl_elem_value_set_integersnd_ctl_elem_value_set_booleansnd_ctl_elem_info_get_min64snd_ctl_elem_info_get_max64snd_ctl_elem_value_set_integer64Pa_GetDeviceCountPa_GetDeviceInfoPa_GetDefaultOutputDevicePa_GetDefaultInputDevicestrtolPa_IsFormatSupportedPa_OpenStreamPa_GetStreamWriteAvailablePa_GetErrorTextPa_GetStreamReadAvailablePa_ReadStreamPa_WriteStreamPa_InitializePa_StartStreamPa_IsStreamStoppedPa_Terminate__ctype_b_locioctlbindperrorgettimeofdayquisk_dC_outquiskMicFilt48Coefsquisk_filt_tunequiskMicFilt8CoefsquiskLpFilt48CoefsPyErr_OccurredPyObject_GetAttrStringPyInt_AsUnsignedLongMaskPyErr_ClearPyString_AsStringnanosleepmemmovequiskAudio96CoefsquiskAudio48p6CoefsquiskFilt53D2CoefsquiskFilt111D4CoefsquiskFilt133D5CoefsquiskFilt185D7CoefsquiskFilt185D3XCoefslibasound.so.2libportaudio.so.2libfftw3.so.3libm.so.6libpthread.so.0libc.so.6__stack_chk_fail_edata__bss_start_endGLIBC_2.0GLIBC_2.1GLIBC_2.15GLIBC_2.1.3GLIBC_2.4GLIBC_2.3GLIBC_2.3.4GLIBC_2.2ALSA_0.9.0rc4ALSA_0.9        0ii <ii F Psi [ii gii qii Fti {ii <0ii ii < y'w@DLPT\`dlpt|ē̓Гԓܓ  $,04<@DLPT\`dlpt|Ĕ̔ДԔܔ  $,04<@DLPT\`dlpt|ĕ̕Еԕܕ  $,04<@DLPT\Ȗ̖Жdhlptx|%9sďȏ̏Џԏ؏܏   $ ( , 0 48<@DHLPTX\`dhlptx |!"#$&'()*+,-./0123Đ4Ȑ5̐6А7Ԑ8ؐ:ܐ;<=>?@ABCDEF GHIJK L$M(N,O0P4Q8R<S@TDUHVLWPXTYXZ\[`\d]h^l_p`taxb|cdefghijklmnopqrtuđvȑw̑xБyԑzؑ{ܑ|}~  $(,048<@DHLPTX\`dhlptx|S[WtU { [ hhhhh h($h0(h8p,h@`0hHP4hP@8hX0<h` @hhDhpHhxLhPhThXh\h`hdhhhplh`phPth@xh0|h hhhhhhhh h(h0h8ph@`hHPhP@hX0h` hhhphxhhhhhhhhph`hPh@h0h hhh hhhhh  h($h0(h8p,h@`0hHP4hP@8hX0<h` @hhDhpHhxLhPhThXh\h`hdhhhplh`phPth@xh0|h hhhhhhhh h(h0h8ph@`hHPhP@hX0h` hhhphxhhhhhhhhph`hPh@h0h hhh hhhhh  h($h0(h8p,h@`0hHP4hP@8hX0<h` @hhDhpHhxLhPhThXh\h`hdhhhplh`phPth@xh0|h hhhhhUVSÊM nu]t$,n|)9s n|n9rƃ n[^]US. Mtt $Ѓ[]Ë$ÐWVSL|$iL$D$T$ f$D$D$t$D$ʉ|$D$ك,$\$l$T$x9({@݃t~1[^_Ít&9}ԋl~t&у9zu؃[^_fvK D$D$݁\فw݁dt&ɉD$D$ۀܱD~у8t}L~u;݁d~r&fك Í݁T~܉\~عs Íعrك Í&'SJ~D$ D$tD$D$$$1҅t/ݛ~ǃ|~ƒ[Ít&'SqNJ\nD$-D$D$$$11҅t ƒ[É'S!ID$D$$$1҅t ƒ[ÍvSþID$D$$$1҅t ƒ[ÍvS~ID$D$$$k1҅t ƒ[ÍvSa>ID$ nD$tD$D$$$1҅t ƒ[ SHXnD$-D$D$$$1҅t ƒ[É'SÎHpD$D$D$$$q1҅t ƒ[É'Sa>HD$-D$D$$$!1҅t ƒ[É'SGt~D$D$D$$$1҅t ƒ[É'SÞG(D~D$\~D$ L~D$ D$D$4$m1҅t ƒ([Ðt&Sa>G(~D$~D$ ~D$D$D$4$ 1҅t݃~ݛ~([Í&SFnD$-D$D$$$1҅t ƒ[É'S~FD$D$$$k1҅t ƒ[ÍvSa>F(D$D$-D$D$4$#1҅tD$$ƒ([ ,\$ Et$$|$(fD$ssD$D$4$1҅$tv|$D$4$D$ D$|$4$T$D$ D$|$$2$-$$ǃ$ǃ~u ‰Ћ\$ t$$|$(,ÍvSD(D$D$hD$D$4$1tD$$$([fSÎD(D$D$-D$D$4$s1tD$$:([Ðt&VS`=De$1D$(D$D$8D$ D$4D$D$$$1t4D$8t$>uf1fD}$D}\$$܄>ݜ>uӋn9D$4 $`fp$`ǃ{I$`i{.)Ǹ[)9݃|1v ىv؃9~؍,.L$كL$`܃ǃ~ݛ$ۃ~$>\$Xۃn$,T$`D$X܃؋\$X~V1f~$l~؋d$Xك$t$<$D$9unE~1ƒ9n؁[^_]ݜ$L$X݄$܃D$`٬$\$d٬$T$dD;D$`.݃ ɋT$X1D$X\$pt$xȉL$l$Ɖl$|ՉL$hMFT$ɋT$hT$Ƀ\$ \$\$0$|;|$dD$0܄$D$XyEE멋ǃ(T$`$L$`)Dž~51@\$$pl$<$D$=T$`9*F [^_]Ãt8n$ۄ$؃n$ۄ$؃VL$dt$xl$|L$XD$pT$XD$XxnD$l@T$ɋD$hT$\$ \$\$@\$0$!D$dD$@܌$D$0ݛ 2$4؋ D$l@ɋ$T$hD$l^SXD$dzW+tT$$G1T$DT$@nT$<8T$84T$40T$0(T$,$T$( D$T$$T$ <T$T$T$T$ T$D$e$-X[Ð&S^*D$D$$$K1t .$[ÐUWVS>*lD$@T$H$~D$@$yD$409D$4c~8$$ $ $D$40$D$D$ D$D$0$@D$D$ D$D$0$0$ʼn D$4D$4D$Dx~D$41D$4\$8|t$LD$L݃lt$8$\$ D$ ܋t$8$\$ D$ ܋܃܋\9t$D}D$41D$8t&F;$T$F@Vc4$D$LD$Lʍt&9|$4XNtl;l$4tuD$@|$$ Ƌ@;t$T$\DD$Pt$$DD$X؋D$Plt&F4$P;l$4uD$H:$t<0~2 1ҋ&փHX9u㋃$0 $Nj0~|11|$@t$8t&@\$PD$P\$X$D$TD$D$XD$D$\D$ ,t$D$D$@$9t$4N90|$@l[^_]Ðt&4$=t&tD$~1$l[^_]Ít&$$0uV1D$4t&@X9u҉u4$Pi 1ҋD$4փHX9uk$&Sa>%(D$D$ D$D$D$wD$D$4$1tD$$D$([ÐS$(D$D$ D$D$D$wD$D$4$1tD$1҉$D$i([Ít&<\$,x$t$0։|$4ljl$8&D$Pv 1Ƀ L$Mbǃnid)~b5 ̹$\$,t$0|$4l$8t&$Ƀ$ ꃃ<~أ<݃~كP݃$~܋݃4~܋D݃~ܳL܋ ~܋~܋܋,~܋D܋}ܳLXܬ$ݛ݃~$݃$~$݃,~$݃4~$݃}$݃~;|$x$EE$݃w݃4r,$݄$\$\$T$$ ݃كLXكTwq$݃~$݃$~$݃,~$݃4~$݃}$݃~أݛ4\$D$$]݃j$ۃnܴ$ټ$$ f$؃٬$ۜ$٬$$݄ݜ$ۃ$ػɉ,$ܻ\$\$ \1݄$ݜ$$ ݄$ݜ$݃ ݃݃ݔ$݃ݔ$$‰݄$݄$؋,$\$\$ \$@\$`\$P\$0賎D$0\$D$P\$݄$\$ ݄$\$,$蒒݄$G܄$_݄$\$݄$\$݄$\$ D$x\$,$C݄$ݜ$݄$ݜ$D$`\$D$@\$݄$\$ ݄$\$,$;$݄$݄$݄$ݛ$݄$ݛݛݛ jۇۇ$ t$$\$Og;ǃ{ǃǃD)Љl$(D$D$($z,$D$D$D$(D$ |D$D$$dzD$($,$D$ D$D$x|D$D$$zvf1퍴&ك|$D$D$D$ fD$l$\$,l$D$ D$,${9uft$(D$($|$.D$D$D$ 4${D$D$D$ l${D$D$D$ q$a{D$(D$D$D$ 4$7{fD$.D$D$D$ <${fD$.D$D$D$ <$zD$D$4$D$(D$ zd$(D$D$ D$4$zfD$.D$D$D$ <$jzfD$.D$D$D$ <$AzD$D$D$ {$zD$(D$D$D$ 4$yǃǃx,\$$t$(u~R8tJT$T$D$D$0T$ D$$y4$D$Iz\$$t$(,Í'UWVS}~P1ɍLv΃9э|5܈G܈݀ݜLݜTu[^_]Ð&VS}m~;tY;t [^ÍуLL݀ݘt&Au[^ÍL뻍<\$0|t$4|$8,4MbD$@0≋4i9t\$0t$4|$8<Ðse01|$$$T$ T$|$.كD$. fD$,l$,\$(l$.D$(+,l$ ɉD$(D$ dD$D$(\$r\$0t$4|$8<Ðdt$4|$8|$.؋D$. fD$,l$,ۛ,l$.\$0<Í&D$8D$<D$ @ÍUWVS{{8@L,$Љ$$ɉ0m $,$D$Ƌp\$D$ l$t$ $eBA  LIl1\T$xt"l$l$C@Ƌx8P ~T$xt$l$$[Ƌ,?ݓL$ݛTۃ\؋D<$܋,\$\$ p݄$ݜ$݄$ݜ$mI\v )ƒ~*llt$T$ D$,$gƅ艴$$݂t\$x݃݃Սt&T$T$G\$ \$\$0\$`4$ t݄$D$x܌$L$x_D$0\$D$`\$݄$\$ ݄$\$4$s9݄$݄$mɋ$ݛ$ݛpx 򍃬8t 򍃬4$荃\$D$ l$t$$y?$ļ[^_]Í&1ǃ&L1ǃL݃݃P9u&1l$ T$x$E<&4݃\$D$ l$t$$B>̜LDŽ$ Ԝl$L$N<$x$L؜$L6$ۃ\؋D<$܋,\$\$ \$0l݄$\$x݄$ݜ$ۄ$D$0ۀ܃LݛLbE݃LG1݃T\ݔ$$݂t݃݃v$ۄ$܋ػݔ$ݔ$ÉɃ<$ݜLݜT\$\$݄$\$ D$x\$\$0\$P\$@o݄$݄$D$0D$PD$@*؋A1݃T\$݂t݃݃؋ÉɃ<$ݜLݜT\$\$݄$\$ D$x\$\$0\$P\$@\$`n݄$݄$D$0D$PD$@D$`R͉$ۄ$܋w؋كƋx8}t$,$l݄$ݛTʋ$ݛݛݛL4ݛTʋ$ݛݛݛL LvL 1ǃ10iǃLZ荃\$D$ l$t$$UKyL,$F$,$"$D$pT$tD$@L$\T$tD$p1'ǁ,ǂ,Í&'Spν<t`<D$$()ȳD$D$$Sg[Í&'WVSp\ Ldž dž$dž(džhdž8dždždždžƆ<ƆD$t$$fD$ D$$f<D$lD$$afD$D$$Af`\\l(p|$,$cWD$D$ $eǃǃȥǃ̥|$$WD$D$$e$݃\$GV ǃhǃl\ǃdݛD$9L‹̟ȟ9L‹,ğ(9L‹l$h9L‹̥dȥ9Lƒĥ$TD$$Tp@'ƃLۆ܋TD$|$ǃ8ǃ؟D$D$ǃx fD$ǃ؃ǃ<ǃإǃܥǃxl$\$l$D$ H?Iȸƒ9OMb\)ܟi\)|)| [^_Í&\$klHt$|$8tЍ|$4$5|$4$@tL \$t$|$ÍuDHLP\$t$|$Í&'VSpkMtD$lD$D$`D$ D$XD$D$$$c1҅L$lD$XLD$`ʅD سdž܋ݖ$\$@\$ \$0hD$0ݞD$@$dD$ ݞƒt[^Ðt&zrldž&SAj D$ D$tD$D$$$a1҅t ƒ[fSiζ̟D$ D$tD$D$$$a1҅t ƒ[fSi~lD$ D$tD$D$$$Za1҅t ƒ[fV1SNi+D$D$$$a$gƍ$L|$lf $ P%$ :6$$L$[^ÍSh^(D$D$ D$D$D$D$4$;`1҅t,D$tD~rt%fu ǃƒ([fǃD$D$D$ $^봐t&uD$D$D$l$f^뀐UWVSgi`UXeE1\d)čT$3djddD$$D$ ^c)ct$3D$4$D$]xDžx$;dx}P TPD$ED$dD$T$ $4dUtD$T$$G]dtT$$b Dž|t&|D$t$](|:D$4$&_D$4$Vd`4$T$tcd$]t8ud$=^Njtt$$[i4$Zt8u 4$6[‹Xtr|T$L|$D$ xD$ dD$D$dD$D$E$bE$^D$X$.aL\T$U$|$D$D$ dD$D$db\E$T$`h|\D$ D$D$x$D$D$D$4bt$\Ue3=e[^_]Ð$7^$D$ xD$HD$ZT$`|t&t$j\x$ axHx1Rv$]$D$ xD$D$Yf$b`1 v$J`1$K]$D$ xD$D$Yt$[:_b UWVSb÷, ǀD$,$D$`YD$ |$$\D$u",,$T\S32 @D$ |$$~\D$|$$\\<D$|$$:\D$ |$$\u),$[S24_@3LE @D$|$$[u",$g[S16 @D$|$$[|$D$|$D$$`D$,[^_]É,$[U32 @&,$ZU24 @&,$ZS24 @&,$ZU16 @|$[,$ZE*UNSEUPPOERTEDE D$,[^_]f,$PZfD*džD$f,$(ZfD*džD$ f,$ZfD*džD$ ,fUWVS1D$0T$xL$>|$ fL$<&ɃD$ l$<\$8l$>|$8|$HBl$<\$8l$>L$8ʼṉ#L$Llj̱#L$ 9L$t؋|$tT$(+|$$T$|$$RT$$…~S9T$t1T$$ (\$$OD$DD$ D$0$$OT$(|$T$$;RT$$U gfff)9D$tD$x@ɋD$tD$tl$tD$xXl$D9D$tD$$T$(\$0t&L$$19L$t|$>كL$ 1T$xL$>D$0 fL$<&ɃD$ l$<\$8l$>|$8|$HBl$<\$8l$>L$8fkL$Lf{L$ 9L$t؋|$t+|$$T$(|$T$$PT$$…~9T$t1T$$$$MT$(|$T$${PT$$똍vD$DD$\$$OL$DL$ D$D$DD$\$$OD$DD$ D$(N9D$tD$$L C\$(l$$9l$tB|$>ك,1T$xl$>D$(T$ fT$Bl$<\$Ll$>9L$IfML$KML$MōlmfML$OMrf؋l$t+l$$|$l$$nNT$$…~9T$tT$$ytH$$YKl$|$$NsT$$럋(붋(qt&,\$[T8t$ 1|$$l$(D$D$4$Lte$R$R$R|$4$ Pl$4$P$A1҉$1\$t$ |$$l$(,Ít&'UWVSS{$$D$@D$D$,e$1 'T$($HJǃ#SvD$((D$(uዅy׀}tѹ#+t$\ED$D$4$I114$-D$XD$ D$t$$JD$XD$P$G_D$L$ OD$LD$D$X$GD$D$Lt$Dt$$Lt DžD$D$Lt$$!Ht DžD$D$L$Ht DžD$D$L$Nt DžD$LD$ D$D$Xt$$HD$LD$D$D$X$MD$HD$D$L$GD$HD$D$LD$D$X$M0T$L$FiMbD$TD$D$L)D$D$XT$T$N8D$TD$LD$D$X$HD$PD$D$X$O9~Ѝ gfff)D$PD$D$X)ʉT$$`O6D$PD$D$X$H<D$X$F?D$L$ND$P$Nu}k#t$\ED$D$4$SF14$D$DD$ D$t$$dGD$DD$L$D&D$P$KD$PD$D$D$DD$D$Pt$Xt$$It DžD$D$Pt$$Dt DžD$D$P$Dt DžD$D$P$Jt DžT$PD$ D$<$DD$PD$ D$D$Dt$$RE D$PD$D$D$D$nJD$TD$D$P$DD$TD$D$PD$D$D$JiMbD$HD$D$P)ʉD$D$DT$H$Kt$0D$HD$0ۂ܋T|$6T$6ɶ fT$4كl$4\$0l$6T$0R9v61҉D$8T$HL$D$1BH$C@LT$ƋD$9 @D$ED$ D$T$4D$$%BDD$L+$BmL+$H$:TD$)ۅTTۅT܍8ٽRR ܃$fPD٭P\$٭R$91҉4$Nك݅82DD$D$$tAZ&H$j8ƋH$ZATD$)ۅTTۅT܍8ٽRR ܃$fP٭P۝T٭RTD$‹DT$ $!9t&@D$ED$ D$T$4D$$?f$;@T$D$&DD$D$$B@(@L \$ÓT$4h<$5D$8o݃|$tݜ$D$xD$|DŽ$tdž@ dž@džl$tA$ݞ|$$\$\$4D$@D$H$T$\$ \$0$D$ D$0D$v ك`^9kؐt&\[^_]؋/D$E4$D$84$݃l1D$ \$E뫍vUWVS|y)VvD$Xh/~ D$ L/D$D$XT$$Ņ/݃T1D$T /t$X\$HD$Pt&*݃$\$\$8#D$v ًD$P\$D$ D$`$$D$`D$h $T$\$\$ "D$D$ D$HʃT$H^9ك`>܋|/D$TD$ D$`ɉ$ݛ|/\$D$`D$h$T$\$\$ F"D$D$ كT8݃݃v8݃l/ثݓ݃t/Ɖl$\D$\ۃ/ܻt*݃fس $\$\$ D$ D$ݛ~t$X1݃F$T$\$\$ \$0!D$D$ D$0v vك`^9u؋/~ D$ ,/D$D$Xl$$Ń|[^_]Íܳ l$\D$\ۃ/݃ƍt&/݃D$T /D$P/ݛۃ/݃$\$\$ \$0pD$ ݛl/D$س $R1>D$ D$ D$Tݛt/كdD$0$\$\$01>1D$ D$Pۃ/D$0$\$|[^_]Ëǃ/@\@D$Tǃ/ǃ/t$$D$]D$Pt$D$]$L/$D$t$&,/D$t$$ D$Tǃ/ǃ/D$]$t$eD$PD$]t$$MD$D$,/$.&UWVS#p|D$$$D$@E$"D$D$ D$ljD$E$LD$\E( $FƋE$6$( D$X&$( D$`D$dE~vكډ1҉L$@|$H|$X|$@t$TfT$@T$lD$l܋lD$lD$l$\$ ED$ 9؋|$Ht$TE~ 1كvE΃E9؉D$lD$lكD$Hأ |$Tv݃l\$@~Z1 $\$ \$00D$ D$0D$@vEE9؉D$lD$l؍D$HD$H݃أ i؋|$T11$#U1t&݄( ك9uػ`1GTG=( uغE\$ $UD$ ~#1݄( QU9؉\$ $ED$ ~,L$X1ҍуHX9UD$\\$ $JML$lD$lܻ|D$ \$H~u1t$@Ɖ|$Tt&؋Mك9~B$G\$D$@L$H݃s$D$@M9|$Tt$@ $>D$HD$@E9~T|$h׉t$T1D$Tك $t$D$D$@$AE9ʉt$H|$ht$T~K1҉|$Tאك $OD$D$HD$D$@$E9‹|$TD$d$D$`$4$~D$X$rD$\$f<$D$@|[^_]ك`&UWVSl$k$~\|$J1݃|$Dl$J fD$H&@Xl$H\$Ll$Jl$L9LՃ9u9/}//)/~C6t$: vl[^_]Ít&,v$Mbꋄ$)‹iҐ//ǃ/wك$݃$k$U/T$LD$Lس,~)؋`1ɃP9uؐt&l[^_]Ëx8t$ƅ~1݃ |$DfED$P؋$ك`\$\$ \$ \$0D$ D$PL$X]]9D$0u؉|$DEx8t$ƅ 1ك`؋X9ux:/t^T$L1D$Lس,؋`t&ɃP9u$w$Ɖ‰tY݃t$ōt&S^ht$ǃ[ \\$L;heD$<1t$P|$Tl$XD$(݃\$$$ݛ كh\$h$ݛك \$J1d;Uݛ</,D$?vuf݄/D$$ك,\$݃/\$݃/\$\$0 D$0ݛ/\$Pt$T|$X\Ð݄/|$ D$ك,$\$݃/\$݃/\$\$09 D$0딍vދ|$Xݜ/\$Pt$T\Í&?tk݃/|$D$؋,$\$݃/\$\$0 D$0'/ݓ/PP9u݃/D$$؋,\$݃/\$\$0h D$0 SC(L$0ÒaD$)‰T$iD$$iL$ ([Ð,\$D$4|$$|$8O,at$ t$0l$(F,$Fl$D$$ F~ FFFF\$t$ |$$l$(,Í&,\$D$4ä`t$ t$0|$$|$8l$(,F,$nFl$D$$w F~ FFFF\$t$ |$$l$(,Ðt&UWVSl$4`݄$$Fn ؋l$L\$8܋l\$@D$Lأ؋\$01X9n ~ol$LD$PD$Ld$0$D$8L$@\$\$ D$PD$XʉFu؋X9n l[^_]É\$ $FD$ $ UWVST$ D$Bq R~aL$ y1ɍl9BŃ9Ju݋T$ BB9rL$ yD$X[^_]yʍ&UWVS% ؐt&Z<{{c{1{S{˄$D$D$Y[Tf&fف$(tshgt{vUtz^z?͸ 0%uttt{1<*zshD$2AD$ ($SnMUVSmJMttt&Ћu[^]S[Ms[iddiidsidmax_record_minutesOOiFilter I is not a sequenceFilter Q is not a sequenceiiiiisisiiiiiiiiiO|iCapture from UDP %s port 0x%XOOiiiilrx_udp_clockagc_max_gainagc_off_gainThe sound device is closed.ssiiissiiiidsiplayback_ratemic_preemphasismic_clipdindex %.5f fdecim %.8f Skip at %.2f _quiskquisk.error_quisk.QUISK_C_APIadd_toneAdd a test tone to the data.idftis_key_downget_stateget_graphReturn a tuple of graph data.get_filterget_filter_rateget_tx_filterget_audio_graphmeasure_frequencyget_overrangeget_smeterReturn the S meter reading.invert_spectrumInvert the input RF spectrumrecord_appSave the App instance.record_graphRecord graph parameters.set_ampl_phaseset_agcSet the AGC parameters.set_squelchSet the squelch parameter.get_squelchset_file_recordset_filtersset_auto_notchSet the auto notch on or off.set_noise_blankerSet the noise blanker level.set_record_stateset_rx_modeset_spot_levelset_sidetoneset_volumeSet the audio output volume.set_split_rxtxSet split for rx/tx.set_tuneSet the tuning frequency.test_1Test 1 function.test_2Test 2 function.test_3Test 3 function.set_fdxsound_devicessound_errorsopen_soundclose_soundcapt_channelsmicplay_channelschange_rateChange to a new sample rateread_soundRead from the soundcard.start_soundStart the soundcard.mixer_setopen_keyopen_rx_udpOpen a UDP port for capture.close_rx_udpset_key_down?$@LL*dA@@The size of filters I and Q must be equalFilter size must be less than %dDFT input data is not a sequenceDFT input data is not a complex/float/int numberFailure in quisk.c in integer decimationFailed to connect to UDP %s port 0x%XFailure in quisk.c in integer interpolationPy_InitModule of _quisk failed!Calculate the discrete Fourier transform.Calculate the inverse discrete Fourier transform.Check whether the key is down; return 0 or 1.Return a count of read and write errors.Return the frequency response of the receive filter.Return the sample rate used for the filters.Return the frequency response of the transmit filter.Return a tuple of the audio graph data.Set the method, return the measured frequency.Return the count of overrange (clip) for the ADC.Set the sound card amplitude and phase corrections.Get the squelch state, 0 or 1.Set the state and names of the recording files.Set the receive audio I and Q channel filters.Set the temp buffer record and playback state.Set the receive mode: CWL, USB, AM, etc.Set the spot mode: 0, 1, ... or -1 for no spotSet the sidetone volume and frequency.Set full duplex mode; ignore the key status.Return a list of available sound device names.Return a list of text strings with sound devices and error countsOpen the the soundcard device.Stop the soundcard and release resources.Set the I and Q capture channel numbersSet the I and Q playback channel numbersSet the I and Q microphone playback channel numbersSet microphone mixer parameters such as volume.Open access to the state of the key (CW or PTT).Close the UDP port used for capture.Change the key up/down state for method ""??D>pB|;F;F AA HC:BzD`L`jFD@@@;G@ @>@>A-DT!@?#B ;(\?Hz>?{Gz?? >d, @/~"@-DT!)@zG?{Gz?cJ!K|?MbP?N9?[|&M?Gz?ffffff?333333?{Gzt? Jp/@Mb@?-DT!333333@ffffff?@ư>h㈵?wbRIFFWAVEfmt factdata(ssiii)digital_input_namedigital_output_namedigital_output_leveltx_channel_delayddiCapture radio samplesCapture microphone samplesCapture digital Tx samplesPlay radio soundPlay microphone soundPlay digital mode soundptimer: %d counts in %d microseconds %.3f counts/sec -DT! @7$tIFCno soundcards found...hw:%d%s %s (hw:%d,%d)%s %shw:%d,%dsnd_card_nextAvailable formats: alsa:Cannot set playback rate %dCannot set playback format.Cannot set start threshold Can not set sample rate %dCan not set channels to %dControl %s open error: %s device_list: control open (%i): %sdevice_list: control hardware info (%i): %sdevice_list: snd_ctl_pcm_next_devicedevice_list: control digital audio info (%i): %sCannot open playback device %s (%s) Cannot allocate software parameter structure (%s) Cannot allocate hardware parameter structure (%s) Cannot initialize playback parameter structure (%s) Cannot set playback access to interleaved.Cannot set playback channels to %dCan not set playback buffer sizeCannot set playback hw_params (%s) Cannot get software playback parameters (%s) Cannot set playback sw_params (%s) Cannot prepare playback interface for use (%s) Cannot open capture device %s (%s)Cannot initialize capture parameters (%s) Quisk does not support your capture format.Interleaved access is not availableCan not set capture buffer sizeCannot set hw capture parameters (%s) Cannot get software capture parameters (%s) Cannot prepare capture interface for use (%s) Cannot find the given element from control %s Control %s element has unknown type Control %s element write error: %s ?;portaudioportaudiodefaultportaudio#PortAudio device %sportaudio:Using default portaudio deviceCan not find portaudio device number %sCan not find portaudio device named %sDid not recognize portaudio device %sCapture and Play sample rates must be equal.O0/dev/ttyOpen serial port %s failed. PPCLAIMOpen %s failed, try modprobe ppdev. ?Send socket returned %d modulation_indexmic_max_gainmic_avg_gain\/$?uSg ?z2L?XBٜ?@{aJF@DB??333333??>;f??%12.6lf %9.3lf %9.3lf %s %12.6lf %9.3lf %9.3lf %12.6lf %9.3lf %s %12.6lf %9.3lf Rw> ]GH=?@Vb܀f6k?|}^ _|?Z wɨ?I<'??Rw> ]GH=?@Vb܀f6k?|}^ _|?Z wɨ?I<'??<'?Iwɨ?Z ^ _|?|}b܀f6k?@VGH=?Rw> ];|(pT8XDx4 T@`DD8\T|$t$t(tTt@ t t L p T d  dp  4# $ $@ / D0 4 6 d7l V ]8^p^$dth4hTdii$kTk uPvdtvz{| }@T}`}t~dXTd\$4L$DdԶԸ$@Dt dtT(Lt$48$`d$DD40dLzR|  0 F J tx?;*2$"D@AA CN A AAE rA AA |N G m K Y huAN bCGAN tC=AN jC=AN jC04=AN jCPTQAN ~CpGAN tCGAN tCGAN tC$GAN tC T[AN0HC iAN0VC8GAN tCX =AN jCx,QAN0~C$lC0Dk D DNAN0}AtKAN0zA,AA Q  AAA 0$BAN oC PTfC DdztLAN yC AN`R CD |LAN yC AN@d AD @8IAA ACQx AA AAE l@DAA CAF@ AA AAF  AA AAA  AA AAA @AN oA VAN0EA0?AN nA@PAA AAN AA AAA lX,AA CAQ CA AAA  CA AAA [ CA AAA AC`A?AN nAT AA AAN CA AAF u CA AAE d@_AN0NA |\AN0KA( C@DSFJ C T }AA AAN AA AAA e AA AAA T0 {AA AANp AA AAA c AA AAA 4 AA AQw A AAB @AA AAQk AA AAA ,@JAA Np  CAE 4`]AN JC@X AC CAFW AA AAG H#nANP]A<#cAA AANp7 CA AAA , 'AA Np  AAC P0 )AA AAC ~ AA AAG KAA AA ):AA AAF CA AAD  AA AAH  AA AAA  AC AAB @ H9AA AAQ  AA AAA 4P OAA N0  AAB Q AA HP 8P^AA CCCPp CA AAG l AA AAH n CA AAD  FC AAG ( UJCPDTFJn G L 8YsC0Je4l YhAA AA`A AA0 YAA f AG @ AG 4 ,Z)C@Da~ B  B x $[*@$ @[c AA AAQ AA AAH h le2 | ebAN QA4 e AA AN0 A AAG , iC D]u G Q, j(AA N  CAF 8 kNAN {CX kNAN {Cx kNAN {C( lAC N  CA lAN0[ CC , mAB C] AAA B T rAA CCN@ AA AAA  AA AAC TptuAA AACP CA AAC # CA AAG <x AA AACpD AA AAA $C0DQY@04 AA AAQ AA AAA 8tAA AAC0AA AA,hAB L AAA H (đCPIQR4 E T 8AA ACF AA AAA | FA AAA <dAA AAC@t AA AAA TAA AACP| AA AAA 2 AA AAB <AA AAN0x AA AAB <XANHA\XOC DUr(|C`HP~ G 0|C0DZU B G A P H $C`Drn A <̢PAC AAN@7AA AA@XܣAA ACV CA AAH <-AC AACp CA AAA XAC AAC2 CA AAG ! CA AAA @8ܫAA AAN AA AAA T||AF AAC CA AAE  CA AAA 1AN `A(гC`D~ H  D'AE _A @TaAN ~ CH $dC DWf D C0HUb F $C0DWf D  8AN0eA0,C`HSH B p H ,UAH0JA$PTC0PSF\$xC0HSHMW<$AA AAC AA AAA 8AA AAt A AAC <XAA AACP AA AAA <\ؼAA AACP AA AAA <8AA AAC0 AA AAA <AA AAC( AA AAA <AC AAC( AA AAA <\HAA AACpAA AA<AA AAC@ AA AAA <CAA AAC@  AA AAA ("AA C  AAH&C@ C dAN  7 Bo8H  2,Ho+oo)o|F8V8f8v88888888899&969F9V9f9v999999999::&:6:F:V:f:v:::::::::;;&;6;F;V;f;v;;;;;;;;;<<&<6<F<V<f<v<<<<<<<<<==&=6=F=V=f=v=========>>&>6>F>V>f>v>>>>>>>>>??&?6?F?V?f?v?????????@@&@6@F@V@f@v@@@@@@@@@AA&A6AFAVAfAvAAAAAAAAABB&B6BFBVB?*dA??GztA??\DpMeDDk`JDjJDeJDdJD\DDpWKDTKD KDpIKDVKE0WLEV)EEE IUErE`}EEHEEHLEPHEEHEF`K|LFL,F@PL8FGFeFGwFFNLF@N,MF)XMFPMF`GFFGGGF"G#?L:h$?E}r,?^Y~Q,??k)?KuN$E]@蘃I]ONXIDI-9Ұ)? uǖ? ȲM?4窮4?-B}dTFw0aS+UҾ9W )#& I?g=Z?" X?oa0Xs?(( z?"n}q?EjcnP}5nyW^Bdl/Ws#O{_?oRՀ?L:0Xs?FW8? 'jNٱn..NuF&44%mSQ^?GG}j?ddKq?$e?824 yff"[k9%`n%du:?Ს}b?L*^e?[5W?T$㓧N=;r=^짪X`XQoa ȲM?u$hM?6t}9?]vw34jHHHE~8 ?=? uǖ?"H{ 4pRb)ӎܼ%Sޱ8 ?`<I?;Z?X^2b?X±a? J=S?Ez=KxX^qOy` JGm]Y?j?{ĝf?`Ws ?KEj_b tҀ@Qi^wX??Ix?{?ҾBe1d?7˓shR.́B =&?o'?M̍?Qp?IQ Ly^T{3 #r᥄?nҝ? e?o6M}.X|'>խ w큾f3?#7?HA6?/c,?HA6?#7?f3? w큾'>խ.X|o6M} e?nҝ?᥄? #rT{3^IQ LyQp?M̍?o'? =&?́BhR.7˓sҾBe1d?{??Ix?^wX?Ҁ@Qi_b tKEj`Ws ?{ĝf?j?m]Y? JGqOy`KxX^Ez= J=S?X±a?X^2b?;Z?`<I?Sޱ8 ?ӎܼ%pRb){ 4"H s?~6K_SBbKuQOG(KZFmH ؕE_BQ@?)%0r<\v7l}3.d.% r#f#N! ?Ys $ ??h/)?d⌺n1?Ƭ&5?{>:?Ab>>?@?SB?P pC?I5D? [E?nwŽE?Xt6TE?`D?ōCC?\\A? ϼ??љuP:?Gs5?ͨ+?[?]^<'`k"N-2tG;fʊAgp[R3q Nq ;qDtVp'( >oX l%ieۘ(aV} #XzeI\92 ɂnH?VtY?{c?'H:{j?M_p?7rMs?Dw? Qy?/|?C6].~?I?;Ƃ?Pr0K?Z?u*5?HFy?lBy~?~ZۑpM|?,KEx?%Zt?bRMo?Dc?cn{L?5fL P!ofo-\sb̛j|ng6Ⴟղǣ}.֐r_O ;畿cgΑeٚ݋5vlv&&sʠơD«\`^wj(A X`0>ǣwߗKK4{?ߗK>ǣwX`0A j(\`^wD«ơ&&sʠvlv݋5ΑeٚcgO ;畿r_}.֐ǣղng6Ⴟb̛j|o-\s P!of5fLcn{L?Dc?bRMo?%Zt?,KEx?~ZۑpM|?lBy~?HFy?u*5?Z?Pr0K?;Ƃ?I?C6].~?/|? Qy?Dw?7rMs?M_p?'H:{j?{c?VtY?ɂnH?\92 zeIV} #Xۘ(ae%iX l'( >oDtVp ;q Nq[R3qc/>p} zxp'Cne.k5Km#iPf!ୱbBt^TI >?{>:?Ƭ&5?d⌺n1??h/)?Ys $ ?#N! ?#f rd.%.l}3\v7?)%0rӊ?R%Je}?UOJzdǒv{`j0ss.?47o^?>u;?׊>}\\b}AfSɭ}GhNYy?y?-d"}0?pD>@?-d"}0?y?hNYy?}G}AfSɭ\\b׊>}>u;?47o^?.?j0ssv{`dǒUOJzR%Je}?;>ӊ?Gf?}I5OПsv1ǃ~@xud R?N5;oN%t?,6]q?!g3?S$p m Yw\ {ms$ 4^F??R`5?.>5?ַ(?[8$x$&⌿f00?F]݁vUXƸT2?T?F??{i?zW!e 4|꧁?}^g5;hȈPFsWB'36=I=eB+A?jqO?v.]&x]~S]XIF6V?P ?Q?9n` UR:_O7>lJ?&-f?-#?gxk?'BYTm?@k?#;hDuAY?,a}?p֥n%L?W1#sq?WRu`@?{7ꑋ}JaxAo?t&\? \?^w%K/s[yzL [?M6da?iUA &5 's?b[f?0tb? 琂0sfEO?~)xL?~)xL?O?0sfE 琂0tb?b[f? 's? &5iUAM6da? [?s[yzL^w%K/ \?t&\?Ao?Jax{7ꑋ}WRu`@??#sqW1p֥n%L?,a}?AY?Du#;h@k?Tm??'BYgxk-#?&-f?O7>lJ?R:_9n` UP ?Q?V?]XIF6x]~Sv.]&jqO?=eB+A?B'36=IFsW;hȈP}^g5;X+ˬ> S?t–>#>:N>Js/n>)/B>S:u.'W݄3@"D;3t@qB2VA{NmL=I6Y2 7(VZ"?~/M4?i9?z:*7?qr({+?\y}۾|,1w/`xx;!4j@ a;%\r`+jyK?a_ 9?AVw^C?foJD?m ~@?>f'9'?"IUl-+%C_CwJzPyJ.[Av#r t=?#N.QM?&eR?'m P?KlA? AY|E\Idu%TbIBW;n]fR9*5=ER)io|? -y?嬙jm?~<94Q0 s:;{Ҷⁿ8mp|L(ѐft>Ff?P ?<|m?KU;/?Sy}?[}OsK?erz3g0|m9sl}5 zD{(ҊKh?&<?ґA|Ŕ?%J?_#E?.s?ǁ'kҸ r~ }墿C:C&ߢqWm9c#i?OTf Ф?`or?Έ5 ? EB?G'?G'? EB?Έ5 ?`or?OTf Ф?c#i?qWm9C:C&ߢ~ }墿Ҹ rǁ'k.s?_#E?%J?ґA|Ŕ?&<?(ҊKh? zD{sl}5|m93g0erz[}OsK?Sy}?KU;/?<|m?P ?t>Ff?L(ѐf8mp|Ҷⁿ:;{4Q0 s~<9嬙jm? -y?>o|?Ogu?Ιc?mCtP tpXZ+v<Su5"+ڂli"cLMJ]?M%n?UN;r?Un?R9\R`?;%BaVj♙k &5lsĻ6e6%3P%7p6I?{ a?ODVUg?HA|e?}Z? fh?1?yDGQhl`&9b~Xq^mNG)?=}QS?./o\?HK{\?8T?ER)if'9'?m ~@?foJD?AVw^C?a_ 9?jyK?%\r`+ a;!4j@`xx;|,1w/\y}۾qr({+?z:*7?i9?~/M4?VZ"? 7(I6Y2{NmL=2VAqB3t@@"D;W݄3.'S:u)/B>Js/n>:N>#>t–>RJ /(("*ZNq0ZZ+0^iN *b ti(?u*ԭ@?kVy-.L?7P0S?Ͳ2V?>U? _P?PVʌ=?a:I6sSIiO^/`!`a.cf>$jTcCW[5 ]>0T S?qvXTjg? Eq?8 s?Qq?L Pf?Un'?n!GhxhI4$a}PUO˳m?;nY?v}?J"u?E?*w?M7 ?\>i?Q9o|g. 횿t.6(!Rbϣ0#\?j? Em"ʭ?"i?%}%?ꏽ?OSVF?OSVF?ꏽ?%}%?"i? Em"ʭ?j?0#\?Rbϣ(!t.6. 횿gQ9o|\>i?M7 ?*w?E?J"u?v}??;nY?PUO˳m}4$ahIxn!GhUn'?L Pf?Qq?8 s? Eq?qvXTjg?0T S?5 ]>CW[f>$jTc!`a.cIiO^/`sSa:I6PVʌ=? _P?>U?Ͳ2V?7P0S?kVy-.L?u*ԭ@?ti(?b ^iN *ZZ+0ZNq0*/((" RJ 5h;M?B/;??G?l 715?Rf>W ιp΁!Pywsqah=;Md? @[?9Bf]Nn%k-lC]k?ti?R{rz\GQt`)8Y[DP s?ţu?=(b;_n0 YG#j0Xy|?O?ęa`4% WCx #l?"\^ь?W`Qaߥsa,|6M?aLb?ɾrda/8Do>}Y?:՜?T-aS&K@-Z®^NN?,10P?v v?,10P?^NN?-Z®S&K@T-a:՜?Y?o>}/8DɾrdaaLb?6M?,|ߥsaW`Qa"\^ь? #l?WCx4% ęa`O?0Xy|?G#jn0 Y=(b;_ţu?[DP s?`)8YGQtR{rz\ti?]k?-lCNn%k9Bf] @[?Md?ah=;sq΁!Pyw ιpRf>Wl 715??G?B/;? 5h;M?8\4?k;[?3{xLL9|[?9TB`1V?k@?%FoA9i؛yu?Y+ wigj?)R^?5P񀿼 3?^3dタ?Ojn?oNDtOތ?BU¡aQ?sCCv?`򨿽aw?`oG¿]z;?m?]z;?`oG¿aw?`sCCv?aQ?BU¡tOތ?oNDOjn?タ?^3d 3?5P)R^?igj?Y+ w؛yu?%FoA9ik@?1V?9TB`9|[?{xLL3k;[?8\4?j>p|jk?Ȼ%?l˵F3?/0^??F?ۂwL?^MP?UN?%F?IǷ`*? =MSg_?_c]a6e14]c<VQG]DOo[0Q B?lK?/E9F?^UB!?׈pdEj>VJ4V^F8%$s3]1QSfe1!XH?_߾uX?Χ\?W͡U?[)5?q{MzA%`Au?01dGagYlQѷJEV׈pdE^UB!?/E9F?lK?0Q B?o[DO<VQG]14]c]a6e?_cg_MS =IǷ`*?%F?UN?^MP?ۂwL?F?/0^??l˵F3?Ȼ%?p|jk?j>n;T?iZg4r?@)2>Kx&5@+ O?u,Ji{@FƋIvMmN?z,Ȍ?txsUPN+a YyZ:??1TBr?\6 0mE񛿐~Ŋ?怂X5?fݕ?ϔ)iH@0B@?PK+ O?LhY*?=ZxލN8n&z!p?_ cw?cw7? AsvkJ _[?&뽼p?u9S?}Eg,dapu }eͼN#H-3?զUSKc?Q:U? G Q*.]_G( 7S6S?. R?9Eh}. BWyTQ8A &@?c-J?=W?-  ,L2=M/T@iZg4r?n;T?vXg>ۨt??$ /H{&? 2?dMz#:?3F]A?s,E?(CsG?λ~G?YD?sjC|9?A9}?uz`R:2t>M~ W֢^OMa^aJaib`R {[#h?Rڏ|Ao~ ?ۓ@?S>H?s=G? ư;?̒^ l5D6rR/KԱWq1XxTmGp_{IL-E?$`T?z6gX?#V?{d@M?@I`Tn!?ŭѴHЈHXO]P`[kL`~4YLt%lFʗ9?.0ۓW?o2a?rd?Qa?wOaS?0MH,>A~(WZâd_t8i;1?g%iXq`ϴA*"J;S?,=6f?L!n?xd o?pD3h?P6,U?YMʈI) 0gmq]s qF+wciꦮ?SHf?IM)C;t?G׉ax?B (w?Wޙ[o?QߠJ!M?dBCBvᇎ#AU~ ~PMM0Ƞwaz]Ixc^+O_?4hrx?oe`e?p}?%BxU?|ׇr?mހ!JHzMuϢө ISF!A~(W0MH,wOaS?Qa?rd?o2a?.0ۓW?ʗ9?Lt%lF~4Y[kL`O]P`ЈHXŭѴH@I`Tn!?{d@M?#V?z6gX?$`T?IL-E?p_{mGxTq1X/KԱW6rRl5D̒^ ư;?s=G?S>H?ۓ@?o~ ?ڏ|A#h?RR {[ib`^aJaOMa֢^~ W2t>Muz`R:A9}?sjC|9?YD?λ~G?(CsG?s,E?3F]A?dMz#:? 2?$ /H{&??ۨt?vXg>j0Q> OFT>\0^U>3T5"#Ea/Or7pPVtkC]K`?Dxv"E?F쫑@E?%?v~E-!L”)A1,۴6F?R? Y;B?hGXDMO0SD?eIr_?t }X?Z!3l>>a1bn(eaM$?4U 8f?a1bZ!3l>t }X?eIr_?0SD?DMOXhG Y;B?R?,۴6F?”)A1-!Lv~E%?F쫑@E?Dxv"E?]K`?VtkCr7pPa/OT5"#E^U>3\0 OFT>j0Q>I0L>V;>My1?Efޖm?3D?dC!?(%&?J_,?(2?1?'W&3?%\H4?xd3?w;1?:sDA*?̛? ֕ '8/ݱ>09 '?]7?.>vPB?+mB]F?F?p5D?s=:ʣUv9?+ G?o^ P?}SR? #ZR?FhP?XjF?90A4?ٱ s?B쫯(OF 8T3 HW!`V kS41` Kk6d4-?pNI?/BT?0D Z?Tt]?oA( \??.QW?򋫭N?4F93?Ccqj: cQ}[aqA_:bnqt&a$I•[J2PI.V,%%IF?G6qX?lw b?`K+ƿe?īEf?xcd?6)]`?z;FQ?njP?1Q6[3a_֊gvokJ0 2lCh٧$\b*=4Q<0?pZ?ՍqŸg?!xfo?4mq? wq?Wm?ꀭHd?I1JP?nmH\d%?`pր7t.OAvMu.lLqY'\ef6V4HMcX?*n?7v?!{?[,}?`m6f{?j~u?q)h? z@-?x!>f6r)wQd$U}FDy[ۃ)+؁Any˒zUEj ּI?BBt?x^e?Onˈ?|9{?Cx?8t ?혁?T\Wzk?"hzh<^OςH77Xm7[Иzl>o=RP9lA+?ʯ?PF^h?bþ?5:/,?7mV?_;XDۺ?'{۳?2U?'{۳?_;XDۺ?7mV?5:/,?bþ?PF^h?ʯ?A+?o=RP9l>zl7[ИXmH77<^Oςzh"hT\Wzk?혁?8t ?Cx?|9{?Onˈ?x^e?BBt? ּI?UEjAny˒z)+؁y[ۃ}FDQd$U6r)wx!>f z@-?q)h?j~u?`m6f{?[,}?!{?7v?*n?McX?6V4HY'\ef.lLqMu.OAvր7t%?`p\dnmHI1JP?ꀭHd?Wm? wq?4mq?!xfo?ՍqŸg?pZ?<0?*=4Q٧$\bChJ0 2lvok_֊g6[3a1QnjP?z;FQ?6)]`?xcd?īEf?`K+ƿe?lw b?G6qX?%%IF?I.V,J2P$I•[nqt&aqA_:ba}[ cQCcqj:4F93?򋫭N??.QW?oA( \?Tt]?0D Z?/BT?pNI?d4-?k641` K kS!`V3 HWF 8T쫯(Os?Bٱ 90A4?XjF?FhP? #ZR?}SR?o^ P?+ G?:ʣUv9?C>Ņ6;E+L^dP%fP(]%M(dnFBp(;9(Em$X&'?s=vPB?]7?9 '?|r>0gICjNIZ".SZvjWc,YeSZJKRFZ `D"Ye!@V50'6SبlN'8/ ֕ ̛?:sDA*?w;1?xd3?%\H4?'W&3?(2?1?J_,?(%&?dC!?3D?Efޖm?My1?V;>I0L>G(z&1ib1WŇ6ꀙ N^45]f4?.˸L?j0>W? A\?8PgZ?osЊL?1Z:?rVpn^(0hɨQi[){g`ş3?׷5 i?^?v?/y?=r?D@?ZspL>!~XAX <Ӑ`] }?Z/2G?/~?8m%?t'u? # hʇ/wຠCI-SbPo _?;=dM? *%?2_? SBk? SBk?2_? *%?;=dM? _?SbPoCI-ຠ/w # hʇt'u?8m%?/~?Z/2G?] }?<Ӑ`X !~XApL>ZsD@?=r?/y?^?v?׷5 i?ş3?[){g`ɨQi(0h?rVpn^1Z:osЊL?8PgZ? A\?j0>W?.˸L?5]f4?ꀙ N^4WŇ61ib1z&(G^3>BH.:件2J"0oqiF@5qɳ?͉?UAn?0?0?UAn?͉?qɳ?5>@I|.qn 2mi;Kˆ?*RX?^HL?8u4?o7ՠb.#OKђZ]Ra}Be?U6 ?L)3"??+?lH ?$mk@l߅-Vq"^AUف??*7Ce? mi?GUL?5kIuɓ#y'Uq߆׸d?NNͶr?#x`?u4O? TfⒿ6kjMgy?Bnѝ?l%kh?EDIWU vּ>e$`7yGж?\%У?Hgn?Hgn?\%У?yGж?e$`7ּ>U vEDIWl%kh?Bnѝ?y?6kjMgfⒿ Tu4O?#x`?NNͶr?߆׸d?'UqIuɓ#y5kGUL? mi?*7Ce?ف??AUq"^l߅-V$mk@lH ??+?L)3"?U6 ?م.u*K1Kiay Ѿ̼'Gn-~`o/b3n*d;ӽ2ޢ?f)?8?FF?6jQ?U?#Nq'X?vX?v9,U?{OyK?,/?X >5gf&RoYp\wW=$0mJWf3}m ?I0 S?[7a?f?<wC|g?u $nb?,/R?,G@_bٌX8nx@Qr qi*P-SmZ?wf)Nq?ȧay?KB|?vC dy?9iEo?oD%1?g6o28sԄ_~@>2w-ks M p6 _?]|L?`Ł?b4P?RSЈ?Xe?/V:i?]d=) |4\:gy`$bTR5rorvFTa?߁_ ?Xr 6?曎: ?JȠ$/?A̲w?Bun;?Bun;?A̲w?JȠ$/?曎: ?Xr 6?߁_ ?rvFTa?robTR5\:gy`$ |4)]d=/V:i?Xe?RSЈ?b4P?`Ł?]|L?6 _? M p2w-ks_~@>Ԅ28sg6ooD%1?9iEo?vC dy?KB|?ȧay?wf)Nq?-SmZ?*Pi qx@QrٌX8n_b,G@,/R?u $nb?<wC|g?f?[7a?I0 S?Wf3}m ?=$0mJwWp\oY5gf&RX >,/?{OyK?v9,U?vX?#Nq'X?U?6jQ?FF?f)?8?2ޢ?d;ӽb3n*~`o/Gn-Ѿ̼'ay 1Ki.u*Kم8 Z A%[I. ھS{F?o|Y?X^?*lP?ԋ}AP`*DV֝SA*KH*U?ncsn`?)76?۠(aѷd[Nj5?R!l?VDh?g=XZgIz@uLf1v"]o?wڕ|?_~[?CŠ|4ac|qL?'[3 ?i[t?OXQzv6C~{Z5LI?=?Z2.Mk?{ {IDnsd:w{?. /Z?\Z_Wm?jתƵ泿aRx&O?q`;}9?UzY?q`;}9?O?aRx&תƵ泿j\Z_Wm?. /Z?d:w{?Dns{ {IZ2.Mk?=?Z5LI?{6C~OXQzvi[t?'[3 ?c|qL?4aCŠ|_~[?wڕ|?1v"]o?LfgIz@ug=XZVDh?R!l?[Nj5?ѷd۠(a)76?ncsn`?*KH*U?֝SAP`*DVԋ}A*lP?X^?o|Y?S{F? ھ[I. A%8 Z Fi+Y?t$X?-|<? 0Z?eBV#?YW(?XV]-?h1+1?zi&5?FMV8?!>k;??{z>?nȫ@?A?x{ hIB=P>BŶS kW;2YwKZ!6Hl8]JcX_p`7ԁ\a\JU0bjWUbDJtbEUW3aTtԜ`Um^dXi[N,W$CSc0>MHN&C|w}1J6 ?rhű5?>PC?9͑Y L?p-iQ?jc*(T?||ٜU?~K'V?VP\V?ą!U?,)UkR?oNcpO?m`[G?54;?1ⲹ&?A0e %WDȗHPRhUȌ%9[/_ƺfaJbpc糿4cHb*@&ar,^-AyYY!Sв'oG|,\?RR?+mA??8/AL0|bPar:y\3:dair[n)3q-+Vkr7p"ss(sH surp]qF+mwRxbh i>aܔIR7,b>EYP?~a?`Jj?+q?0%u?x?[I{?;@|?#s}?dm|?r9C{? mqx?c)t?o?9o\%c?t[F?kW9Qڗu(h}]sTBg{`A\\m& -ZKe s ;6j;EYP?7,bܔIR i>awRxbhF+mp]qH surs(s7p"s-+Vkr)3qr[nai3:dar:y\|bP8/AL0+mA??RR?IK:>\?icb?ȇ\Ce?KzuBh?Pi?fj?Ü^pi?*Mqg?e?nTb?Zͦ~^??V?Z{R4K?PC?rhű5?J6 ?|w}1HN&Cc0>M$CSN,WdXi[Um^TtԜ`EUW3aDJtbjWUb\JU0b7ԁ\ap`JcX_!6Hl8];2YwKZ kW>BŶSB=P>{ hIFBq88r:q(#;W ?Ɠ0?1 8?ob=?f A?/*jB?bq?gC?rC?(dCC?x?!>k;?FMV8?zi&5?h1+1?XV]-?YW(?eBV#? 0Z?-|<?t$X?Fi+Y?$@$@GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 CwF g(&X -Z*X.c ="FZ Cܺ 0a\ intW8aio W  Z_1[   Z#d #N # # a # # # # #  #$T !#( "#,v $#0, &#4/ (Z#8 ,Z#< .z#@ 2>#D' 3L#F3 4#G 8#H# A#L J#TF K#X L#\% M#`, N%#ds PZ#h& R#l     # #  Z#  0  0'  gZ  G 6 !#  "# 7 Ai > Fi# Gy 0 LR  0# 2> 40   j k# k#QDE#E#E# F# 6G#G#+K#NL#gM # EN<#$bOt#(P#,Ti#0\Uo#4 Vu#8Z#<P[O#@\#D]0#H^h#Lwa{#Pd#TEf#Xj #\fmz#`Oq#dt#hx#lHy#pV|#t}#x~+#|###### #B# ##z#######g#### #0# l ###e 4:#O##Z`#z###yZ#7#Z# ## #9#xDJZd##souZ##Z####<   ' #'  8 > X # 4 buf#obj##len# # <Z# Z# &# ' # ' # ' #$ ( #( #0  0X A3 9 ZS #S Z d j { #S ׆  Z ##ج  Z #Z  Z # 0 )# 3)# )#  )# )# )# =O# 0 # # 7#$ / z#( #, )#0 )#4 7)#8 ) )#< )#@ #D #H 6#L !#P #T #X )#\ C)#` )#d p )#h)#lzO#p)#tA)#x)#|>)#)#] )# )# )#Y  )#F# ( j#)### +#9#Zd#{ #)# #$<  !"#Y#)#$#% '(#m)#* # +- #  ,( #=-Y # .+1 2# 3Z#Z14#0#L546 6HNZh##78  9 (:#{;###Z# < = | >Z[ ??@YA"(#B##BNT#i0   % &# 4'm# (Z# *# m n +  #get #set#doc# # b  #  # = 4,## Z##_is(y  y# &# ## ## ## ## I ## [## ## *Z#$_tsT8  ;# <<# ># n?Z# CZ# DZ# CF# G# ~H## 4I##$ K##( L##, 0 M##0 O##4 P##8 3 Q##<  S##@ [Z#D ~]Z#H X_##L `#P%-Z#Z#d7G a? a/5 (>mv  PR>  # #  0 76w F: # :# P# Hk#Qad k E# 7{ 0  0|>K ?{# 5@{# AZ# BZ# M CZ# CDZ# E0# F0# G0# <H0# IZ# JZ# KZ# LZ# MZ# NZ# OZ# P{# >Q{# s S{# T{# U# VZ# WZ# XZ# YZ# " ZZ# 0 [Z# \#L _j'   # j# UZ# zZ# Z# j# j# z  j#   p  # j# UZ# zZ# Z# u# y# {#$ z j# UZ# Z# # #  0  0 o: { # U!Z# "Z# #:# $J# J 0 Z 0 yZ v  !# "## ,#Z# $Z#  %#y &yIgZg M8MMZM%  Zc __s  ~88 88%G>Z __s> __n>%>?11 11%B v8v vv%! "__x## Z#>#>>$n%j%YZ&iZ$ %j%YZ%&iZ&d#@#Z # __n#%#Z' Z CD(bZ)iZ*i1Zl)i2Z+Z"+lA'=DE$(=(=-(Y=Z)d?)di?'# EE`,#,u#'n #EE\,n #,un #'f #E-F,f #,uf #'^ #0FmF,^ #,u^ #'1V #pFF(P,V #,uV #'p#FGl,#,u#' #GWG,#,u#'@#`GG,@#,u@#'#GG8@,#,u#'38#HGH||,8#,u8#' #PHH,#,u#'M #HI,M #,uM #'# IgIH0 ,#,u#'2#pIIl ,2#,u2#'0H#IJ ,H#,uH#-"2JZl'#JK!,#,u#*msgSn'a1S#K^KLM!,S#,uS#-Ul'N#`KK!,#,u#-bZl'$#K]L",#,u#-~-Z~-~->{~'d#`LL>P",#,u#'0#LM",#,u#)nZ.LL+ '# MlM",#,u#'|E#pM5N. ;#,E#,uE#-bGZl'#@NN w#,#,u#'"#N>P #,#,u#-bZl'#@PR $,#,u#-`#~+n# )iZ +Z )obj#+ -3$~/7RmR0I 0a 0v $ 0a12 RV 3&(2 j (Y2 Z (.2 ZT )i4 Z )k4 Z+4 Z`+4 Z~+5 &c35 #b5 - 6 3&ſ-,7 Z 2.8 .-9 Z -: `-; #d-< h-= l-?> p-^? p-h@ p /RRL 00;0N F&30' 3#VV&,3#,u3#'I:#V&W&,:#,u:#-t<Zl' #0WoW  ', #,u #'W#pW\Mj(,#,u#)iZ)jZS)kZ)nZ+bZH++5Zt+#)cx)d2 + C+c++% +r%+O)FFTj()pt++8 'p S#\dJ),S#,uS#)iUZv)jUZw*kUZX)nUZ+v Vj(+W#r)d2X+ X+XU+X)cY-lZ-[Z 48]~0K5 6W 7c6o56{a'#de),#,u#8 Z'1 #ee9*, #,u #'A y #ej,+(y #( y ZF,y Z)obj #e)i Z)j ZL+ Z-. Z$- -& #-  # - +> b'F #jk+, #,u #- #h- Zl9dft #klk+, #,u #- #h- Zl'?Zpk|r_-(j(YZ,Z)iZ!+2Z3!: T-?p#^p#hp#p# p# p# yp# p# p# p#bp#-  -  J,+- 0'<rs_!-,<(<ZB")cx>`")j?Z")k?Z #-@Z ; qA- BZ#C-#- D.+ +E.-# .<0' -. 0-'J ]t{ug# /,](]ZJ$+_h$+_$)j`Z$)k`Z5%-aZ ; qb. cZ#d /#e /#- f/'+g+/U% /<0' .+/ 0.'']#uw%/0,]#,u]#)ip_&+`Z3&*bufa{~-`b\+ cZH&=HvQv/&__v>)__x>j&>8v@ 00V&0K&48.wX0V&0K&1>wN&2(>u'(Y>Z',Q>Z,>Z)i@Z')j@ZT()k@Z()i1@Z()i2@Z))inp@ZJ)+@Zx)+ @Z)+@Z)+Q@Z*)dA6*)d1AI*)d2A*&avgA- BZ -BZ -BZ -BZ -,CZ - D#z - E# ; - E#P -E#` -&F2{ -sG2 -!H2 -I2 -J2@; -nK2` -L2@{ - M2 -bNZ 2<0 2<0 2<0 2<0'M'#P**3,'#,u'#-)h'r#&+f3,#,u#'Zj+D5(j,(,(YZ-,Z)iZ.)cx~/)cpx#0)d=0)diP0: \15d#### #(#0#8#@#Hrp#P|p## # # # # # bp# - D5 4T5 0'r'#^n05,'#,u'#-)5@-*5` 5 0 5 0' #`Ð056, #,u #)i ZM1)j Z1)pt 1'f#АӒ26,f#,uf#+!hr2+h2+hh2)miph2+th2?27,j,YZ)iZ3)d3$k7%j%YZ&iZ#9##@298jYZAjAA AZAZAV ZA,ZAyZAZBiZBjZBkZAZBmagAAD CZ8jYZ,BiZAiZBxm0Bxm1Bxm2Bxm3ABc0Bc1Bc2Bc3BinZBoutZD(yZ3=,yj(YyZ\5)i}Z6)n}Z09+i}ZO9+1}Z9+<}ZA:)d~:)dr~J;)di~;+~;+!<+<+TZ?=-Z<-@-D-jH-+ -(-- В-q -NX-Zh- p-K-rZd- Z0-p-p-pE?>7'p;007_=0$7=56<7=6^7>FF7FR7>k7@]<07>0x7>5(67?67t?68?6 8?68?6"8?6-8@F7\F7XF7HF7TF7PF7<F7@F7DF7>h<05@0f@0@56@6@><GG56A498H0`8<0U8#A0J88A5 6k8LA6t8vA68A68A68A68AF8F8F8F8 F8 F8 F80HH=0AI`0BD<ZB @,D j-BP*buf @t-7)iZB+Z C+YZ7C)xrZeC)xiZC+,ZC+T  C+# D-s*fdsyr-" --Z-ZJx?)decZ+DJ^1 E 0M8E E 0M9E E 0M :E E 0qM;E  F 06M$F QF 0aM?AF nF 0#M@^F F 0.MqC{F F<04M^DF F 0\MEF9 .w] 0a\ intW8aio  Z_1[ Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#  0  0' g L ) 0    jk k)#  ki#Q Di E)# Ei# E)# F# 6 G)# G)#+ K1#N LO#g M# E N#$b O#( P#, T#0\ U#4 V#8 Z#<P [#@ \#D ]#H ^#Lw a#P d#TE f#X j? #\f m#`O q&#d t)#h xR#lH y^#pV |>#t }J#x ~#| i# # j# v# )# # # # # # # # #g # # 1# 0#k lB oe  y Z7 $)4 ?EZZZZ kq) ))x Z)s Z )) Z7 NT)n)7< N ))  ))= 4 buf #obj #len )#  )# < Z#  Z# & #  #  #  #$ ( #(  #0 ) 0 A  Z  Z       Z  $ * Z? Z J P Zj   ۨ # 3 #  #  #  #  # = # 0 z#  z# 7 z#$ / #(  z#, #0  #4 7 #8 ) #<  #@  4#D  z#H 6 z#L ! z#P z#T  z#X #\ C #`  #d p #h #lz #p #tA #x #|> # #] # # #Y #F z# j ( T j # # `# `# + # #Z #  # #  `#$   !  "#Y ## $ # %`  ' (C#m )n# *y# +#  , #= - # .  1%1 2=CO 3[aZ{{Z1 4L 56 6Z 7 8  9( :&{ ;28RZ# < =| >[ ?? @Y Ai Bi) T    %>  &# 4 '# (Z#  *# mD n   #get #set #doc #  #P   Zu   # o #  #  Z#  Z# w ;#  ;#  !;#  ";#  #Z# ; $Z# g %Z# & &Z# 4 'Z#  (Z#  )Z# ? *Z# N +Z# H ,Z#  -Z# I .Z#  /Z#  0Z# Z 1Z#  2Z# t 3Z#  4Z#  50#  60# 70# < 80#  9(#  :;#  ;# ( 0?| >  ?# 5 @#  AZ#  BZ# M CZ# C DZ#  E0#  F0# G0# < H0#  IZ#  JZ#  KZ#  LZ#  MZ#  NZ#  OZ#  P# > Q# s S#  T#  U#  VZ#  WZ#  XZ#  YZ# " ZZ# 0 [Z#  \;#L  _'   /5ZEE(   # E# UZ# zZ# Z# E# E# z  E#;qcdevccEYcZieZref;imf; ] dev!X txt"v#IgZ}g$#B vv vv%c devGdevG{GYGZdJ;%K%K& Z>F'EH'YZrH(fp{8 )08 )p08 *jZH+D H*u0I*s>1I&KsZ@QIh'sEI'YsZI(fpu{8 )v08 )pv08 *jwZI+D xSJ*uy02J*sz>^J, ~J-.J-:J.F/R0 -FJ-:J-.K12R8K,xKK'.P.R2K2K2K.@, Lv-L-L2M2)M2\M.@349zM4Q4Z)60()]60$)k7 *dt8M5]B-pM6@jt?77:7$8*ZpN$9iZN:YZN:ZpO:8Z9P:ZlP:ZP:ZP:(tQ;;H8 ;;@8 ;C(;K`8 <ZtN=iZP> R? \RO9i ZR@_,.@, A1.0 @-./ @8..`3 @X/1.6 Bx0.5 >^[S8oJS7o7uo9devrS;s;X;s;`;_tZl8S77u8 nTY77u82pZT77u8%T77u:XT8wU?77u:hU;XZl)* @, ) / )' `3 ) 6 ) 5 ) 0  0)")#Ȗ  0)e'`2 )(. ))Z@2 )V*Z- )+Z- ),;).,)0/0)0$4 (C0)2@DD E FoD cF%/@^1D hZD\ iZD jZD? q; ;/ 0?D7 C&9# 0a\ intW8aio Z_1[} Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#  0}  0' g  0   j\ k#  kZ#Q DZ E# EZ# E# F# 6 G# G#+ K"#N L@#g Mr# E N#$b O#( P#, T#0\ U#4 V#8 Z#<P [#@ \#D ]#H ^#Lw a#P d#TE f#X j0 #\f m#`O q#d t#h xC#lH yO#pV |/#t };#x ~#| Z# # [# g# # s# # # # # # # #g # # "# 0#\ l3 v|`e  y Z7 % 06ZKKK \bw x Zs Z Z( ?E_(< ? u{  . 4 v buf #obj #len #  # < Z#  Z# & #  #  #  #$ ( v #(  #0  0 A  Z  Z       Z    Z0 Z ; A Z[   ۙ # 3 #  #  #  #  # = # 0 k#  k# 7 k#$ / #(  k#, #0  #4 7 #8 ) #<  #@  %#D  k#H 6 k#L ! k#P k#T  k#X #\ C #`  #d p #h #lz #p #tA #x #|> # #] # # #Y #F k# [ ( E j # # Q# Q# + w# #Z #  # #  Q#$   !  "#Y ## $# %Q  '  (4#m )_# *j# +#  , #= - # .  1" 2.4@ 3LRZllZ1 4~L 56 6Z 7 8  9v( :{ ;#)CZ# <v =v| >[ ?? @Y AZ BZ E    %/  &# 4 '# (Z#  *# m5 n   #get #set #doc #  #A   Z" .&* >@$) A##" cH'"*M" i)" l" > *!#}& {(%Z!!%(#&g&*)! l! $ " & Z ($!&w)]("r (:)p$'' $!h'" # $$%U%&$'V#()(*'+9"+K*9')( ) '' %#  ' '% +!(#%)>#$* 5E$ 7) G/0'I( 6@'3& 9Q%v% ?b%" Bsw** H$f")m#1(&L' ! Xy( [#N)^*#&A!'%E&) &#u   # o# # Z# Z# w,#  ,# !,# ",# #Z# ;$Z# g%Z# & &Z# 4 'Z# (Z# )Z# ?*Z# N+Z# H,Z# -Z# I.Z# /Z# 0Z# Z1Z# 2Z# t3Z# 4Z# 50# 60# 70# <80# 90# :,# ; # 0 0?|> ? # 5@ # AZ# BZ# M CZ# CDZ# E0# F0# G0# <H0# IZ# JZ# KZ# LZ# MZ# NZ# OZ# P # >Q # s S # T # U# VZ# WZ# XZ# YZ# " ZZ# 0 [Z# \,#0 M2MMZM%IgZRg  Z}__s  G>Z__s>__n>%>B vv vv%^" %?1R1 11%"pZ!UG pypU!"pHU"p#orGV$q%sZ~%errsZ:V%devsZV$D%tM~#K%uV#!uV#'v]W#*wc.W&l%V'Rc`(pLW(eW'}(W(W(W'}&[(W(X(&X'}x(<3~'}(Zf(rf?9} (f(f?'}GU; (f(f?'}g (f(f?'}[ (g(&g?'}1F (;g(Sg?'} (hg(g?'}1@!(g(g?)}HW(g(g?@GC?(Yg:;e]h!<~'}?!(k(k?9}U "(k(k?'}&L"( l(#l?9}xx"(8l(Pl?'}B "(el(}l?'}G"(l(l?'}F[T"(l(l?'}m(#(l(m?)}r(m(1m?8)G8Fm#! GS#m!]&GS#m#.*In8$_@:n%!_~n"_Z!_,n">_"(_Z%errcZn$odG@P-#'e%"o%idf%Bo# g%bo%idxh0o##io#)io4tmpi#j p>$Bbuf| ~'}$(Kp(cp(wp'}H\"%(p(p(p9}\R%(p(p(p)}X(q(&q(:qWFhC=ZA% S%D0C)"%8 7%D0oC1"%@<" Z%D0C+&%A%C#%I)EE E7R /, 0a\ intW8aio[g Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#n  0g  0'  0 "-FZZ/G.H,+..f/"/.++ ./-/{-0.-+/.v/*-,D-.0++N.,/Zj.Z/b,E.</Z##/#d-Z# -Z#,#,#-#$,#,,#4.40/=,##+Z#y.(#S+ # *-#0/E.Hu \  \# o #  #  Z#  Z# w #  #  !#  "#  #Z# ; $Z# g %Z# & &Z# 4 'Z#  (Z#  )Z# ? *Z# N +Z# H ,Z#  -Z# I .Z#  /Z#  0Z# Z 1Z#  2Z# t 3Z#  4Z#  50#  60# 70# < 80#  9l#  :#  ;\# l 0?| >3  ?\# 5 @\#  AZ#  BZ# M CZ# C DZ#  E0#  F0# G0# < H0#  IZ#  JZ#  KZ#  LZ#  MZ#  NZ#  OZ#  P\# > Q\# s S\#  T\#  U#  VZ#  WZ#  XZ#  YZ# " ZZ# 0 [Z#  \#lB vn v vv%@.Z -G>Z __s>__n>%>,Z; dev; -Z-A iZZ-%Y,%d+L ,ZQG R 7 OOq  q q ! " q# 0 r$H" =r" |r" r% &   r r% & 0p<  r s% 'n t`Y  s' x  C/ `P-? ? ?s 11 0a\ intW8aio W  Z[ Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#  0  0' gZ  < 6 !#  "## 2> 40 1E22O0i01 0s200100? 7 0 (>mv  PR >  M  #  M# ] 0  11#10012 00/0k211 91'2N2.0X076w FK # K# a# H#Qa<dG | V#7V111 0Udp##Z #__n#%#Zj1*Z0*0*ZIgZ(gr0 MfMMZM%10Z=01Z0Z0Z0Zbuf 7 0(L|(42Z+B Z1ZS0Z1Zip`__v>__x> __v>__x>![1BZ(x|"B|#retDZ|$LT%}&'2}$89%^}%}(%}$SJPT%d}&h)nL*+0P%<}&'G~$L%2~%^~( (+Y,F1\0~: -fhb* .h's~/e0W2Z| 1B Z2tv1+5Y1kY!z1nZ] $dx &()X)W1(n%@%b%%$: @t9 &X'L )X L'c )o W1(8v.8'30}t 4V }Z52 ZW15#0<|W16fd>Zؖ71?#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#  0}  0' g  0#2>40   jk k)#  ki#Q Di E)# Ei# E)# F# 6 G)# G)#+ K1#N LO#g M# E N#$b O#( P#, T#0\ U#4 V#8 Z#<P [#@ \#D ]#H ^#Lw a#P d#TE f#X j? #\f m#`O q&#d t)#h xR#lH y^#pV |>#t }J#x ~#| i# # j# v# )# # # # # # # # #g # # 1# 0#k lB oe  y Z7 $)4 ?EZZZZ kq) ))x Z)s Z )) Z7 NT)n)7< N ))  ))= 4 buf #obj #len )#  )# < Z#  Z# & #  #  #  #$ ( #(  #0 ) 0 A  Z  Z       Z  $ * Z? Z J P Zj   ۨ # 3 #  #  #  #  # = # 0 z#  z# 7 z#$ / #(  z#, #0  #4 7 #8 ) #<  #@  4#D  z#H 6 z#L ! z#P z#T  z#X #\ C #`  #d p #h #lz #p #tA #x #|> # #] # # #Y #F z# j ( T j # # `# `# + # #Z #  # #  `#$   !  "#Y ## $ # %`  ' (C#m )n# *y# +#  , #= - # .  1%1 2=CO 3[aZ{{Z1 4L 56 6Z 7 8  9( :&{ ;28RZ# < =| >[ ?? @Y Ai Bi) T    %>  &# 4 '# (Z#  *# mD n   #get #set #doc #  #P   ZG a? a$*  U 0| >  ?E# 5 @E#  AZ#  BZ# M CZ# C DZ#  E0#  F0# G0# < H0#  IZ#  JZ#  KZ#  LZ#  MZ#  NZ#  OZ#  PE# > QE# s SE#  TE#  U#  VZ#  WZ#  XZ#  YZ# " ZZ# 0 [Z#  \;#L  _4'   # 4# UZ# zZ# Z# 4# 4# z  4#;   :  # 4# UZ# zZ# Z# u# y# {#(>mv  PR>  # #  0 F  #  # # H:#Qad : # 7J 0IgZjgi34Z3;iZ 2@=!4!ZĀ"iZ#2Z$.4=X1$3Z %Jp &]+ SN'0X 2@SC!4݁!Z(3;"iZ1v$3x]1$3]1$Q3 ]1$Y3!]1)3aZ`g!%4a4!aZ5(a;"idZi*3e;#4e;#2f$N4hX1+3Z,%44ӄ,Z-3Z.iZR/3;.x;Ӆ/33;/54;1/2;/4;:/2n0x_1;pX11i4;1o4;1^4;`X11u4;hX11N4½W11V4½X114:@X11: X118ZW113ZW11ZW123  $vl((u"iZ"jZى"kZ#bZs#+5Z#֊"cx# ; #% _##r#ߋ#l "ptl # 5#;`#8;3zZE2832Z$'܌(2Z(24!2Z"i4Z*4Z#~34Z1$<4Z "d5;P4j%%N&p&&x5%%6%j'7&&x8692''<:2'o)$`L$a3ZH5))__v>__x>93p))23)*J((u1(3*Z12+ZX112,;1|2-;13/ZxX1120Z|X1131Zt]1132;;; < Fo; c; eU=(Za1; gZ;\ iZ= ;a1=^";a1 ;u'0D;44d ; 0\;;45 ; 0;36.4*.~9 0a\ intW8aio W  Z_1[ Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#  0  0'  g 5xB 6z# 4{# k 6!# "#    j kk#  k#Q D Ek# E# Ek# F# 6 Gk# Gk#+ Ks#N L#g M# E N#$b O.#( P:#, T##0\ U)#4 V/#8 ZF#<P [ #@ \:#D ]#H ^"#Lw a5#P d#TE f#X j #\f m4#`O qh#d tk#h x#lH y#pV |#t }#x ~#| # # # # k# # # # U# 4# # # #g # # s# 0# l e   4y ?EZU7 `fkv Z k kkx Zks )/ZNkk Y_Zy kky<  kk  k k 4 buf #obj #len k#  k# < Z#  Z# & #  #  #  #$ ( #(  #0 k 0  A  Z  Z   $ 5   @ F Z[  f l Z Z ٌ  Z [  # 3 #  #  #  #  # = # 0 #  # 7 #$ / 4#(  #, #0  #4 7 #8 ) #<  #@  v#D  #H 6 #L ! #P #T  #X #\ C #`  #d p #h #lz  #p #tA #x #|> # #] # # #Y #F #  (  j U# # # # + # #Z # 5 # #  #$   !  "U#Y ## $N# %  'I (#m )# *# +#  , #= - # .  1ags 2 3ZZ1 4L 56 6Z" 7Y 8@  9( :RXh{ ;tzZ# < =| >[ ?Y? @YY A B#k   I  %  &# 4 '# (Z#  *# ;m n   #get #set #doc #  #   '-ZG?IgZng4Z**N4ZresZm4"}*?+‘"4"}res$}m% 45@+++v545res7cm85K}+(,tvVBh5]0,A. str],]Z!tm_}i`Z6"ka}^1"%5b]1tvqBh#N,9$aJ#N- V$ab#N-0 s$az%N.X &aZ } 0 4P..W Z"4h'' ' k26.=.< 0a\ intW8aio[g Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#n  0g  0' ?  v v# # UZ# zZ# Z# # # z  #     v# # UZ# zZ# Z# uv# yv# {v#$N z # UZ# Z# N# ^# ^ 0 n 0 o { v# U!Z# "Z# ## $#  0  0  MMMZM%?1M1 11%~88 88%5 .9/֓8 5 v5 Z6@//85v5Z|&6#/0.8#b#6#Z i'ZȔ6(t(D)G580y1g888 2:5;SD5@ 0a\ intW8aio[g Z#d#N## a# ####   #$T!#( "#,v$#0,&#4/(Z#8,Z#<.z#@2>#D'3L#F34#G8#H#A#LJ#TF K#XL#\%M#`,N%#dsPZ#h&R#l     # # Z#n  0g  0'  0   0?|> ?# 5@# AZ# BZ# M CZ# CDZ# E0# F0# G0# <H0# IZ# JZ# KZ# LZ# MZ# NZ# OZ# P# >Q# s S# T# U# VZ# WZ# XZ# YZ# " ZZ# 0 [Z# \#6 Z =B>Er Y Z3 iZdˤdiޤcxd6 e % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I : ; &' II : ; I8 ' : ;I : ;<  : ;  : ; (  : ;  : ; .? : ; ' I 4 : ; I : ; I!.? : ;' I ": ;I#4: ;I$.: ;' %: ;I&4: ;I'.: ;' I@(: ;I)4: ;I*4: ;I +4: ;I,: ;I -4: ;I . /1X Y011.: ;' @24: ;I3!I/41RUX Y5 U64174184: ;I 9.: ;' I@: : ;; : ;1RUX Y?.? : ;' @@.: ; ' A4: ; IB4: ; IC.: ; ' I D.? : ;' I@E : ;F41 G1H1RUX Y I1RUX Y J UK1X YL4: ; I M4: ; I? < N4: ;I? < O4: ; I?  % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I' II : ; I8 '  : ; : ;I : ;< '  : ;  : ; ( .: ; ' : ; I: ; I4: ; I.: ;'  : ;I!: ;I"4: ;I#.? : ; ' I 4 $%4: ; I&.: ; ' I@': ; I(4: ; I )4: ; I *4: ; I+4: ; I,.1@-1.1 /4101X Y1 2413.? : ; ' @4: ; I 51RUX Y 6.? : ;' @ 7: ;I 8.? : ;' I@94: ;I:4: ;I;4: ;I <.? : ;' I@ =4: ;I >.? : ;' @?.? : ;' @@1RUX YA1X YB1RUX YC!I/D4: ; I? < E4: ;I? < F4: ; I?  % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I&' II : ; I8 '  : ; : ;I : ;<  : ; (  : ; .? : ; ' I 4 : ; I: ; I.: ;' I@ : ;I!: ;I": ;I #4: ;I$4: ;I %4: ;I& : ;'1X Y(1)1X Y*.? : ; ' I@+: ; I ,: ; I -4: ; I.4: ; I/.? : ; ' @0: ; I1.? : ;' I@2.: ;' I 3: ;I44: ;I54: ;I6 : ;7 8.? : ;' @91RUX Y: U;41<41 = 1> U?1@1RUX YA41B4: ;I C4: ; I D!I/E4: ; I? < % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I : ; ( : ;I: ; : ; .? : ; ' I 4 : ; I.? : ;' I : ;I: ; I.: ; ' I 4: ; I4: ; I .1@1 41! "41#1RUX Y $ U%1&1X Y '1RUX Y (1X Y )1 *1 +.: ; ' ,.: ;' I@-: ;I.4: ;I /4: ;I01RUX Y141 2.? : ; ' I@3: ; I 4: ; I 54: ; I64: ; I7.? : ; ' @8: ; I9.? : ;' @:: ;I ;4: ;I<.? : ;' @=!I/>4: ; I ?4: ; I? < % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I : ; (  : ; ( .? : ; ' I 4 : ; I: ; I.: ; ' .: ; ' 4: ; I.: ;' .: ; ' I 4: ; I.1@1X Y   !.? : ; ' I@": ; I#4: ; I$1RUX Y %1& U'41(1X Y )41 *1RUX Y +1 ,.? : ; ' @-1X Y . /1RUX Y 0.: ;' I 14: ;I24: ;I3.? : ; ' @ 4: ; I 54: ; I 64: ; I 74: ; I84: ; I? < % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I' II : ; I8 '  : ; : ;I : ;<  : ;  : ; ( .? : ; ' I 4 : ; I.: ;' : ;I4: ;I .: ;' @!: ;I"4: ;I#4: ;I$4: ;I %1RUX Y&1'!I/(: ;I ).: ;' I@*4: ;I+.: ; ' I@,: ; I-: ; I .4: ; I/4: ; I04: ; I 14: ; I 2.? : ;' I@34: ;I41X Y5 641718 U9.? : ;' @:.? : ;' @;4: ; I? < <4: ;I? < =4: ; I?  % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ &I' II : ; I8 '  : ; : ;I : ;< .? : ; ' I 4 : ; I.? : ; ' I@: ; I 4: ; I4: ; I4: ; I .? : ; ' @ : ; I !4: ; I"4: ; I #1RUX Y $1%1RUX Y &1 '4: ; I? < % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/ & : ; .? : ; ' I 4 : ; I.? : ; ' @: ; I 4: ; I4: ; I.? : ; ' I@4: ;I4: ;I4: ;I&I.? : ;' I@: ;I 4: ;I 4: ; I? < !I/ 4: ; I?  !4: ;I?  % : ; I$ > $ >   I : ; : ;I8 : ;  : ;  : ; I8 I !I/  : ; .? : ; ' I@: ; I 4: ; I4: ; I 4: ; I? < Y /usr/include/i386-linux-gnu/bits/usr/lib/gcc/i686-linux-gnu/4.6/include/usr/include/usr/include/i386-linux-gnu/sys/usr/include/python2.7/usr/include/netinetquisk.cstdio2.hstring3.hmathinline.hsocket2.hstddef.htypes.hstdio.hlibio.htime.hselect.hstdint.hpyport.hobject.hmethodobject.hdescrobject.hcomplexobject.hpystate.hfftw3.hsockaddr.hsocket.hin.hquisk.hfilter.hfloatobject.hsocket.h C2IguLH0K2/wJ;x/WNe@\bgKL_  kg.q<Jdtef *-Lh,hei/ -L/sY-L/sY-L/sY-L/{*-L/sX-L/$-L/A-L/--L/4-L/4-Me=,iz-L/tY-M/ -L/|XvY-I"סel/yJ-M=t-L.3-M,lY-LY/nJu-LuY;/YaY-LYYY/}-Lu/z^-LY/u-L,~Zq䟑eg2g3a䄦bgVdX tDx. ;NNxeu.zucJteu.&eK;i% mu)u6upXfpJ$p<X! Xf m<YYZ,0a.a.afa.a<</` <W.h$m3vh,2#[%ptjJtmj<ggm.mfXZry)YegsgYsnXnfjX/Zy<u-L[-Lg^u-Lf  durMe/&e=&K0//g;",i+a< KK*$ 1z.!O)KI==Md0,02g>:wUKu9L,YIK/pfJE<.;E<<<-̌uzz< dM==xXuf=׽S~J .v. .>gge=e=f, d\ %.;\<%<g;0sX 30##I.ffe=.Jeg<.sXJ.<<g1uhVlYi++Ke,xJKHRxJ 9(Hg,hc1dL,gcgg=A_.;r tsf tm<fm !J.~hZ:0*AXAaA)AaOg@ee/dfX-I=t /-CKIMtX O].?zf1J=-u-Lf  -KhK؟gYg"_.!J_#!eH>H K-B/;HZk!,k<<kff K;=w>Xg=2;oS\,f-$eueO~j*-=pg /;=Nu-LKffu-L!r p.ftzY<t,/R!gf"$K]t<䑁=I.!z.zXzJJzt.ztfzfJu <=It)#h)n1d)Pg"=Im=/x(}t  s.x )>?hf.hfK;>,LV0;:/e3=t,g <{t|Q   x 0j+wdh..Pb.v=UKu90,gr{ {M<+- ;hIs$s st XsJ <s< XmYs Js TuJ  t@egLqM=t}f}Jf/uu=mxXLr-K/'/-L2XtJI)fe-g?9g&0-JJeg˭O)JgL,ef.JF@+1+~.<~.tI=Q~J|ff|X~t.~<.Ys.?~ff<Whz V|ff|ftf.ug=;hZg %l"A(Keg-gK-gheX} f=}<[2-gQeg;0/K-LY/weg;2f:g#-K/-=2etKg/~=vXsK-g-=r"sK-g-=kJLvgeK";=<uvLYe/zf|x< 2ug_)LvgeK-=h;0zJ*uU :g%#-K/-=lJ:g%s/#-K-=2svb:g%s/#-K-=`yf.yyytyf.#%%%%w% X!uYqJXa(0u-M!t$\,0d>!gg廝lflfe==>K-gJ;=-YIKIgjf/ɏguuy/lz s.ZYegqYYggYpwtxF","u/-/-u/-0egjv f)-=;g;g0v$zfh9htJ te=<}$hLs-ggu u .8f%yt s>&0Je{/->|Xe=W>@@wq|:j*u,d%-/u~t.Y/~<~X.=;vuyt<A-,Ige=;>1L4 f+z}f.|;>}f.:If?Jesh;//-91/LY;uX Z}t/0g=0xf >,g;=   -g-ZpYz,4ef|.=/-0eg<w# nyJGg-he=~~ue=~~ @t}}t/0b>,g;=vtK .vh .vt@w13xtM4oe/KAlx,xxx ,uM./-S|t-=x>P1w:XL-e=y+|tL+'2A,%rhe=9>1vԆpNA~f.k)yJ~<.;}t/0g=0xf -+g0<;=I+ȃ~X{iuXA~f.k)yJ~<.; ֶ~f.yf;=}f.;ҵ~f.zf;=~f.;8~f.g-uJ~<.;v~f.g-uJ~<.;q-g'JgW:vVgW,wڎI=;K ,u~#r ȃ jf<jtsY;K$r frt rJ  ʑ/CyJttrX -X.YrX 'r< tt~Jf;=~fJ-.~.tvtR}/Iu/Iu1Gw/Iu/IuJ~X{T-=;/hg/SRVLtBh-Y:\/pdtgV=IgZ&Zt&JXJ0e'JY'f\v Xv $䭟wR  a)kg Pg;/iY<e0eg-K/gI/iv OXו1cirhMY>\~~fJ~JX~f.~ffI404i $~׻X׻~~.fAzy tu fp xs=]7kYsuW5y_y.mdt/u!tX!1-Gi[zdL$v/s=<'-L/'-L/'-L/ $*YYYYYZ&-L f/zf={Xȑq{Jȑ D /usr/include/i386-linux-gnu/bits/usr/lib/gcc/i686-linux-gnu/4.6/include/usr/include/usr/include/python2.7/usr/include/alsasound_alsa.cstring3.hstdio2.hstddef.htypes.hstdio.hlibio.hpyport.hobject.hmethodobject.hdescrobject.hpcm.hcontrol.hquisk.hf}}1c0-;KiJfqK/KdL僀KgP=u=un[ee-/; fJXK-;KiHJfxtWuv=H>wffxXJ|xJ|'~P+IK-g/ (v.LeKu{$.!~..~ IY=:>eKdL~ JIKXjfwJ~u! v=J<.IYY:>eKdL<jfwJ v"!...'=KKKwJuMeg+0/G/~fX~.~fX~fJKXjfmJ]vYs#\*s/Ys/Ys/Y/Jzz.fzJaɄ~kL{t{tX釟AB"ɟIg$$B幃K:B(}֤L|t|tX釟AB "ɟ||f|Ig$$幃KI<u :ByLzf|4~~%|%:}|?{C|{|?|:{:"!z+!{8H.8*f{f{JHX{{:{zzzz#XM;zvy1cnst NG1-gg1cMuqQ JgIH.;Jd:>geI-=0,lYekuycK5<K.6Je=t^.0.u N[M9g9Lf9g/gMgyz< fMn<~f~XzuzfBzȘV M/IX=eg*!gg-~g ==uv֜=u- =;//=sKYsKeKef$=/=;,vi+\<%gKK*&  -/d.g.s=s";=u-=vz>Bweg-1:>G[cu/;0UY3==x$zz;YK"Jt<Iy.oJJo<<o<= wJ xK-?:0,O1V=U-Oe.Jn.wX fq<Juqfzz;YK"Jt<Iz.IYnnK-?:0,K-1V/;0U-3w Jq<JtrJ{yJPy.w< =38v=/+M+M9MqMG=UY-Luq<tu{yJP+8v=/q1Mg/;LUY-k"Yq<.r&z.myJQs:==q1M/;>UY-k;K/t<<s tJ v-~f<~fX>~t< tstfbg~tJC~tth s<<<sss///////KggsssuX JKK///////Kguutf wJ J}Jt}<Hu/kJl.~i.Ji<.=v-=-0y lK-/-=/f wJ J}Jt}<Hu/}i.=h.h<=ILy.A>yX lK-/-=/ /usr/lib/gcc/i686-linux-gnu/4.6/include/usr/include/i386-linux-gnu/bits/usr/includeextdemod.cstddef.htypes.hlibio.hquisk.hstdio.h = Xp.w`zuPYw t@AtAOtOt0ttttt 5 t5 6 t 6 7 t7 8 t8 = t@ A tA O tO ~ t ~ t t t t t P W P V  t  t H t H K tK L tP Q tQ _ t_ t t t  t ! t! / t/ h t h k tk l tp q tq  t t t t  t ! t! " t" # t # & t& 7 t7 tttt ttit ~i~ 0-1V P ~~d~ PHSPdDIdbd~pqtqrtrut uvtv|t|ntnotoptpqt qrtrxtxctcdtdeteft fgtghth@t@AtABtBCt CDtDEtEctpPwPpRWPPP+Q+`WhlWwREPPpw8wEEc8+0+=PB`P0RhwP0$W0CWEP0PWR P\ [qPc [qWP^Wz0WPc0z #B ;r3$v"r3$v"[Pc #B ;r4$w4$EPw4$PwſEPVPcſpqtqtt ttttt0ttttMt MNtNOtPQtQRtRSt STtTbtbTtTUtUVtVWt WXtXYtYftJ\0l{PEU0`R@]0Wv"@PpPYfR00V&VKpVpvV0VYf0a0 @ PE@{15]H]a10W,W,.0a0/EH@BPBM@E[\ v4$T"E H3$P"Y[[[fq3$p"[M [\[Yf  \\Yf $P$MPYfP26P6TWT{@JVPVU]X]aUPMTYfTP~ [[*[,. [\]@pqtqrtrut uvtvttttt tttttt ttH tH K tK L tL M t M N tN O tO o!t0126B0PkRCf~uR08U0W0`f0V0P~  03 ; UW!o!~gyR60W WW!o!0Q4!;!Q# ##fVsVsL VO V W!o!V*1P1WP  P M WM O P\d[ 3$"[[O { \ \[V`~`f[f~ HgH4!G!H PPP4!G!P\uU!W!\p\O { \ \[O k [ [\\O o!\^^O o!^p!q!tq!t!tt!f"tf"g"tg"h"tp"q"tq""t""t ""t""t""t""t""t ""t""t"t&tt&w&tw&x&tx&y&t y&z&tz&&t&&t&&t&&t&&t &&t&&t&'t""P"%@%%P%%W%q&@{&'@""R"'H|$%V%%P%%V{&&V&C'V##0`$f$Vu$|$0$%Ut%%U%%0%%R%&0e&q&W&&U&&0&'R5'O'0V'v'Ru$|$P|$%W%&&K&VK&Z&Z&[&v[&q&V{&&W&v'W""P"&&'$$[$$$%[]O%S%PS%d%PXd%s%[]&&p& &pp &C&[C&q&P&&[&&''t''t''t0''t''t''t''t'J(t0J(K(tK(L(tP(S(tS(5)t5)8)t8)\/tP((P()W6)*W,\/WP((R()V6))V))P)W*VW*q*Pr**P**P**R,E,VE,_,P`,z,P{,,P,,V,,P,-P-1-V1-K-PL-g-Pj-o-Po--V--P--V-.P..P..V..P.A/VA/F/PF/\/V+,X()X6)*X,\/X`/a/ta/b/tb/c/t c/d/td/r/tr/00t0010t1020t2030t 3040t4050t50Z0tZ0[0t[0\0t\0]0t ]0^0t^0_0t_00t`//R_00R////[\00[\00//P//V/ 0p00P00P//0000//r q+ "_00r q+ "00t00t00t 00t00t01t11t11t11t 11t11t11t11t11t11t 11t11t1[2t0 1R12RI1b1 b1l1[11[11[N2[2 I1b1 b1w1\11\N2[2 I11P11p11PN2[2PI1b10N2[200 1r q'"12r q'"`2a2ta2b2tb2c2t c2t2tt23t33t33t 33t33t3u4tD334~p4u4~p4u4~234~p4u4~s3z3~33oC33~434I434~44t44t44t 44t44t4:t::t::t::t ::t::t:.<t44P4.<44R4.<550u66V660#707P77088Q8N8P88Q99B9099 F;N;0N;t;V;;V8?8pw"?8N8pw"1N8p8Vp88qr"88rq"177P78 8^8W^88R550r69::W660 79:-:Y:y:4850=5K59957U::U55P55V56W6r7V::V-:o:Vy::V55P59::77P799U6&6[55 r69::66  77[:-:[Y:y:[0<1<t1<2<t2<@<t @<W=tW=Z=t Z=[=t[=`=t`=z=t==t==t==t ==t==t==t==t==t ==t==t=E?tE?F?tF?G?tG?H?t H?I?tI?P?tP?Ht=>P>>WJ??W??WX@w@W@:AWBCWCUDWD;EWEFWFFPFFW=$>R$>2?UJ??R??R?6AU6ABHBBRBFUFFRrHHU=t>t>>P>>P>2?J?AA:AP:A3B3BMBPNBhBPyBBPB C CCPCCCCPCDD>DPEDUDPUDDDDDDPDERE(EP/E;EP;EEEEPEEPEEFEFIFPIFUFRVFxFPFFPFFFrHrHH>>0>>Vv??0??V??0@'@Vk@w@0@@VA:A0ABV CC0vC|CVEDUD0DDV/E;E0nEtEVFF0FFVHrH>> X@'@ X@@ XmAsA\XCCRC X{DD XcEtE XFF XAAuXjCoC\AA[SC^C[HHtHHtHIt@IAItAIBItBICIt CIDItDIRItRIMtMMtMMtMMt MMtMMtMMttL~L0LLRLL0MMUMM0LLv2MMuL"JJPJJYKmKPmKKKKPKLMMtMMtMMt MOtOOt OOtOOtOOtNO\NO`OOdNOOh0OOlOOtOOtOOt OOtOOtOEPt EPFPtFPGPtGPHPt HPIPtIPPPtPP[Pt [P\Pt\P]Pt]P^Pt ^P_Pt_P`PtOP0P PQJP`PQPP[`PaPtaPbPtbPcPt cPdPtdPjPtjPRtR Rt R Rt R Rt R Rt RRtRStSStSStSSt SStSStSTtTTtTTtTTt TTtTTtTVtVVtVVtVVt VVtVVtVot`PQQQV R^^^P^^U^^P^e_~e__V__P__V__P_bVbcc!dV!d5g~giiiPijVjjjl~lkmVkmmUmmVmmmn~nnVn6o~6ooVQQ0QQVQQ0RS0SHSWSSWSSPmTxT0TTRTIU0UUW)V]VWVVQW WR\\WF]Q]W]]0m^^V_,_06_J_P5`J`0h``R``P`a0a3aR9aTaR\aba0b=bWcc0ccPd!dPii0ijRjj0k.k0kt>?t?@t @AtAHtHtttt tttttt tttttt tt^t*P*8VBNPNVPVVV8RBaRaWRW'R'WW 0UT0BXX^X8B^^^^`ctctt t`PVP1VV`RRW&10U\1\X`X X^V ^ t " t0" # t P X R  V   R  V P X  P0 1 t1 2 t2 3 t 3 4 t4 t t t t t0 M 0y Q` f wf i [` y wy } [ t t t t t  t   t  t * t P * P R Q r R p P  R * r p H  V * @  Q( * Q0 3 t3 t t  t t X tX Y t P  h  XR t t t t t TtTUtUVtVWt WXtX`t`t400 # @# ) P) VY@VAV@%VV$@$GVpzVPP 0 V$R$DV<AP%V0OVG0]V[b0bhPhVPV0RR P7   @@@600%[1101 a1 Y,,95 9A%GpzRwX  wX[    @AtAOtOt ttttt tt0tt ttt0(6 , q-(tYt Y`t`t tttt tt ttt,VVtt:t :=t=>t@AtAOtOt ttttt ttttt t t tt$P$Vtt t0  t t t0  h8 c hl httfufhthu1P1~ R ~E~]~)=PI[PPgxPP]dPE~]~PWPOWgW P,P,tRQURU~dVgVORgER]RO~gE~]~&R&d&~OROdO~OROO~yU>X~XdUdu}[UxKUpU u} U~UU![UU"9UKUUU u} UUPP%1PAOPPP|PPPP")PPPPPP u V!+V&KVV V!+S!+$VpT*9U*9&T&dUUUV4UXdUdu}!U "U9UpUUU,8PJVP^jPzPPPP!P P9@PPP.5PpwPb}u}4VpVVV~!~x~"~9~p~~~~~!~x~"~9~p~~~~~!~x~"~9~p~~~~~!~x~"~9~p~~~~~!~x~"~9~p~~~~T"TV"AKxVAKxlWxTqSS.W.6E$N$P%&%P""P"K#V$9$V$%V%#&V#K#W#K##K#~##S####~%%W%%%%~%%W%%%%~tctchthtPXRR:PRdlRyRR7:@d@NPXyXPWP:WP0VPU:UXyXy:VV:X#:JX:JX#JJXJttt tttttt tt.t.4t45t56t 67t78t8FtPV5V8FVRFbiPiW8JWPW P +Wb\J\\+\PHQH+W+9D9HuAF#W @DLWPQtQRtRSt STtTWtWtttt ttt0\cPc0PP0~PQ\<W<_w_W\W0\[PP u2$`P-"[[ttt tt3 t3 4 t4 5 t5 6 t 6 7 t7 8 t8 j tj k tk l tl m t m n tn p tp t. 8  W  Wo  0  P  0 0 Q X  Q  X P$ . Qv 0 Q X  Xo 0$ . R\ R ? #o R # [  \@ S P  t  t  t   t  t J t0J K tK L tL M t M N tN P tP t0 p U P, = P 0 ) ) G Vv  VF R R s V P Z Z v V  Q   = Vs ~ ~ W t t  t  t ttNt NOtPStStthtPVP0DHPHIV~HU~HDIH~  ~YYkDIhHHDIH0D0Ih0DIhpstst0tt0tt0t&t0l03t3ttt@@22XXܖqT,uTT#+[Tttt ttKtKLtLMtMNt NOtOPt3P3@V-CP@R@OU)@0WfzPzH(-PrYPQtQRtRSt SVtVltltttt ttctP[P[VPcVPRc0 UU0pqtqtttut uvtvytyKtKNtNOtOPt PQtQRtRtpPVACPRZPpRCURsRsU0AWAC0[\[ \t \]!\]ttt tttttt tt t t t  t   t  t ( tP( HRUP$U$VRVU a Ra ( U0WW,:0WW0 W[[[\HJ[:<[X[[ ư> ư> `]][[\ ?\ @w+A   ? [$ ?[][eg[6;\[;X\t\X[\"'\['\t\[\X\[\:KvvKP\[P\t\]\]0 1 t1 2 t2 3 t 3 4 t4 B tB t  t  t  t  t tt  0] k Vk } 0 Q} 0 P 0 0 P 2 0> V R*0_rVrw"0  u2] k v" 0 V V*R*@W@_w_nWr0W 1E i i m 1 0 W 8 W8 : 0P w} ? [   ? P  V k D P HH P PP P TT P  W k  P LL  [ [ 6 [8 :  [ \ i  !t!'t'(t ()t),t,tttt tttttt ttt VPQQeVehhVVVP.V.WVV\V\PRV,i0Q.0pV0R,i1Rppp[[V0RR0\V\<0<BRI\Rttt ttttttttt ttttt ttt tDt DHtHt hxPxW^gPgVtt0t/t0[P/V03t3tt0txtxt0PPPVttt0tt #t#ttxtxt1t0Z]ZZ@AtAItIt0tttt0ttt0t !t!"t"#t #$t$'t'tttt tt1t0U U[\[\qu[u @[@AtABtBCt CDtDttt tttYppu[\[\Yp #psrswRr #Op #p|P|pP #Yp0pwQQ0ttt tt|t|}t}~t~t tttCl0euT0(?P0R0Cl0XeuX P3$"V P3$v"#QqQQ\[ttt tttttt tt't,0TCf0Qv0R0,0CfXXv L3$"V L3$v"q#QqQQv [ 01t12t23t 34t47t7>t0>?t?@t@At ABtBCtCIt00]0$7T0RCI00]07\qX#PpPCIPqXCIW\[CIPQtQRtRSt STtTWtW t( !t!"t"#t #$t$%t%)t(Px0 t0R%)0Px0\qd#PpP%)Pqd%)U [%) 01t14t45t 56t69t9t(ttt ttt(0S0q0R00S0Q\nud#PpPPqudWh [   t  t  t   t  t t t t t t t5 J 0 U U J 0 P P) 1 R1 T5 > R> X  t  t  t   t  t t t t t t t  tK r 0 0K r 0 w W) <) F  [K M PM P ! t! " t" # t # $ t$ ' t' 2t23t34t45t 56t67t7ctk 0/U 0k 0I 7<I 7F  \[k m Pm 7Tttt t  t !t!"t.T0QQ[w_\r3384p444484W WYFZsZ[AcCcdcfcnccgiW WYFZsZ[AcCcdcfcnccgi WY[\PbAcCcdcfcncgg WWWY[\PbAcCcdcfcncggaaaaa"bmmaaaaa"bmmaajAjHjjaajAjHjj(d.d;dCdJdVdXd5g(d.d;dCdJdVdXd5gddNfzfff g5g[ppBJ` 1.symtab.strtab.shstrtab.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.ctors.dtors.jcr.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_str.debug_loc.debug_ranges$.o888 HH@Ho))Uo++d ,,Hm 22 v77.q08080 |`B`BxBBCC \\``hh~pp~xx~||~ddHk c/ 0* 2A096&]p 1g ?%'"h Lj'8H)+,27 08 `B B C \`hpx|d hp(x5`B KZhB tlxxB  C h`D 8@XH'P0 Eu <Jx^pqEG yPE= 0F= pF= FQ GG L`GG GG HG PH[ Hi   IG +ApI= QIQ ^J kyKN `KK K `LB Lf  ML pM @NL N 48#488I0Y,m@PI yx'`B8 8 R   ` hd& 6lHZ c vV@ VV 0W? pW \   d *e? 6e ;$JV bpj_ k\ pk   r}  + (t{  '( u w $z 2+ C{ @Q ] @l @|       @{ @` `  @ @; @P % ; 3PJ @xO]`h] w    n `c  А <0@?DOHcduXhp\@ H X! T1 <= DM P` u       0      0$ 1 I < ВO (a l     @0    @ ȅ ؃ x  ^  8 # . 5 8 > 8 L @J Y 8 f `2 v 8  8  /  s h @   ( $ , 0% 44 - @ - U @2 h `3 s 6  @8  H8  `8   5  0   @,  Ȗ  $  0 0 > A%@F @<"pA%N 8 V I)@^ @P-k }  P `P-@  O ܖ W1 ؖ W1 W1 W1P "-X1: It]1P@ ax]1n]1|]1]1`- X1  W1@X1 W1 X1  pX1 `X11hX1AW1S_W1p X1 xX1|X1X1$ & & % % o% U% >% ]1P^1[` (`[` 3>ITjwtܺ B P>& C |  /B( Wz  ^1;+8 HY7 0   )a "  3ay       3 I\m*  ^1N $B ? u O$^1c) j /@Chw  X@( 0' ?a1UjpN  b . 0BQap  : 6 2H`|`X@3   2Ti ~0, @^1| &P.U 9'1 I ]j@+   ="  #2I6 W@h gz)Cqa10 %7N_p;C (^1$| *AZfp  }   + h?  N j  *  (   9 !!,^10!C!f!!(!!a1!!!!@* " "a1 ","<"H"k"}"""/ ""0^1"## '#I#d#v#1 ####  #$: $4^1%$ 7$4 G$Q$`$2 t$ x$$$$$ %"%G%^%@/ o%%pc  % %%"%@% N &!&J&p&p)' &&&&'  '7 '8.'^'crtstuff.c__CTOR_LIST____DTOR_LIST____JCR_LIST____do_global_dtors_auxcompleted.6159dtor_idx.6161frame_dummy__CTOR_END____FRAME_END____JCR_END____do_global_ctors_auxquisk.cIsSquelchsample_ratesquelch_levelcurrent_graphquisk_process_agcagcReleaseagcInUseagcOffGainagcMaxGainagcLevelchange_rateaverage_countrx_udp_gain_correctrx_udp_read_blocksset_fdxisFDXtest_3test_2test_1set_tunerx_tune_freqset_split_rxtxsplit_rxtxset_volumeset_noise_blankerset_squelchset_agcrecord_graphgraphScalegraphYgraphXinvert_spectrumquisk_invert_spectrumget_audio_graphset_key_downclose_rx_udprx_udp_socketrx_udp_startedopen_keyget_squelchmixer_setstart_soundread_soundclose_soundadd_tonetesttonePhaseset_rx_modeset_record_statequisk_record_fullquisk_record_indexquisk_record_bufsizequisk_play_indexquisk_mic_indexquisk_record_bufferset_filtersfilter_bandwidthcFilterQcFilterIsizeFilterQuiskErrormeasure_freqHalfBand1.14141HalfBand2.14142HalfBand3.14143index.14134samples.14137fft_window.14139planA.14138fft_count.14136fft_average.14140measure_freq_moderit_freqmeasured_frequencyget_smeterSmetermeasure_frequencyget_overrangeget_filterfft_windowget_graphuse_fft.14029count_fftptWriteFftfft_sizeuse_remove_dcfft_avgmeter.14028get_statefft_erroris_key_downXdftfft_size.14171planF.14173planB.14174samples.14172fft_window.14175idftdftquisk_process_decimatequisk_decim_srateStorage.13599dRxFilterOutinit.13484Storage.13488cRxFilterOutinit.13501Storage.13506open_rx_udpdAutoNotchplanFwd.13424quisk_auto_notchdata_in.13428index.13423data_out.13429notch_fft.13430average_fft.13435count1.13420old1.13419old2.13421count2.13422fltrSig.13436fltr_fft.13434fltrRev.13427fltr_out.13433fft_window.13431fltr_in.13432fltrFwd.13426planRev.13425set_sidetonesidetoneVolumesidetonePhasekeyupDelayset_auto_notchquisk_process_demodulatequisk_demod_srateStorage.13650quisk_filter_srateget_filter_raterecord_apppyApprx_udp_clockis_little_endianFFT1FFT2FFT3open_soundsize_dsamples.13715dsamples.13716dsamples2.13717orig_cSamples.13718playSilence.13728dOutCounter.13724keyupEnvelope.13727sidetoneIsOn.13725sidetoneEnvelope.13726sidetoneVector.13723sample_rate.13377cSaved.13369index.13375save_sum.13371dSaved.13370save_size.13372state.13374win_index.13376hwindow_size.13373testtoneVector.13516audioVector.13517rxTuneVector.13721HalfBand7.13730HalfBand8.13731HalfBand9.13732agcGainReal.13719is_squelch.13729in.13360c3.13359c0.13356c1.13357c2.13358out.13361dindex.13355CSWTCH.436txTuneVector.13722agcGainImag.13720seq0.13879dc_key_delay.13893dc_average.13890dc_sum.13891dc_count.13892QuiskMethodsQuisk_API.14250.L525.L526.L527.L524.L528.L529.L530.L531.L532sound.crecord_samplesremain.11120file_name_samplesfp.11118samples.11119record_audioremain.11102file_name_audiofp.11100samples.11101PlaybackAddCardcorrect_sample.part.0.constprop.2cSamplesdelay_sample.constprop.3time0.11072calls.11070total.11071pt_sample_startpt_sample_stoppt_sample_readwant_recordis_recording_samplesis_recording_audioMicCaptureMicPlaybackcwCount.11149cwEnvelope.11148filtInterp.11151tuneVector.11150DigitalInputDigitalOutputdigital_output_levelCapturePlaybackDevicesCaptureDevicessound_alsa.cdevice_listcheck_formatsbuffer4buffer3buffer2bufferzhandle.15639sound_portaudio.cquisk_pa_name2indexquisk_open_portaudiofbufferis_key_down.cclose_key_enetkey_socketkey_methodfdkey_is_downkeyed.11875time0.11890microphone.ctransmit_udpmic_socketudp_iq.13386udp_size.13387align4transmit_mic_imdphase1.13407vector1.13409vector2.13410phase2.13408tx_filter_digitalfilter1.13321tx_filtermic_decim.13304filtDecim.13301filter1.13299filter2.13300gainA.13295x_1.13294mic_max_gaintime_short.13297time_long.13298sample_rate.13305gainB.13296mic_interp.13303filtInterp.13302mic_avg_gainmic_levelmic_timerspotLevelmodulation_index.L145.L146.L147.L148.L149.L150.L151.L152utility.cstart_time.10978time0.10977filter.ccoef.11226coef.11245extdemod.cfm_1.10958fm_2.10959_GLOBAL_OFFSET_TABLE___dso_handle__DTOR_END____i686.get_pc_thunk.cx__stack_chk_fail_local__muldc3__i686.get_pc_thunk.bx_DYNAMICquisk_play_alsasnd_ctl_elem_value_set_id@@ALSA_0.9snd_pcm_info_get_name@@ALSA_0.9PyModule_AddObjectquisk_set_ampl_phasesnd_pcm_sw_params_malloc@@ALSA_0.9quisk_set_key_downPyString_AsStringconnect@@GLIBC_2.0snd_ctl_elem_id_sizeof@@ALSA_0.9snd_pcm_hw_params_any@@ALSA_0.9snd_pcm_close@@ALSA_0.9quisk_audioVolumesnd_pcm_info_get_id@@ALSA_0.9QuiskTimeSecfftw_plan_dft_1dsnd_ctl_elem_info_get_min64@@ALSA_0.9quiskFilt240D5Coefsquisk_cDecim2HB45snd_ctl_pcm_info@@ALSA_0.9shutdown@@GLIBC_2.0quisk_dC_outquisk_record_statePyInt_AsUnsignedLongMaskquisk_set_spot_levelquisk_open_soundsnd_pcm_hw_params_get_rate_max@@ALSA_0.9.0rc4snd_pcm_start@@ALSA_0.9snd_pcm_hw_params_get_channels_min@@ALSA_0.9.0rc4quisk_start_sound_portaudioquiskAudio24p6CoefsPa_ReadStreamquisk_sound_errors__gmon_start___Jv_RegisterClassesquisk_sound_devicesquisk_set_file_recordrealloc@@GLIBC_2.0Pa_GetDeviceInfoQuiskGetConfigDouble__printf_chk@@GLIBC_2.3.4snd_pcm_prepare@@ALSA_0.9quisk_sidetoneCtrlquisk_capt_channelsrecv@@GLIBC_2.0quisk_using_udp_finistrncpy@@GLIBC_2.0snd_ctl_elem_value_set_integer@@ALSA_0.9quisk_read_alsaquisk_noise_blankerptimersnd_ctl_open@@ALSA_0.9fftw_plan_dft_r2c_1dmemset@@GLIBC_2.0fopen64@@GLIBC_2.1quiskFilt111D2Coefssnd_ctl_elem_value_set_integer64@@ALSA_0.9cexp@@GLIBC_2.1snd_pcm_hw_params_set_rate@@ALSA_0.9quiskFilt185D3Coefssnd_ctl_card_info_get_name@@ALSA_0.9PyComplex_Type__memcpy_chk@@GLIBC_2.3.4quisk_read_portaudiosnd_pcm_hw_params@@ALSA_0.9snd_ctl_pcm_next_device@@ALSA_0.9quiskFilt133D5Coefssnd_ctl_elem_info_get_max@@ALSA_0.9quiskFilt185D7Coefsquisk_open_micquisk_mic_preemphasisPyComplex_AsCComplexquisk_micplay_channelsperror@@GLIBC_2.0PyFloat_FromDoubleexp@@GLIBC_2.0snd_pcm_state@@ALSA_0.9quisk_close_soundPyArg_ParseTuplesnd_pcm_open@@ALSA_0.9gettimeofday@@GLIBC_2.0quisk_filt_cInitstrtol@@GLIBC_2.0PyErr_Occurredfree@@GLIBC_2.0Pa_StartStreamquiskLpFilt48Coefssnd_ctl_elem_info_set_id@@ALSA_0.9quiskFilt53D1Coefsquisk_process_samplesfftw_plan_dft_c2r_1dquisk_dDecimatePyCapsule_NewPyFloat_Typesnd_ctl_card_info_get_id@@ALSA_0.9PyComplex_FromDoublessnd_ctl_close@@ALSA_0.9snd_pcm_sw_params@@ALSA_0.9quiskAudio96Coefsquisk_dInterpolateioctl@@GLIBC_2.0quisk_close_sound_alsasocket@@GLIBC_2.0snd_pcm_delay@@ALSA_0.9__ctype_b_loc@@GLIBC_2.3fseek@@GLIBC_2.0inet_aton@@GLIBC_2.0snd_pcm_info_set_device@@ALSA_0.9PyEval_RestoreThreadquisk_tmp_microphoneQuiskPrintTimefclose@@GLIBC_2.1quisk_sound_statequiskAudio24p3CoefsPa_GetErrorTextsnd_pcm_writei@@ALSA_0.9quisk_close_sound_portaudiosnd_ctl_elem_info@@ALSA_0.9QuiskSleepMicrosecquisk_close_micquiskAudioFmHpCoefsfftw_executeQuiskGetConfigStringPyString_FromStringnanosleep@@GLIBC_2.0memcpy@@GLIBC_2.0PyInt_FromLongPyEval_SaveThreadinit_quiskquisk_extern_demodstrlen@@GLIBC_2.0snd_pcm_readi@@ALSA_0.9cos@@GLIBC_2.0snd_strerror@@ALSA_0.9quisk_dFilterquisk_mixer_setPySequence_GetItemsnd_pcm_hw_params_test_format@@ALSA_0.9PyInt_AsLongcabs@@GLIBC_2.1quiskMicFilt8CoefsPySequence_Sizesnd_ctl_elem_value_sizeof@@ALSA_0.9Pa_GetDeviceCountPyType_IsSubtypePa_GetStreamReadAvailablesnd_pcm_hw_params_get_rate_min@@ALSA_0.9.0rc4quiskFilt240D5CoefsSharpbind@@GLIBC_2.0mic_max_displaysnd_ctl_elem_info_get_min@@ALSA_0.9snd_ctl_elem_id_set_numid@@ALSA_0.9snd_ctl_elem_info_sizeof@@ALSA_0.9quisk_close_keyselect@@GLIBC_2.0snd_pcm_drop@@ALSA_0.9PyFloat_AsDoubleclose@@GLIBC_2.0fwrite@@GLIBC_2.0quisk_cInterp2HB45PySequence_CheckrxModestrstr@@GLIBC_2.0log10@@GLIBC_2.0snd_ctl_elem_info_get_type@@ALSA_0.9Py_BuildValuequisk_process_microphonePa_OpenStreamPyObject_GetAttrStringPa_GetDefaultInputDevice__bss_startquisk_start_sound_alsaquiskFilt53D2Coefsmalloc@@GLIBC_2.0Pa_Initializesnd_pcm_info_sizeof@@ALSA_0.9__stack_chk_fail@@GLIBC_2.4_Py_NoneStructPyErr_NewExceptionPyList_Appendatan2@@GLIBC_2.0quiskFilt167D3Coefsquisk_open_keysnd_ctl_card_info@@ALSA_0.9snd_pcm_hw_params_get_channels_max@@ALSA_0.9.0rc4QuiskGetConfigIntPa_TerminatequiskMicFilt48Coefssnd_pcm_hw_params_set_access@@ALSA_0.9quisk_read_rx_udpquiskFilt185D3XCoefsquisk_tx_tune_freqmemmove@@GLIBC_2.0snd_pcm_hw_params_malloc@@ALSA_0.9Pa_GetDefaultOutputDevicequisk_pyConfigPy_InitModule4quisk_mic_clipsend@@GLIBC_2.0snd_pcm_hw_params_set_channels@@ALSA_0.9Pa_WriteStreamquisk_sample_sourcequisk_start_sound_endPyErr_Clearputs@@GLIBC_2.0PyTuple_Newsnd_ctl_card_info_sizeof@@ALSA_0.9fftw_destroy_plansetsockopt@@GLIBC_2.0snd_card_next@@ALSA_0.9quisk_filt_tunesnd_ctl_elem_info_get_id@@ALSA_0.9quisk_mainwin_handlePyTuple_SetItemPyErr_SetStringquiskFilt111D4Coefssnd_pcm_info_set_stream@@ALSA_0.9__sprintf_chk@@GLIBC_2.3.4open64@@GLIBC_2.2quisk_cInterpolatequiskFilt48dec24Coefssnd_ctl_elem_id_set_interface@@ALSA_0.9__snprintf_chk@@GLIBC_2.3.4quisk_play_portaudioPyList_SetItemquisk_dInterp2HB45data_widthquisk_is_key_downquisk_cDecimatefftw_freetan@@GLIBC_2.0quisk_get_overrangequiskAudio24p4Coefssnd_pcm_sw_params_free@@ALSA_0.9snd_pcm_hw_params_set_buffer_size_near@@ALSA_0.9.0rc4Pa_IsStreamStopped_edatasnprintf@@GLIBC_2.0Pa_IsFormatSupportedsnd_pcm_info_set_subdevice@@ALSA_0.9PyComplex_FromCComplexquisk_filt_dInitsnd_ctl_elem_write@@ALSA_0.9quisk_read_soundquiskFilt12_19CoefsPyList_New__cxa_finalize@@GLIBC_2.1.3quiskFilt133D2Coefsquisk_play_channelssnd_pcm_hw_params_free@@ALSA_0.9snd_ctl_elem_value_set_boolean@@ALSA_0.9snd_ctl_elem_info_get_max64@@ALSA_0.9quisk_set_tx_modesnd_pcm_hw_params_set_format@@ALSA_0.9__fdelt_chk@@GLIBC_2.15snd_pcm_sw_params_current@@ALSA_0.9Pa_GetStreamWriteAvailablequisk_get_tx_filter_initquiskAudio48p6Coefssnd_pcm_sw_params_set_start_threshold@@ALSA_0.9fftw_mallocquisk-3.6.11/README.txt0000644000175000017500000000006411632372224014016 0ustar jimjim00000000000000The information from this file is now in docs.html. quisk-3.6.11/microphone.c0000666000175000017500000005560712142455200014641 0ustar jimjim00000000000000#include #include #include #include #include #include #include "quisk.h" #include #include "microphone.h" #include "filter.h" #ifdef MS_WINDOWS #include static int mic_cleanup = 0; // must clean up winsock #else #include #include #define INVALID_SOCKET -1 #endif #if DEBUG_IO static int debug_timer = 1; // count up number of samples #endif // The microphone samples must be 48000 sps or 8000 sps. The output sample // rate is always MIC_OUT_RATE samples per second // FM needs pre-emphasis and de-emphasis. See vk1od.net/FM/FM.htm for details. // For IIR design, see http://www.abvolt.com/research/publications2.htm. // Microhone preemphasis: boost high frequencies 0.00 to 1.00 double quisk_mic_preemphasis; // Microphone clipping; try 3.0 or 4.0 double quisk_mic_clip; // If true, decimate 48000 sps mic samples to 8000 sps for processing #define DECIM_8000 1 // These are external: int mic_max_display; // display value of maximum microphone signal level 0 to 2**15 - 1 static int mic_socket = INVALID_SOCKET; // send microphone samples to a socket static int spotLevel = 0; // 0 for no spotting; else the level 10 to 1000 static double mic_avg_gain = 10.0; // Typical gain for the microphone in use static double mic_max_gain = 100.0; // Do not increase gain over this value static int mic_level; // maximum microphone signal level for display static int mic_timer; // time to display maximum mic level static int align4; // add two bytes to start of audio samples to align to 4 bytes static double modulation_index = 1.6; // For FM transmit, the modulation index #define TX_BLOCK_SHORTS 600 // transmit UDP packet with this many shorts (two bytes) (perhaps + 1) #define MIC_MAX_HOLD_TIME 400 // Time to hold the maximum mic level on the Status screen in milliseconds // If TEST_TX_WAV_FILE is defined, then this file is used as the transmit // audio source. Otherwise the microphone (if any) is used. The // WAV file must be recorded at 48000 Hertz in S16_LE format. // For example: #define TEST_TX_WAV_FILE "/home/jim/quisk/quisk_test.wav" //#define TEST_TX_WAV_FILE "/home/jim/pub/quisk/notdist/quisk.wav" // If USE_GET_SIN is not zero, replace mic samples with a sin wave at a // frequency determined by the sidetone slider and an amplitude determined // by the Spot button level. // If USE_GET_SIN is 1, pass these samples through the transmit filters. // If USE_GET_SIN is 2, transmit these samples directly. #define USE_GET_SIN 0 // If USE_2TONE is not zero, replace samples with a 2-tone test signal. #define USE_2TONE 0 #ifdef TEST_TX_WAV_FILE static int wavStart; // Sound data starts at this offset static int wavEnd; // End of sound data static FILE * wavFp; // File pointer for WAV file input static void open_wav(void) { char name[5]; int size; if (!wavFp) { // Open sound test file wavFp = fopen(TEST_TX_WAV_FILE, "rb"); if (!wavFp) { printf("open_wav failed\n"); return; } wavEnd = 0; while (1) { if (fread (name, 4, 1, wavFp) != 1) break; fread (&size, 4, 1, wavFp); name[4] = 0; //printf("name %s size %d\n", name, size); if (!strncmp(name, "RIFF", 4)) fseek (wavFp, 4, SEEK_CUR); // Skip "WAVE" else if (!strncmp(name, "data", 4)) { // sound data starts here wavStart = ftell(wavFp); wavEnd = wavStart + size; break; } else // Skip other records fseek (wavFp, size, SEEK_CUR); } //printf("start %d end %d\n", wavStart, wavEnd); if (!wavEnd) { // Failure to find "data" record fclose(wavFp); wavFp = NULL; } } } static void get_wav(complex * buffer, int count) { // Put transmit audio samples from a file into buffer. // The sample rate must equal quisk_sound_state.mic_sample_rate. int pos, i; short sh; if (wavFp) { pos = ftell (wavFp); for (i = 0; i < count; i++) { fread(&sh, 2, 1, wavFp); buffer[i] = sh * ((double)CLIP32 / CLIP16); if (++pos >= wavEnd) { fseek (wavFp, wavStart, SEEK_SET); pos = wavStart; } } } } #endif #if USE_GET_SIN static void get_sin(complex * cSamples, int count) { // replace mic samples with a sin wave int i; double freq; complex phase1; // Phase increment static complex vector1 = CLIP32 / 2; // Use the sidetone slider 0 to 1000 to set frequency //freq = (quisk_sidetoneCtrl - 500) / 1000.0 * MIC_OUT_RATE; freq = quisk_sidetoneCtrl * 5; freq = ((int)freq / 50) * 50; #if USE_GET_SIN == 2 phase1 = cexp(I * 2.0 * M_PI * freq / MIC_OUT_RATE); count *= MIC_OUT_RATE / quisk_sound_state.mic_sample_rate; #else phase1 = cexp(I * 2.0 * M_PI * freq / quisk_sound_state.mic_sample_rate); #endif for (i = 0; i < count; i++) { vector1 *= phase1; cSamples[i] = vector1; } #if DEBUG_IO if (debug_timer == 0) printf ("get_sin freq %.0lf\n", freq); #endif } #endif #if USE_2TONE static void get_2tone(complex * cSamples, int count) { // replace mic samples int i; static complex phase1=0, phase2; // Phase increment static complex vector1; static complex vector2; if (phase1 == 0) { // initialize phase1 = cexp((I * 2.0 * M_PI * IMD_TONE_1) / quisk_sound_state.mic_sample_rate); phase2 = cexp((I * 2.0 * M_PI * IMD_TONE_2) / quisk_sound_state.mic_sample_rate); vector1 = CLIP32 / 2.0; vector2 = CLIP32 / 2.0; } for (i = 0; i < count; i++) { vector1 *= phase1; vector2 *= phase2; cSamples[i] = (vector1 + vector2); } } #endif static int tx_filter(complex * filtered, int count, int is_cpx) { // Input samples are creal(filtered), output is filtered. // For is_cpx == 1, output is SSB I/Q samples; else output is creal(filtered) sound. int i; double dsample, x, dtmp, peakA, gain, amplitude; complex csample; static double x_1 = 0; static double gainA = 10.0, gainB = 0.8; static double time_short, time_long; static struct quisk_dFilter filter1={NULL}, filter2; static struct quisk_cFilter filtDecim, filtInterp; static int mic_interp, mic_decim, sample_rate; #if DEBUG_IO static double peakIn = 0, peakOut1 = 0, peakOut2 = 0, peakOut3 = 0; // input/output level #endif if (!filtered) { // initialization gainA = mic_avg_gain; if (! filter1.dCoefs) { if (quisk_sound_state.mic_sample_rate == 8000) { sample_rate = 8000; mic_decim = 1; mic_interp = MIC_OUT_RATE / sample_rate; quisk_filt_dInit(&filter1, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double)); quisk_filt_dInit(&filter2, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double)); quisk_filt_cInit(&filtInterp, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double)); } else if (DECIM_8000) { // decimate 48000 to 8000 sps sample_rate = 8000; mic_decim = mic_interp = MIC_OUT_RATE / sample_rate; quisk_filt_dInit(&filter1, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double)); quisk_filt_dInit(&filter2, quiskMicFilt8Coefs, sizeof(quiskMicFilt8Coefs)/sizeof(double)); quisk_filt_cInit(&filtDecim, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double)); quisk_filt_cInit(&filtInterp, quiskLpFilt48Coefs, sizeof(quiskLpFilt48Coefs)/sizeof(double)); } else { // process at 48000 sps sample_rate = 48000; mic_decim = mic_interp = MIC_OUT_RATE / sample_rate; quisk_filt_dInit(&filter1, quiskMicFilt48Coefs, sizeof(quiskMicFilt48Coefs)/sizeof(double)); quisk_filt_dInit(&filter2, quiskMicFilt48Coefs, sizeof(quiskMicFilt48Coefs)/sizeof(double)); } } dtmp = 1.0 / sample_rate; // sample time time_short = 1.0 - exp(- dtmp / 0.010); time_long = 1.0 - exp(- dtmp / 10.000); quisk_filt_tune(&filter1, 1650.0 / sample_rate, rxMode != 2); quisk_filt_tune(&filter2, 1650.0 / sample_rate, rxMode != 2); return 0; } #if DEBUG_IO //QuiskPrintTime("", -2); #endif if (mic_decim > 1) count = quisk_cDecimate(filtered, count, &filtDecim, mic_decim); peakA = 1E-6; for (i = 0; i < count; i++) { dsample = creal(filtered[i]) / CLIP16; // normalize to +/- 1.0 #if DEBUG_IO x = fabs(dsample); if (x > peakIn) peakIn = x; #endif #if 1 // high pass filter for preemphasis: See Radcom, January 2010, page 76. // quisk_mic_preemphasis == 1 was measured as 6 dB / octave. // gain at 800 Hz was measured as 0.104672. x = dsample; dsample = x - quisk_mic_preemphasis * x_1; x_1 = x; // delayed sample #endif #if 1 // FIR bandpass filter; separate into I and Q csample = quisk_dC_out(dsample, &filter1); #endif #if 1 // Audio compression. The desired output level is quisk_mic_clip / 2.5. dtmp = cabs(csample); if (dtmp != 0) { gain = quisk_mic_clip / 2.5 / dtmp; // target gain if (gain > mic_max_gain) gain = mic_max_gain; if (gainA > gain) gainA = gainA * (1 - time_short) + time_short * gain; // gainA too high else gainA = gainA * (1 - time_long) + time_long * gain; // gainA too low } csample *= gainA; #endif #if DEBUG_IO x = cabs(csample); if (x > peakOut1) peakOut1 = x; #endif #if 1 // Clip signal at the level 1.0 dtmp = cabs(csample); if (dtmp > 1.0) csample = csample / dtmp; #endif #if 1 // FIR bandpass filter; separate into I and Q csample = quisk_dC_out(creal(csample), &filter2); #endif if (is_cpx) { amplitude = cabs(csample); } else { // convert to real samples dtmp = creal(csample); csample = dtmp; amplitude = fabs(dtmp); } if (amplitude > peakA) peakA = amplitude; #if DEBUG_IO if (amplitude > peakOut2) peakOut2 = amplitude; #endif filtered[i] = csample; } // Normalize final amplitude based on the peak dtmp = (double)count / sample_rate; // sample time gain = 0.9 / peakA; // target gain if (gain > 1.0) gain = 1.0; if (gainB > gain) { x = 1.0 - exp(- dtmp / 0.010); gainB = gainB * (1 - x) + x * gain; // gainB too high } else { x = 1.0 - exp(- dtmp / 10.000); gainB = gainB * (1 - x) + x * gain; // gainB too low } //printf ("gain %10.6lf gainB %10.6lf dtmp %10.6lf x %10.6lf count %d\n", gain, gainB, dtmp, x, count); for (i = 0; i < count; i++) { csample = filtered[i]; csample *= gainB; amplitude = cabs(csample); if (amplitude > 1.0) csample /= amplitude; filtered[i] = csample * CLIP16; // convert back to 16 bits } if (mic_interp > 1) count = quisk_cInterpolate(filtered, count, &filtInterp, mic_interp); #if DEBUG_IO for (i = 0; i < count; i++) { amplitude = cabs(filtered[i]) / CLIP16; if (amplitude > peakOut3) peakOut3 = amplitude; } #endif //printf("%5.2lf\n", increasing); #if DEBUG_IO if (debug_timer == 0) { printf ("peakIn %10.6lf peakOut1 %10.6lf peakOut2 %10.6lf peakOut3 %10.6lf gainA %6.1lf gainB %6.3lf", peakIn, peakOut1, peakOut2, peakOut3, gainA, gainB); if (peakOut3 > 1.0) printf (" CLIP\n"); else printf ("\n"); peakIn = peakOut1 = peakOut2 = peakOut3 = 0; } #endif #if DEBUG_IO //QuiskPrintTime(" tx_filter", 2); #endif return count; } static int tx_filter_digital(complex * filtered, int count, double volume) { // Input samples are creal(filtered), output is filtered. // This filter has minimal processing and is used for digital modes. int i; double dsample, amplitude; complex csample; static struct quisk_dFilter filter1; #if DEBUG_IO double x; static double peakIn = 0, peakOut2 = 0; // input/output level #endif if (!filtered) { // initialization quisk_filt_dInit(&filter1, quiskMicFilt48Coefs, sizeof(quiskMicFilt48Coefs)/sizeof(double)); quisk_filt_tune(&filter1, 1650.0 / 48000, rxMode != 2); return 0; } #if DEBUG_IO //QuiskPrintTime("", -2); #endif for (i = 0; i < count; i++) { dsample = creal(filtered[i]) / CLIP16; // normalize to +/- 1.0 #if DEBUG_IO x = fabs(dsample); if (x > peakIn) peakIn = x; #endif // FIR bandpass filter; separate into I and Q csample = quisk_dC_out(dsample, &filter1); amplitude = cabs(csample); #if DEBUG_IO if (amplitude > peakOut2) peakOut2 = amplitude; #endif if (amplitude > 1.0) csample /= amplitude; filtered[i] = csample * CLIP16 * volume; // convert back to 16 bits } //printf("%5.2lf\n", increasing); #if DEBUG_IO if (debug_timer == 0) { printf ("peakIn %10.6lf peakOut2 %10.6lf", peakIn, peakOut2); if (peakOut2 > 1.0) printf (" CLIP\n"); else printf ("\n"); peakIn = peakOut2 = 0; } //QuiskPrintTime(" tx_filter", 2); #endif return count; } PyObject * quisk_get_tx_filter(PyObject * self, PyObject * args) { // return the TX filter response to display on the graph // This is for debugging. Change quisk.py to call QS.get_tx_filter() instead // of QS.get_filter(). int i, j, k; int freq, time; PyObject * tuple2; complex cx; double scale; double * average, * fft_window, * bufI, * bufQ; fftw_complex * samples, * pt; // complex data for fft fftw_plan plan; // fft plan double phase, delta; int nTaps = 325; if (!PyArg_ParseTuple (args, "")) return NULL; // Create space for the fft of size data_width pt = samples = (fftw_complex *) fftw_malloc(sizeof(fftw_complex) * data_width); plan = fftw_plan_dft_1d(data_width, pt, pt, FFTW_FORWARD, FFTW_MEASURE); average = (double *) malloc(sizeof(double) * (data_width + nTaps)); fft_window = (double *) malloc(sizeof(double) * data_width); bufI = (double *) malloc(sizeof(double) * nTaps); bufQ = (double *) malloc(sizeof(double) * nTaps); for (i = 0, j = -data_width / 2; i < data_width; i++, j++) // Hanning fft_window[i] = 0.5 + 0.5 * cos(2. * M_PI * j / data_width); for (i = 0; i < data_width + nTaps; i++) average[i] = 0.5; // Value for freq == 0 for (freq = 1; freq < data_width / 2.0 - 10.0; freq++) { //freq = data_width * 0.2 / 48.0; delta = 2 * M_PI / data_width * freq; phase = 0; // generate some initial samples to fill the filter pipeline for (time = 0; time < data_width + nTaps; time++) { average[time] += cos(phase); // current sample phase += delta; if (phase > 2 * M_PI) phase -= 2 * M_PI; } } // now filter the signal using the transmit filter tx_filter(NULL, 0, 0); // initialize scale = 1.0; for (i = 0; i < data_width; i++) if (fabs(average[i + nTaps]) > scale) scale = fabs(average[i + nTaps]); scale = CLIP16 / scale; // limit to CLIP16 for (i = 0; i < nTaps; i++) samples[i] = average[i] * scale; tx_filter(samples, nTaps, 1); // process initial samples for (i = 0; i < data_width; i++) samples[i] = average[i + nTaps] * scale; tx_filter(samples, data_width, 1); // process the samples for (i = 0; i < data_width; i++) // multiply by window samples[i] *= fft_window[i]; fftw_execute(plan); // Calculate FFT // Normalize and convert to log10 scale = 0.3 / data_width / scale; for (k = 0; k < data_width; k++) { cx = samples[k]; average[k] = cabs(cx) * scale; if (average[k] <= 1e-7) // limit to -140 dB average[k] = -7; else average[k] = log10(average[k]); } // Return the graph data tuple2 = PyTuple_New(data_width); i = 0; // Negative frequencies: for (k = data_width / 2; k < data_width; k++, i++) PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k])); // Positive frequencies: for (k = 0; k < data_width / 2; k++, i++) PyTuple_SetItem(tuple2, i, PyFloat_FromDouble(20.0 * average[k])); free(bufQ); free(bufI); free(average); free(fft_window); fftw_destroy_plan(plan); fftw_free(samples); return tuple2; } // udp_iq has an initial zero followed by the I/Q samples. // The initial zero is sent iff align4 == 1. static void transmit_udp(complex * cSamples, int count) { // Send count samples. Each sample is sent as two shorts (4 bytes) of I/Q data. // Transmission is delayed until a whole block of data is available. int i, sent; static short udp_iq[TX_BLOCK_SHORTS + 1] = {0}; static int udp_size = 1; if (mic_socket == INVALID_SOCKET) return; if ( ! cSamples) { // initialization udp_size = 1; udp_iq[0] = 0; // should not be necessary return; } for (i = 0; i < count; i++) { // transmit samples udp_iq[udp_size++] = (short)creal(cSamples[i]); udp_iq[udp_size++] = (short)cimag(cSamples[i]); if (udp_size >= TX_BLOCK_SHORTS) { // check count if (align4) sent = send(mic_socket, (char *)udp_iq, udp_size * 2, 0); else sent = send(mic_socket, (char *)udp_iq + 1, --udp_size * 2, 0); if (sent != udp_size * 2) printf("Send socket returned %d\n", sent); udp_size = 1; } } } static void transmit_mic_carrier(complex * cSamples, int count, double level) { // send a CW carrier instead of mic samples int i; for (i = 0; i < count; i++) // transmit a carrier equal to the number of samples cSamples[i] = level * CLIP16; transmit_udp(cSamples, count); } static void transmit_mic_imd(complex * cSamples, int count, double level) { // send a 2-tone test signal instead of mic samples int i; complex v; static complex phase1=0, phase2; // Phase increment static complex vector1; static complex vector2; if (phase1 == 0) { // initialize phase1 = cexp((I * 2.0 * M_PI * IMD_TONE_1) / MIC_OUT_RATE); phase2 = cexp((I * 2.0 * M_PI * IMD_TONE_2) / MIC_OUT_RATE); vector1 = CLIP16 / 2.0; vector2 = CLIP16 / 2.0; } for (i = 0; i < count; i++) { // transmit a carrier equal to the number of samples vector1 *= phase1; vector2 *= phase2; v = level * (vector1 + vector2); cSamples[i] = v; } transmit_udp(cSamples, count); } int quisk_process_microphone(int mic_sample_rate, complex * cSamples, int count) { int i, sample, maximum, interp; double d; // Microphone sample are input at mic_sample_rate. But after processing, // the output rate is MIC_OUT_RATE. interp = MIC_OUT_RATE / mic_sample_rate; #if 0 // Measure soundcard actual sample rate static time_t seconds = 0; static int total = 0; struct timeb tb; static double dtime; ftime(&tb); total += count; if (seconds == 0) { seconds = tb.time; dtime = tb.time + .001 * tb.millitm; } else if (tb.time - seconds > 4) { printf("Mic soundcard rate %.3f\n", total / (tb.time + .001 * tb.millitm - dtime)); seconds = tb.time; printf("backlog %d, count %d\n", backlog, count); } #endif #if DEBUG_IO //QuiskPrintTime("", -1); #endif #if DEBUG_IO debug_timer += count; if (debug_timer >= mic_sample_rate) // one second debug_timer = 0; #endif #ifdef TEST_TX_WAV_FILE get_wav(cSamples, count); // Replace mic samples with sound from a WAV file #endif #if USE_GET_SIN get_sin(cSamples, count); // Replace mic samples with a sin wave #endif #if USE_2TONE get_2tone(cSamples, count); // Replace mic samples with a 2-tone test signal #endif maximum = 1; for (i = 0; i < count; i++) { // measure maximum microphone level for display cSamples[i] *= (double)CLIP16 / CLIP32; // convert 32-bit samples to 16 bits d = creal(cSamples[i]); sample = (int)fabs(d); if (sample > maximum) maximum = sample; } if (maximum > mic_level) mic_level = maximum; mic_timer -= count; // time out the max microphone level to display if (mic_timer <= 0) { mic_timer = mic_sample_rate / 1000 * MIC_MAX_HOLD_TIME; mic_max_display = mic_level; mic_level = 1; } if (quisk_is_key_down()) { #if USE_GET_SIN == 2 transmit_udp(cSamples, count * interp); #else switch (rxMode) { case 2: // LSB case 3: // USB if (quisk_record_state == PLAYBACK) { count = tx_filter_digital(cSamples, count, 0.9); // filter samples, minimal processing transmit_udp(cSamples, count); } else if (spotLevel == 0) { count = tx_filter(cSamples, count, 1); // filter samples transmit_udp(cSamples, count); } else { count *= interp; transmit_mic_carrier(cSamples, count, spotLevel / 1000.0); } break; case 4: // AM if (quisk_record_state != PLAYBACK) // no audio processing for recorded sound count = tx_filter(cSamples, count, 0); for (i = 0; i < count; i++) // transmit (0.5 + ampl/2, 0) cSamples[i] = (creal(cSamples[i]) + CLIP16) * 0.5; transmit_udp(cSamples, count); break; case 5: // FM if (quisk_record_state != PLAYBACK) // no audio processing for recorded sound count = tx_filter(cSamples, count, 0); for (i = 0; i < count; i++) { // this is phase modulation == FM and 6 dB /octave preemphasis cSamples[i] = CLIP16 * cexp(I * creal(cSamples[i]) / CLIP16 * modulation_index); } transmit_udp(cSamples, count); break; case 7: // digital modes case 8: case 9: if (spotLevel == 0) { count = tx_filter_digital(cSamples, count, 1.0); // filter samples, minimal processing transmit_udp(cSamples, count); } else { count *= interp; transmit_mic_carrier(cSamples, count, spotLevel / 1000.0); } break; case 10: // transmit IMD 2-tone test count *= interp; transmit_mic_imd(cSamples, count, 1.0); break; case 11: count *= interp; transmit_mic_imd(cSamples, count, 1.0 / sqrt(2.0)); break; case 12: count *= interp; transmit_mic_imd(cSamples, count, 0.5); break; } #endif } #if DEBUG_IO //QuiskPrintTime(" process_mic", 1); #endif return count; } void quisk_close_mic(void) { if (mic_socket != INVALID_SOCKET) { close(mic_socket); mic_socket = INVALID_SOCKET; } #ifdef MS_WINDOWS if (mic_cleanup) WSACleanup(); #endif } void quisk_open_mic(void) { struct sockaddr_in Addr; int sndsize = 48000; #if DEBUG_IO int intbuf; #ifdef MS_WINDOWS int bufsize = sizeof(int); #else socklen_t bufsize = sizeof(int); #endif #endif #ifdef MS_WINDOWS WORD wVersionRequested; WSADATA wsaData; #endif modulation_index = QuiskGetConfigDouble("modulation_index", 1.6); mic_max_gain = QuiskGetConfigDouble("mic_max_gain", 100.0); mic_avg_gain = QuiskGetConfigDouble("mic_avg_gain", 10.0); if (quisk_sound_state.tx_audio_port == 0x553B) align4 = 0; // Using old port: data starts at byte 42. else align4 = 1; // Start data at byte 44; align to dword if (quisk_sound_state.mic_ip[0]) { #ifdef MS_WINDOWS wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) return; // failure to start winsock mic_cleanup = 1; #endif mic_socket = socket(PF_INET, SOCK_DGRAM, 0); if (mic_socket != INVALID_SOCKET) { setsockopt(mic_socket, SOL_SOCKET, SO_SNDBUF, (char *)&sndsize, sizeof(sndsize)); Addr.sin_family = AF_INET; // This is the UDP port for TX microphone samples, and must agree with the microcontroller. Addr.sin_port = htons(quisk_sound_state.tx_audio_port); #ifdef MS_WINDOWS Addr.sin_addr.S_un.S_addr = inet_addr(quisk_sound_state.mic_ip); #else inet_aton(quisk_sound_state.mic_ip, &Addr.sin_addr); #endif if (connect(mic_socket, (const struct sockaddr *)&Addr, sizeof(Addr)) != 0) { close(mic_socket); mic_socket = INVALID_SOCKET; } else { #if DEBUG_IO if (getsockopt(mic_socket, SOL_SOCKET, SO_SNDBUF, (char *)&intbuf, &bufsize) == 0) printf("UDP mic socket send buffer size %d\n", intbuf); else printf ("Failure SO_SNDBUF\n"); #endif } } } } void quisk_set_tx_mode(void) // called when the mode rxMode is changed { tx_filter(NULL, 0, 0); tx_filter_digital(NULL, 0, 0.0); #ifdef TEST_TX_WAV_FILE if (!wavFp) // convenient place to open file open_wav(); #endif } PyObject * quisk_set_spot_level(PyObject * self, PyObject * args) { if (!PyArg_ParseTuple (args, "i", &spotLevel)) return NULL; if (spotLevel == 0) transmit_udp(NULL, 0); // initialization Py_INCREF (Py_None); return Py_None; } quisk-3.6.11/sound_alsa.c0000666000175000017500000007501612110156116014621 0ustar jimjim00000000000000/* * This modue provides sound access for QUISK using the ALSA * library for Linux. */ #include #include #include #include #include "quisk.h" /* The sample rate is in frames per second. Each frame has a number of channels, and each channel has a sample of size sample_bytes. The channels are interleaved: (channel0, channel1), (channel0, channel1), ... */ #define CORRECT_PLAY_RATE 1 extern struct sound_conf quisk_sound_state; // Current sound status static int is_little_endian; // Test byte order; is it little-endian? static short buffer2[SAMP_BUFFER_SIZE]; // Buffer for 2-byte samples from sound static unsigned char buffer3[3 * SAMP_BUFFER_SIZE]; // Buffer for 3-byte samples from sound static int buffer4[SAMP_BUFFER_SIZE]; // Buffer for 4-byte samples from sound static int bufferz[SAMP_BUFFER_SIZE]; // Buffer for zero samples int quisk_read_alsa(struct sound_dev * dev, complex * cSamples) { // Read sound samples from the ALSA soundcard. // Samples are converted to 32 bits with a range of +/- CLIP32 and placed into cSamples. int i; snd_pcm_sframes_t frames, avail; short si, sq; int ii, qq; int nSamples; complex c; if (!dev->handle) return -1; switch(snd_pcm_state(dev->handle)) { case SND_PCM_STATE_RUNNING: break; case SND_PCM_STATE_PREPARED: break; case SND_PCM_STATE_XRUN: #if DEBUG_IO QuiskPrintTime("read_alsa: Capture overrun", 0); #endif snd_pcm_prepare(dev->handle); break; default: #if DEBUG_IO QuiskPrintTime("read_alsa: State UNKNOWN", 0); #endif break; } snd_pcm_delay(dev->handle, &avail); // available frames dev->dev_latency = avail; if (dev->read_frames == 0) { // non-blocking: read available frames if (avail == 0) avail = 32; // read frames to restart from error if (avail > SAMP_BUFFER_SIZE / dev->num_channels) // limit read request to buffer size avail = SAMP_BUFFER_SIZE / dev->num_channels; } else { avail = dev->read_frames; // size of read request } nSamples = 0; switch (dev->sample_bytes) { case 2: frames = snd_pcm_readi (dev->handle, buffer2, avail); // read samples if (frames == -EAGAIN) { // no samples available break; } else if (frames <= 0) { // error dev->dev_error++; #if DEBUG_IO QuiskPrintTime("read_alsa: frames < 0", 0); #endif snd_pcm_prepare (dev->handle); snd_pcm_start (dev->handle); break; } for (i = 0; frames; i += dev->num_channels, nSamples++, frames--) { si = buffer2[i + dev->channel_I]; sq = buffer2[i + dev->channel_Q]; if (si >= CLIP16 || si <= -CLIP16) dev->overrange++; // assume overrange returns max int if (sq >= CLIP16 || sq <= -CLIP16) dev->overrange++; ii = si << 16; qq = sq << 16; cSamples[nSamples] = ii + I * qq; } break; case 3: frames = snd_pcm_readi (dev->handle, buffer3, avail); // read samples if (frames == -EAGAIN) { // no samples available break; } else if (frames <= 0) { // error dev->dev_error++; #if DEBUG_IO QuiskPrintTime("read_alsa: frames < 0", 0); #endif snd_pcm_prepare (dev->handle); snd_pcm_start (dev->handle); break; } for (i = 0; frames; i += dev->num_channels, nSamples++, frames--) { ii = qq = 0; if (!is_little_endian) { // convert to big-endian *((unsigned char *)&ii ) = buffer3[(i + dev->channel_I) * 3 + 2]; *((unsigned char *)&ii + 1) = buffer3[(i + dev->channel_I) * 3 + 1]; *((unsigned char *)&ii + 2) = buffer3[(i + dev->channel_I) * 3 ]; *((unsigned char *)&qq ) = buffer3[(i + dev->channel_Q) * 3 + 2]; *((unsigned char *)&qq + 1) = buffer3[(i + dev->channel_Q) * 3 + 1]; *((unsigned char *)&qq + 2) = buffer3[(i + dev->channel_Q) * 3 ]; } else { // convert to little-endian memcpy((unsigned char *)&ii + 1, buffer3 + (i + dev->channel_I) * 3, 3); memcpy((unsigned char *)&qq + 1, buffer3 + (i + dev->channel_Q) * 3, 3); } if (ii >= CLIP32 || ii <= -CLIP32) dev->overrange++; // assume overrange returns max int if (qq >= CLIP32 || qq <= -CLIP32) dev->overrange++; cSamples[nSamples] = ii + I * qq; } break; case 4: frames = snd_pcm_readi (dev->handle, buffer4, avail); // read samples if (frames == -EAGAIN) { // no samples available break; } else if (frames <= 0) { // error dev->dev_error++; #if DEBUG_IO QuiskPrintTime("read_alsa: frames < 0", 0); #endif snd_pcm_prepare (dev->handle); snd_pcm_start (dev->handle); break; } for (i = 0; frames; i += dev->num_channels, nSamples++, frames--) { ii = buffer4[i + dev->channel_I]; qq = buffer4[i + dev->channel_Q]; if (ii >= CLIP32 || ii <= -CLIP32) dev->overrange++; // assume overrange returns max int if (qq >= CLIP32 || qq <= -CLIP32) dev->overrange++; cSamples[nSamples] = ii + I * qq; } break; } for (i = 0; i < nSamples; i++) { // DC removal; R.G. Lyons page 553 c = cSamples[i] + dev->dc_remove * 0.95; cSamples[i] = c - dev->dc_remove; dev->dc_remove = c; } return nSamples; } void quisk_play_alsa(struct sound_dev * playdev, int nSamples, complex * cSamples, int report_latency, double volume) { // Play the samples; write them to the ALSA soundcard. int i, n, index; snd_pcm_sframes_t frames, delay; int ii, qq; #if DEBUG_IO static int timer=0; #endif if (!playdev->handle || nSamples <= 0) return; // Note: snd_pcm_delay() is not reliable when using the "default" ALSA device and // arbitrary sample rates. It seems to be confused by the rate conversion. So we // are changing rates (decimate) ourselves. // switch(snd_pcm_state(playdev->handle)) { case SND_PCM_STATE_RUNNING: //printf("State RUNNING\n"); snd_pcm_delay(playdev->handle, &delay); // samples left in play buffer break; case SND_PCM_STATE_PREPARED: #if DEBUG_IO //QuiskPrintTime("play_alsa: State PREPARED", 0); #endif snd_pcm_delay(playdev->handle, &delay); delay = 0; break; case SND_PCM_STATE_XRUN: #if DEBUG_IO QuiskPrintTime("", 0); printf("play_alsa: Play underrun; nSamples %d\n", nSamples); #endif quisk_sound_state.underrun_error++; playdev->dev_underrun++; snd_pcm_prepare(playdev->handle); delay = 0; break; default: #if DEBUG_IO QuiskPrintTime("play_alsa: State UNKNOWN", 0); #endif delay = 0; break; } playdev->dev_latency = delay; if (report_latency) { // Report for main playback device quisk_sound_state.latencyPlay = delay; // samples left in play buffer } // There will be additional samples available to read in the capture buffer. index = 0; #if CORRECT_PLAY_RATE #if DEBUG_IO timer += nSamples; if (timer > playdev->sample_rate) { timer = 0; printf("Samples new %d old %ld total %ld latency_frames %d\n", nSamples, delay, nSamples + delay, playdev->latency_frames); } #endif if (nSamples + delay > playdev->latency_frames * 9 / 10) { nSamples--; #if DEBUG_IO printf("Remove a sample nSamples %d delay %d total %d\n", nSamples, (int)delay, nSamples + (int)delay); #endif } else if(nSamples + delay < playdev->latency_frames * 5 / 10) { cSamples[nSamples] = cSamples[nSamples - 1]; nSamples++; #if DEBUG_IO printf ("Add a sample nSamples %d delay %d total %d\n", nSamples, (int)delay, nSamples + (int)delay); #endif } #endif if (nSamples + delay > playdev->latency_frames) { index = nSamples + delay - playdev->latency_frames; // write only the most recent samples quisk_sound_state.write_error++; playdev->dev_error++; #if DEBUG_IO QuiskPrintTime("", 0); printf("play_alsa: Discard %d of %d samples at %ld delay\n", index, nSamples, delay); #endif } if (playdev->sample_bytes == 2) { while (index < nSamples) { for (i = 0, n = index; n < nSamples; i += playdev->num_channels, n++) { ii = (int)(volume * creal(cSamples[n]) / 65536); qq = (int)(volume * cimag(cSamples[n]) / 65536); buffer2[i + playdev->channel_I] = (short)ii; buffer2[i + playdev->channel_Q] = (short)qq; } n = n - index; frames = snd_pcm_writei (playdev->handle, buffer2, n); if (frames <= 0) { #if DEBUG_IO QuiskPrintTime("play_alsa: frames < 0", 0); #endif if (frames == -EPIPE) { // underrun quisk_sound_state.underrun_error++; playdev->dev_underrun++; } else { quisk_sound_state.write_error++; playdev->dev_error++; } snd_pcm_prepare(playdev->handle); frames = snd_pcm_writei (playdev->handle, buffer2, n); if (frames <= 0) { index = nSamples; // give up } else { index += frames; } } else { index += frames; } } } else if (playdev->sample_bytes == 3) { while (index < nSamples) { for (i = 0, n = index; n < nSamples; i += playdev->num_channels, n++) { ii = (int)(volume * creal(cSamples[n]) / 256); qq = (int)(volume * cimag(cSamples[n]) / 256); if (!is_little_endian) { // convert to big-endian buffer3[(i + playdev->channel_I) * 3 ] = *((unsigned char *)&ii + 2); buffer3[(i + playdev->channel_Q) * 3 ] = *((unsigned char *)&qq + 2); buffer3[(i + playdev->channel_I) * 3 + 1] = *((unsigned char *)&ii + 1); buffer3[(i + playdev->channel_Q) * 3 + 1] = *((unsigned char *)&qq + 1); buffer3[(i + playdev->channel_I) * 3 + 2] = *((unsigned char *)&ii ); buffer3[(i + playdev->channel_Q) * 3 + 2] = *((unsigned char *)&qq ); } else { // convert to little-endian memcpy(buffer3 + (i + playdev->channel_I) * 3, (unsigned char *)&ii + 1, 3); memcpy(buffer3 + (i + playdev->channel_Q) * 3, (unsigned char *)&qq + 1, 3); } } n = n - index; frames = snd_pcm_writei (playdev->handle, buffer3, n); if (frames <= 0) { #if DEBUG_IO QuiskPrintTime("play_alsa: frames < 0", 0); #endif if (frames == -EPIPE) { // underrun quisk_sound_state.underrun_error++; playdev->dev_underrun++; } else { quisk_sound_state.write_error++; playdev->dev_error++; } snd_pcm_prepare(playdev->handle); frames = snd_pcm_writei (playdev->handle, buffer3, n); if (frames <= 0) { index = nSamples; // give up } else { index += frames; } } else { index += frames; } } } else if (playdev->sample_bytes == 4) { while (index < nSamples) { for (i = 0, n = index; n < nSamples; i += playdev->num_channels, n++) { ii = (int)(volume * creal(cSamples[n])); qq = (int)(volume * cimag(cSamples[n])); buffer4[i + playdev->channel_I] = ii; buffer4[i + playdev->channel_Q] = qq; } n = n - index; frames = snd_pcm_writei (playdev->handle, buffer4, n); if (frames <= 0) { #if DEBUG_IO QuiskPrintTime("play_alsa: frames < 0", 0); #endif if (frames == -EPIPE) { // underrun quisk_sound_state.underrun_error++; playdev->dev_underrun++; } else { quisk_sound_state.write_error++; playdev->dev_error++; } snd_pcm_prepare(playdev->handle); frames = snd_pcm_writei (playdev->handle, buffer4, n); if (frames <= 0) { index = nSamples; // give up } else { index += frames; } } else { index += frames; } } } } static int device_list(PyObject * py, snd_pcm_stream_t stream, char * name) { // retern 1 if the card name was substituted snd_ctl_t *handle; int card, err, dev; char buf100[100]; const char * card_text, * pcm_text; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; snd_ctl_card_info_alloca(&info); snd_pcm_info_alloca(&pcminfo); card = -1; if (snd_card_next(&card) < 0 || card < 0) { printf("no soundcards found...\n"); return 0; } while (card >= 0) { sprintf(buf100, "hw:%d", card); if ((err = snd_ctl_open(&handle, buf100, 0)) < 0) { printf("device_list: control open (%i): %s", card, snd_strerror(err)); goto next_card; } if ((err = snd_ctl_card_info(handle, info)) < 0) { printf("device_list: control hardware info (%i): %s", card, snd_strerror(err)); snd_ctl_close(handle); goto next_card; } dev = -1; while (1) { if (snd_ctl_pcm_next_device(handle, &dev)<0) printf("device_list: snd_ctl_pcm_next_device\n"); if (dev < 0) break; snd_pcm_info_set_device(pcminfo, dev); snd_pcm_info_set_subdevice(pcminfo, 0); snd_pcm_info_set_stream(pcminfo, stream); card_text = snd_ctl_card_info_get_name(info); if ( ! card_text || ! card_text[0]) card_text = snd_ctl_card_info_get_id(info); if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) { if (err != -ENOENT) printf ("device_list: control digital audio info (%i): %s", card, snd_strerror(err)); continue; } else { pcm_text = snd_pcm_info_get_name(pcminfo); if ( ! pcm_text || ! pcm_text[0]) pcm_text = snd_pcm_info_get_id(pcminfo); } if (py) { // add to list of devices snprintf(buf100, 100, "%s %s (hw:%d,%d)", card_text, pcm_text, card, dev); PyList_Append(py, PyString_FromString(buf100)); } if (name) { // return the "hw:" name snprintf(buf100, 100, "%s %s", card_text, pcm_text); if (strstr(buf100, name)) { snprintf(name, QUISK_SC_SIZE, "hw:%d,%d", card, dev); snd_ctl_close(handle); return 1; } } } snd_ctl_close(handle); next_card: if (snd_card_next(&card) < 0) { printf("snd_card_next\n"); break; } } return 0; } PyObject * quisk_sound_devices(PyObject * self, PyObject * args) { // Return a list of ALSA device names [pycapt, pyplay] PyObject * pylist, * pycapt, * pyplay; if (!PyArg_ParseTuple (args, "")) return NULL; // Each pycapt and pyplay is [pydev, pyname] pylist = PyList_New(0); // list [pycapt, pyplay] pycapt = PyList_New(0); // list of capture devices pyplay = PyList_New(0); // list of play devices PyList_Append(pylist, pycapt); PyList_Append(pylist, pyplay); device_list(pycapt, SND_PCM_STREAM_CAPTURE, NULL); device_list(pyplay, SND_PCM_STREAM_PLAYBACK, NULL); return pylist; } static snd_pcm_format_t check_formats(struct sound_dev * dev, snd_pcm_hw_params_t *hware) { snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; dev->sample_bytes = 0; strncpy (dev->msg1, "Available formats: ", QUISK_SC_SIZE); if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S32) == 0) { if (!dev->sample_bytes) { strncat(dev->msg1, "*", QUISK_SC_SIZE); dev->sample_bytes = 4; format = SND_PCM_FORMAT_S32; } strncat(dev->msg1, "S32 ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_U32) == 0) { strncat(dev->msg1, "U32 ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S24) == 0) { strncat(dev->msg1, "S24 ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_U24) == 0) { strncat(dev->msg1, "U24 ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S24_3LE) == 0) { if (!dev->sample_bytes) { strncat(dev->msg1, "*", QUISK_SC_SIZE); dev->sample_bytes = 3; format = SND_PCM_FORMAT_S24_3LE; } strncat(dev->msg1, "S24_3LE ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_S16) == 0) { if (!dev->sample_bytes) { strncat(dev->msg1, "*", QUISK_SC_SIZE); dev->sample_bytes = 2; format = SND_PCM_FORMAT_S16; } strncat(dev->msg1, "S16 ", QUISK_SC_SIZE); } if (snd_pcm_hw_params_test_format (dev->handle, hware, SND_PCM_FORMAT_U16) == 0) { strncat(dev->msg1, "U16 ", QUISK_SC_SIZE); } if (format == SND_PCM_FORMAT_UNKNOWN) strncat(dev->msg1, "*UNSUPPORTED", QUISK_SC_SIZE); else snd_pcm_hw_params_set_format (dev->handle, hware, format); return format; } static int quisk_open_alsa_capture(struct sound_dev * dev) { // Open the ALSA soundcard for capture. Return non-zero for error. int err, dir, sample_rate; int poll_size; unsigned int ui; snd_pcm_hw_params_t *hware; snd_pcm_sw_params_t *sware; snd_pcm_uframes_t frames; snd_pcm_t * handle; if ( ! dev->name[0]) // Check for null capture name return 0; #if DEBUG_IO printf("*** Capture on alsa device %s\n", dev->name); #endif if ( ! strncmp (dev->name, "alsa:", 5)) { // search for the name in info strings char buf[QUISK_SC_SIZE]; strncpy(buf, dev->name + 5, QUISK_SC_SIZE); device_list(NULL, SND_PCM_STREAM_CAPTURE, buf); err = snd_pcm_open (&handle, buf, SND_PCM_STREAM_CAPTURE, 0); } else { // just try to open the name err = snd_pcm_open (&handle, dev->name, SND_PCM_STREAM_CAPTURE, 0); } if (err < 0) { snprintf(quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot open capture device %s (%s)", dev->name, snd_strerror (err)); return 1; } dev->handle = handle; if ((err = snd_pcm_sw_params_malloc (&sware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot allocate software parameter structure (%s)\n", snd_strerror (err)); return 1; } if ((err = snd_pcm_hw_params_malloc (&hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); snd_pcm_sw_params_free (sware); return 1; } if ((err = snd_pcm_hw_params_any (handle, hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot initialize capture parameters (%s)\n", snd_strerror (err)); goto errend; } /* UNAVAILABLE if ((err = snd_pcm_hw_params_set_rate_resample (handle, hware, 0)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot disable resampling (%s)\n", snd_strerror (err)); goto errend; } */ // Get some parameters to send back if (snd_pcm_hw_params_get_rate_min(hware, &dev->rate_min, &dir) != 0) dev->rate_min = 0; // Error if (snd_pcm_hw_params_get_rate_max(hware, &dev->rate_max, &dir) != 0) dev->rate_max = 0; // Error if (snd_pcm_hw_params_get_channels_min(hware, &dev->chan_min) != 0) dev->chan_min= 0; // Error if (snd_pcm_hw_params_get_channels_max(hware, &dev->chan_max) != 0) dev->chan_max= 0; // Error #if DEBUG_IO printf("Sample rate min %d max %d\n", dev->rate_min, dev->rate_max); printf("Number of channels min %d max %d\n", dev->chan_min, dev->chan_max); #endif // Set the capture parameters if (check_formats(dev, hware) == SND_PCM_FORMAT_UNKNOWN) { strncpy(quisk_sound_state.msg1, dev->msg1, QUISK_SC_SIZE); strncpy (quisk_sound_state.err_msg, "Quisk does not support your capture format.", QUISK_SC_SIZE); goto errend; } strncpy(quisk_sound_state.msg1, dev->msg1, QUISK_SC_SIZE); sample_rate = dev->sample_rate; if (snd_pcm_hw_params_set_rate (handle, hware, sample_rate, 0) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not set sample rate %d", sample_rate); goto errend; } if (snd_pcm_hw_params_set_access (handle, hware, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { strncpy(quisk_sound_state.err_msg, "Interleaved access is not available", QUISK_SC_SIZE); goto errend; } if (snd_pcm_hw_params_get_channels_min(hware, &ui) != 0) ui = 0; // Error if (dev->num_channels < ui) // increase number of channels to minimum available dev->num_channels = ui; if (snd_pcm_hw_params_set_channels (handle, hware, dev->num_channels) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not set channels to %d", dev->num_channels); goto errend; } // Try to set a capture buffer larger than needed frames = sample_rate * 200 / 1000; // buffer size in milliseconds if (snd_pcm_hw_params_set_buffer_size_near (handle, hware, &frames) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not set capture buffer size"); goto errend; } poll_size = (int)(quisk_sound_state.data_poll_usec * 1e-6 * sample_rate + 0.5); if (frames < poll_size * 3) { // buffer size is too small, reduce poll time quisk_sound_state.data_poll_usec = (int)(frames * 1.e6 / sample_rate / 3 + 0.5); #if DEBUG_IO printf("Reduced data_poll_usec %d for small sound capture buffer\n", quisk_sound_state.data_poll_usec); #endif } #if DEBUG_IO printf("sample rate %d\n", sample_rate); printf("num_channels %d, %s\n", dev->num_channels, dev->msg1); printf("Capture buffer size %d\n", (int)frames); if (frames > SAMP_BUFFER_SIZE / dev->num_channels) printf("Capture buffer exceeds size of sample buffers\n"); #endif if ((err = snd_pcm_hw_params (handle, hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set hw capture parameters (%s)\n", snd_strerror (err)); goto errend; } if ((err = snd_pcm_sw_params_current (handle, sware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot get software capture parameters (%s)\n", snd_strerror (err)); goto errend; } if ((err = snd_pcm_prepare (handle)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot prepare capture interface for use (%s)\n", snd_strerror (err)); goto errend; } // Success snd_pcm_hw_params_free (hware); snd_pcm_sw_params_free (sware); #if DEBUG_IO printf("*** End capture on alsa device %s %s\n", dev->name, quisk_sound_state.err_msg); #endif return 0; errend: snd_pcm_hw_params_free (hware); snd_pcm_sw_params_free (sware); #if DEBUG_IO printf("*** Error end for capture on alsa device %s %s\n", dev->name, quisk_sound_state.err_msg); #endif return 1; } static int quisk_open_alsa_playback(struct sound_dev * dev) { // Open the ALSA soundcard for playback. Return non-zero on error. int err, dir, sample_rate; unsigned int ui; snd_pcm_hw_params_t *hware; snd_pcm_sw_params_t *sware; snd_pcm_uframes_t frames; snd_pcm_t * handle; if ( ! dev->name[0]) // Check for null play name return 0; #if DEBUG_IO printf("*** Playback on alsa device %s\n", dev->name); #endif if ( ! strncmp (dev->name, "alsa:", 5)) { // search for the name in info strings char buf[QUISK_SC_SIZE]; strncpy(buf, dev->name + 5, QUISK_SC_SIZE); device_list(NULL, SND_PCM_STREAM_PLAYBACK, buf); err = snd_pcm_open (&handle, buf, SND_PCM_STREAM_PLAYBACK, 0); } else { // just try to open the name err = snd_pcm_open (&handle, dev->name, SND_PCM_STREAM_PLAYBACK, 0); } if (err < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot open playback device %s (%s)\n", dev->name, snd_strerror (err)); return 1; } dev->handle = handle; if ((err = snd_pcm_sw_params_malloc (&sware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot allocate software parameter structure (%s)\n", snd_strerror (err)); return 1; } if ((err = snd_pcm_hw_params_malloc (&hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); snd_pcm_sw_params_free (sware); return 1; } if ((err = snd_pcm_hw_params_any (handle, hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot initialize playback parameter structure (%s)\n", snd_strerror (err)); goto errend; } // Get some parameters to send back if (snd_pcm_hw_params_get_rate_min(hware, &dev->rate_min, &dir) != 0) dev->rate_min = 0; // Error if (snd_pcm_hw_params_get_rate_max(hware, &dev->rate_max, &dir) != 0) dev->rate_max = 0; // Error if (snd_pcm_hw_params_get_channels_min(hware, &dev->chan_min) != 0) dev->chan_min= 0; // Error if (snd_pcm_hw_params_get_channels_max(hware, &dev->chan_max) != 0) dev->chan_max= 0; // Error #if DEBUG_IO printf("Sample rate min %d max %d\n", dev->rate_min, dev->rate_max); printf("Number of channels min %d max %d\n", dev->chan_min, dev->chan_max); #endif // Set the playback parameters sample_rate = dev->sample_rate; if (snd_pcm_hw_params_set_rate (handle, hware, sample_rate, 0) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback rate %d", sample_rate); goto errend; } if (snd_pcm_hw_params_set_access (handle, hware, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback access to interleaved."); goto errend; } if (snd_pcm_hw_params_get_channels_min(hware, &ui) != 0) ui = 0; // Error if (dev->num_channels < ui) // increase number of channels to minimum available dev->num_channels = ui; if (snd_pcm_hw_params_set_channels (handle, hware, dev->num_channels) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback channels to %d", dev->num_channels); goto errend; } if (check_formats(dev, hware) == SND_PCM_FORMAT_UNKNOWN) { strncpy(quisk_sound_state.msg1, dev->msg1, QUISK_SC_SIZE); snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback format."); goto errend; } // Try to set a play buffer larger than needed frames = sample_rate * 200 / 1000; // buffer size in milliseconds if (snd_pcm_hw_params_set_buffer_size_near (handle, hware, &frames) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Can not set playback buffer size"); goto errend; } dev->play_buf_size = frames; #if DEBUG_IO printf("num_channels %d, %s\n", dev->num_channels, dev->msg1); printf("Playback buffer size %d\n", dev->play_buf_size); #endif if ((err = snd_pcm_hw_params (handle, hware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback hw_params (%s)\n", snd_strerror (err)); goto errend; } if ((err = snd_pcm_sw_params_current (handle, sware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot get software playback parameters (%s)\n", snd_strerror (err)); goto errend; } if (dev->latency_frames > dev->play_buf_size) { dev->latency_frames = dev->play_buf_size; #if DEBUG_IO printf("Latency frames limited to buffer size\n"); #endif } #if DEBUG_IO printf("Audio rate %d latency_frames %d\n", sample_rate, dev->latency_frames); #endif if (snd_pcm_sw_params_set_start_threshold (handle, sware, dev->latency_frames * 7 / 10) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set start threshold\n"); goto errend; } if ((err = snd_pcm_sw_params (handle, sware)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot set playback sw_params (%s)\n", snd_strerror (err)); goto errend; } #if DEBUG_IO snd_pcm_sw_params_get_silence_threshold(sware, &frames); printf("play silence threshold %d\n", (int)frames); snd_pcm_sw_params_get_silence_size(sware, &frames); printf("play silence size %d\n", (int)frames); snd_pcm_sw_params_get_start_threshold(sware, &frames); printf("play start threshold %d\n", (int)frames); printf ("play channels are %d %d\n", dev->channel_I, dev->channel_Q); #endif if ((err = snd_pcm_prepare (handle)) < 0) { snprintf (quisk_sound_state.err_msg, QUISK_SC_SIZE, "Cannot prepare playback interface for use (%s)\n", snd_strerror (err)); goto errend; } // Success snd_pcm_hw_params_free (hware); snd_pcm_sw_params_free (sware); #if DEBUG_IO printf("*** End playback on alsa device %s %s\n", dev->name, quisk_sound_state.err_msg); #endif return 0; errend: snd_pcm_hw_params_free (hware); snd_pcm_sw_params_free (sware); #if DEBUG_IO printf("*** Error end for playback on alsa device %s %s\n", dev->name, quisk_sound_state.err_msg); #endif return 1; } void quisk_start_sound_alsa (struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { struct sound_dev * pDev; memset(bufferz, 0, sizeof(int) * SAMP_BUFFER_SIZE); is_little_endian = 1; // Test machine byte order if (*(char *)&is_little_endian == 1) is_little_endian = 1; else is_little_endian = 0; if (quisk_sound_state.err_msg[0]) return; // prior error // Open the alsa playback devices while (1) { pDev = *pPlayback++; if ( ! pDev) break; if ( ! pDev->handle && pDev->portaudio_index < 0) if (quisk_open_alsa_playback(pDev)) return; // error } // Open the alsa capture devices and start them while (1) { pDev = *pCapture++; if ( ! pDev) break; if ( ! pDev->handle && pDev->portaudio_index < 0) { if (quisk_open_alsa_capture(pDev)) return; // error if (pDev->handle) snd_pcm_start((snd_pcm_t *)pDev->handle); } } } void quisk_close_sound_alsa(struct sound_dev ** pCapture, struct sound_dev ** pPlayback) { struct sound_dev * pDev; while (*pCapture) { pDev = *pCapture; if (pDev->handle && pDev->portaudio_index < 0) { snd_pcm_drop((snd_pcm_t *)pDev->handle); snd_pcm_close((snd_pcm_t *)pDev->handle); } pDev->handle = NULL; pCapture++; } while (*pPlayback) { pDev = *pPlayback; if (pDev->handle && pDev->portaudio_index < 0) { snd_pcm_drop((snd_pcm_t *)pDev->handle); snd_pcm_close((snd_pcm_t *)pDev->handle); } pDev->handle = NULL; pPlayback++; } } void quisk_mixer_set(char * card_name, int numid, double value, char * err_msg, int err_size) // Set card card_name mixer control numid to 0.0 <= value <= 1.0, for integer // or boolean (0 or 1) controls. { int err; static snd_ctl_t * handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t * id; snd_ctl_elem_value_t * control; unsigned int idx; long imin, imax, tmp; snd_ctl_elem_type_t type; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); err_msg[0] = 0; if (value < 0) value = 0; else if (value > 1.0) value = 1.0; snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_numid(id, numid); //snd_ctl_elem_id_set_index(id, index); //snd_ctl_elem_id_set_device(id, device); //snd_ctl_elem_id_set_subdevice(id, subdevice); if ( ! strncmp (card_name, "alsa:", 5)) { // search for the name in info strings char buf[QUISK_SC_SIZE]; strncpy(buf, card_name + 5, QUISK_SC_SIZE); if ( ! device_list(NULL, SND_PCM_STREAM_CAPTURE, buf)) // check capture and play names device_list(NULL, SND_PCM_STREAM_PLAYBACK, buf); buf[4] = 0; // Remove device nuumber err = snd_ctl_open(&handle, buf, 0); } else { // just try to open the name err = snd_ctl_open(&handle, card_name, 0); } if (err < 0) { snprintf (err_msg, err_size, "Control %s open error: %s\n", card_name, snd_strerror(err)); return; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { snprintf (err_msg, err_size, "Cannot find the given element from control %s\n", card_name); return; } snd_ctl_elem_info_get_id(info, id); type = snd_ctl_elem_info_get_type(info); snd_ctl_elem_value_set_id(control, id); idx = 0; switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: if (value > 0.5) snd_ctl_elem_value_set_boolean(control, idx, 1); else snd_ctl_elem_value_set_boolean(control, idx, 0); break; case SND_CTL_ELEM_TYPE_INTEGER: imin = snd_ctl_elem_info_get_min(info); imax = snd_ctl_elem_info_get_max(info); tmp = (long)(imin + (imax - imin) * value + 0.4); snd_ctl_elem_value_set_integer(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER64: imin = snd_ctl_elem_info_get_min64(info); imax = snd_ctl_elem_info_get_max64(info); tmp = (long)(imin + (imax - imin) * value + 0.4); snd_ctl_elem_value_set_integer64(control, idx, tmp); break; default: snprintf (err_msg, err_size, "Control %s element has unknown type\n", card_name); break; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { snprintf (err_msg, err_size, "Control %s element write error: %s\n", card_name, snd_strerror(err)); return; } snd_ctl_close(handle); return; } quisk-3.6.11/WinQuisk.pyw0000644000175000017500000000026011632372222014627 0ustar jimjim00000000000000#!/usr/bin/python import quisk # May be quisk.py or package quisk if quisk.__file__.find('__init__') >= 0: # quisk is the package import quisk.quisk as quisk quisk.main() quisk-3.6.11/libfftw3-3.dll0000644000175000017500000600610711632372230014704 0ustar jimjim00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELaJ*! 8zhpP%] 0^P`t.textxz`0`.data`~@`.rdata @`@.bssp @.edata^0@0@.idataP@0.reloct`v"@0B/4 /19?/35/47,/61 /730/86@U Eh |ph |pPKtÐt&U Uh |ph |pR+tÍ'US |pt>  |pA9wYCtЋ |p؃9v Rs |p js] UVS] t3PEPSuVnۉYu |ptd_e[^] t& hs |ptD |p[noREPjEP6nXte[^] 1e[^] r1 념U]{oD$SD$ u$~t[D$zpD$ $zpuD$tÐQ|p $drD$ D$Q|pL$$T$(@L$ T$D$zp$drOrÐWVS\$(T$ |$$uf$D$T<$D$W$D$KÅx4$D$#9É|t9}[^_ÍCǃ[^_S\$|$tD$)؉$8؃[1|$U1WVS;l$8|$4 D$<uf$|$0D$w<$D$z$D$nƅ$D$B9|9}t$t$8L$<uf$|$0D$<$D$$D$ƅxJ$D$9|t<9}9D$t5;l$81[^_]ÍF뱍F+L$U9D$u˃[^_]ÐUWVS \$4l$ |$$~uMD$D$(9D$}RD$$19}D$4$ǍD9|D$t$,T$0L$(4$T$9L$| [^_]Ãu|$, D$(u|$0t/\$(.~ӋT$,D$0l$(EՋL$(Dž뭋T$(D$,D$0T$(|$(|$, D$(tAt$(.qT$,D$0l$(EEɋ\$(_Dž [^_]Ã|$0uL$(D$,D$0L$(|$(T$(. T$,D$0l$(EEEEˋt$(___Džԃ [^_]ÐUWVS1ۃ;\$4l$(}U1$19}2$t$Ƌt$ɋt$ D$,֋t$$T$09|ӃD$8|$<$;\$4|[^_]UWVS D$4T$4l$@t$<1)…9}m19}_D$$1;L$0}6T$$|$ Nj|$$ɋ|$(D$4׋|$,T$8;L$0|уT$D,$T$9| [^_]1;\$0.}D$$19}2T$$|$ Nj|$$ɋ|$(׋|$,T$D9|ՃL$4D$8 $D$;\$0| [^_]É9UWVS D$8T$8l$Dt$<1)…9}m19}_D$$1;L$0}6T$$|$ Nj|$$ɋ|$(D$4׋|$,T$8;L$0|уT$@l$$9| [^_]1;\$0.}D$$19}2T$$|$ Nj|$$ɋ|$(D$@׋|$,9|ՃL$4D$8 $D$;\$0| [^_]É9UWVS\$P!D$ L$D9L$ D$D$1;t$8}_$D$19}2D$|$4l$$l$Nj|$0D$9|L$u݃nS⏀ S~-FF|$@_EM% ؉E щMw]}怃 f]UЀ ˆUL$D f}f;t$DtD$ȡzpD$$ߡzpn|$(EWUOMw u ,[^_]É|$(1ҋ~OՋT$(B1҃F NT$.YR^ٍ\C@t\$9r)ڃFFt$@~CK% Cl$@U щKu{k怃 f{SЀ ˆSL$D fkf;t$DtD$ȡzpD$$ߡzpHL$(9;ACQSi k D$@C!9%D$@PD$@ffD$ff9T$$D$ BBBB PuËL$(\$D$  $҃UWVS<T$4D$0D$,u)t <1[^_]݀zpT$4Dž8D } T$T4Rt$(fT$4 $l$T$PɉD$$t6u#݅zpDž|$$OL$0D$$ɋX4gT$,tmu I_|$0EGGɅGG T$0R(܅ݝEmD$,ut|$$G(zpuFwL$$EAAɅAA t$$V(܅ݝET$$L$0B(Y(s\|$0<$t$$t$0|$(T$P+} ỉ2%ÅuL$(AD$0<[^_]ËD$$$t$0F(zp|$4t$0,$|$t$89zpL$0EDžQ(܅ݝt$4T$0D$ t$T$,$q|$4t$$D$ |$t$,$L$4|$$,$L$|$8zpT$$DžR(܅ݝvL$$L$0T$4\$D$ $<T$4\$t$ T$,$7ܝDžDžl$$,$t$04$ <1 L$4\$D$  $>T$4\$L$ T$,$!7ܝDžDž<1UWVS$tf$D$pz@~ǂ$$<$X4$D$$$$$\$]$$*$L$U<$$N@D$@T$DD$xT$|L$<$1҃DD$do]$T$l1҃G L$lT$hVDwT$4\$h9r);D$lIT$4FGS¨t9$uC9$uS9$uC 9$uSCfD$`f7D$`PD$|!9[T$xC!9DT$dt SD$dT$#PD$9\$dl$dtGT$dzf߁\$tjrl$xt$|$L$z$шL$zF@~ U 9\$p$$@@1[^_]1|$<.u|$<.tNjt$Dl$@1ɉt$|l$x1\$|l$x׋zp!ډ!99tAD$xڍL$x%L$ ЍT$t߉D$x$$$uvL$p$i@l$<.$uqfd$z|$<wN|$pD$zT$tA$DT$t$x$4$$A^D$p[^_]É 1f.T$zӀڈT$zb|$x\$|f$t$T$ $P$|$@\$D~@D$p..L$4$l$4l$WL$4É $ D$T$؋t$ \$|$$l$(,ÐWVSL$\$t$ȉى91t-ډ)9):)ʉ9)ȉu[^_Í WVST$$\$ t$(touq׉t$$ :L$¸ j)91хt1ډ)9):)ʉ9)ȉuωЃ[^_Ízt$$|$\ j)9}Tt$|$$A9؉g1.tʉ)9):)ډ98)؉҉Й뇉t$|$$Ù ]뛉t$\$$i‰EUWVShl$||$||$D$tt>~)șușt9~׃t 1ۿ9}'L$|L$|<$D$t9|ىh[^_]ûS\$ ~+t!~ؙt9~؃[Ã[à L$t$1\$~/t!~șt39~9t\$t$ þ\$t$ ÉV SL$~.t 9λșt9~9tȃ[^É9uVSt$\$tؙÙtu1[^V1S\$ tٰ4 9[^à L$\$t$~D$ȅt1\$t$ uAD$.~D$t܃|$~D$tb;\$~D$뱉9T$~D$љ҉ut؉ 29ʉ9t1҉c\D$L$xЙ)эQÐUWVS|$$ptL%u^(Pw,$,zp$$ |$$ u|[^_]Ë$$D$<$WЋ$$(\$0.-zpgfff)))шuك+<$l$WL$09.a+<$l$WL$09uD$zp$D$,\$0T$1ҋl$*ɉu؍l$0)}D$0<$Wl$,;l$,|<$T$WD$09.<$T$WD$09u$$*|$$U s$$+<=t<=u6D$=<$Wj$$  |$$Q$$X.<$l$Wu$-zp$D$(\$0l$ 1ҋl$*ɉu؍l$0)<$T$WD$09u?$$*%!zp"zp.Wȉ<$L$Wu;$ zp$D$$\$0L$1ҋl$*ɉu؍l$0)<$T$WD$09u__D$ <$WO1ۅ.bD$ <$W9_Go+oo9؉<$\$W<=.؉<$\$W<=u$zp%zp.<$D$WuD$0<$Wl$(;l$(|TD$0<$Wl$$;l$$|D$/<$W#D$-<$W L$T$D$L$T$$ à D$$L$T$Php@KhpHP @@ S\$C u \$[$Љ\$[ D$$9T$ ËT$tHËD$D$zpD$)D$D$zpD$øzpÐS\$ $ؿT$L$HL$T$H @PP[SD$T$L$ \$t 9t @u1[9Hu9Xu.t@@ [SD$T$t$S[t9C ut CC~[ËK S $f\$[YUWVSD$4D$t$0PT$t]1% €( ШuV)tQ vF F 9D$o|$|$˄u[^_]à F wF u4$V vF 뗋L$dL$t3*\$8D$8;u1[^_]É4$ViF \$81D$8+D$F -ƒ+ Шt%1ۃ-F ÃLL$F 1ۍAЃ vAQɃv Qw,QF k <tF ĉ4$V|$1ۉN D$}l$1sx|$8F D$8/1D$ F -Ã+ بt%1-TF T$ F 1ۍAЃ vAQɃvQdQF <F 뺃M|$8F D$8/1D$4F -Ã+ بt%1-TF T$F 1ۍAЃ vAQɃvQQF <tF 뾉4$V4$V뤉4$Vl$8D$8]2F t4 1)t"(tT=9v F uƉ4$VN |$|$ 4$VDF 14$V4$V 4$V4$V* L$T$D$L$T$$ à D$$ϺT$Vhp@pRhpP@ D$$虺T$@ ËD$@S\$CCuPu\$[镺[É$PD$ VS\$t$CtFF4$CuF[^ÐVS\$t$$19}1҉9|[^ S\$1t[  $蕹[$肹[鷹V1St$ t1҃~F 9[^UWVS l$$|$ E<$D$qE=tA1~:C<$D$KL$<$~S <$ T$l9uȃ [^_]Ã$t$D$ 8L$\$t$t"$t$ÍP@J B$t$UWVSl$0t$4}D$D$zp4$M1~MS T$T$K҉L$CD$ zpuzpD$D$zp4$ 9}D$t$0D$4zp[^_]t$0D$4zp[^_]ᐐ $ à $T$PL$HT$P Ð $L$HT$PL$H T$PL$ HT$$P à $lT$PL$HT$P L$HT$ PL$$HT$(PL$,H T$0P$ Ð $L$HT$PL$H T$PL$ HT$$PL$(HT$,P L$0H$T$4P(L$8H,T$Ƌ^V$]؋N \$^ $E ؋D$ 98ċt$l$4$ [^_]Ã1l$\$ t$|$l$ Mu\$ t$|$l$ËE$}~&] $4$D$e9}݉\$ t$|$l$Ã1l$\$ t$|$l$ ]u\$ t$|$l$ËE $Q}~&] $64$D$9}݉\$ t$|$l$Ãl$\$ t$|$l$ D$uu&1\$$\$\$ t$|$l$ËE $ƋE~(] $4$D$;ƋE9ۅt$tM $g}~&] $L4$D$9}݉MS1ɋD$~PB9Bu 9[1[W11VST$t$~ÃB9Bu- 91Ƀ~Vr9ru 9[^_UWVSt$l$|$ $=t"1҃~tfX 9Xxy 91Ƀ~VB9Bu5 9Mt 1҃~tJp 9px0 9$[^_]ËX9X x 9.~X9X y$$[^_]Ëx9x .x 9$[^_]Ð\$ t$\$ |$l$$[;ōpKt(19}"1ҋ 2D D2D D2 9|\$ t$|$l$UWVS \$ $;ōpKt(19}"1ҋ 2D D2D D2 9|E=t!|$$t$1Ƀ~zz 9M [^_]1Ƀ.~r r 9M [^_]UWVS T$ |$$$FL$ ōXt(19}"1ҋ D DD D 9|t$ L2u\*)t(19}"1ҋ D DD D 9| [^_]Ã|$|$(\$ t$l$\$$<$[ōpD$ Lt(19}"1ҋ 2D D2D D2 9|\$ t$|$l$Ãl$\$ t$|$l$ D$$UD$t =u D$ \$ t$|$l$$uÉD$Mt+19}%1ҋ D DD D 9|uuA8C.uyf9{.u:.ut6|ӃA8C׋k*$$t$tA8C.@R4$ ~l$|hL$xp$HD$(P$@x 4$\$|\$'T$x1<t?w $zp⋴$Lҋ$LAƒr$t$,|$, $ȗD$$$D$ 9\$$d\$x<tCw1$zpD$0D${S,$|$$|$UD$8<uT$,$T$$뗃$>-׉Й|$|t$T$,$U?;$.}CL$$ j)9}L$|T$<$L$[뱿;$.gt$K,$L$$σL$U;$|؃:t$K{,$L$$ωL$UL$@L${C,$|$$|$UD$@,$D$|mOL$ D$|t$($t$(1)׉)km)͋ |pF4 |pUWVSL$@T$Hʼnx@D$TMLEDD$Ht$X\$PL$8uP]Ht$HT$\\$l\$\$$t$\$t$ V@$Cl\$$FD\$t$D$ (lST$ \$$B@JHD$BDD$ QB$D$zpD$[Ã)Ѝ@9x>H9> t|$t;_>\$Xl$tt$T[l$HL$DT$8\$4t$0D$@OXW@_Dw`oLGHG\,$>uT$HӉGPT$\$wP4$sl$4GTD$8OL$l$$P\$HG +\$HTR$l$H_ GuV$L$H_GDMP$_\$,$=T$0$ZSt$44$NSl$8,$BS<$= D$تzp$虂D$D$$ Ð,\$ t$$|$(|$0t$<\$@W@D$8L$4\$t$ D$L$$R8GD\$@t$<\$8t$4D$0\$ t$$H8|$(,\$\$$t$\$t$ V@$R\$$FD\$t$D$ RS\$SD$RRC@D$[BRST$ \$$BDJHD$B@D$ A$D$zpD$[ÃLt$@|$Dl$H\$[^_]à D$zpD$lhpD$$ UWVST\$hl$l|$pt$t$D$LE\$@D$xHˋPT$PӋ@ D$\$8 Ьzp\$0DD$D\$DD$DD$T$(l$Ьzp\$ D$8D$@ Ȭzpzp ȬzpD$8 جzpD$|@D$NjT$|R T$ ׋L$|AʋQD$0 Ȭzp ȬzpD$0D$( جzpl$@D$ D$ D$ ʋL$փl$L$ŋ$ơzpD$xD$||$LGT[^_]à D$zpD$hpD$$ ÐUWVSt$$$$D$l$$A ED\$`YډȋIT$XT$P@D$‹$RT$ $\$H\$@DDD$D\$D\$D$d$\$8D$D$\$0D$8\$(D$0\$ $B D$HD$(D$@D$`D$ D$H Hzpd$8 @zpыR׋Ad$X @zpD$( HzpD$@ Hzpd$0 @zpQ׋AD$ HzpD$`d$P @zpƃl$l$$ŋ$ơzp$$|$l t[^_]à D$`zpD$hpD$$ ÐUWVSl$$$$$$D$d\$X\$P$P׋@D$ \$H\$@\$8$P׋@D$\$0\$($P ׋@D$T$ \$T$D$XD$HD$PD$8D$@ ȭzp zpD$( zp zpD$X zpD$H zpUӋE ȭzpD$ zpD$0 zp zpD$P zpD$8 zpD$@ zpD$( ȭzpD$ zpD$H zpD$XD$ zp zpUӋE zpD$0 ȭzpD$ zpD$8 zpD$P zp zpD$@ zpD$ ȭzpD$( zp zpD$XD$ zpD$H zpUӋE  zpD$ ȭzpD$0 zp zpD$P zpD$8 zpуl$d$Ƌ$zp$Ń|$dl[^_]à D$zpD$hpD$$* ÐUWVSt$$$$$$D$l$B\$`\$X\$PЋR׋@D$ \$H\$@\$8\$0$P׋@ D$\$(\$ \$$P׋@D$\$D$`D$HŋED$8D$(d$8UыED$`d$Hd$(D$XD$0D$D$  zpɋUʋED$Pd$@D$D$@D$PD$ d$ʋUыE D$Xd$0d$Ãl$l$Ƌ$zp$Ń|$lt[^_]à D$@zpD$HhpD$$ UWVS$$$$$$$$P ׋@D$ ݜ$ zpݜ$ zpݜ$zp\$x\$p zp\$h$BƉЋR׋@D$ zp zp\$` zp\$X\$P zp\$H⋔$B\$ ЋR׋@ D$ zp zp\$D$ D$\$@ zp\$8\$0D$ zpD$ \$(D$@ zpD$` zpܬ$܄$E ËUd$` zpD$@ zpl$pD$p݄$D$x݄$D$hD$X zpD$H zpD$8 zp zp zpD$H zpD$X zp zpD$8 zp zpƋE zpUˋE zp݄$d$x\$D$hܤ$D$P zp zpzpD$(zpD$0 zp zpD$P zpD$0D$( zpED$ zpUʋE  zpl$Ӄ$$Ƌ$zp$Ń$Ĥ[^_]à D$zpD$hpD$$\ UWVS$$ $$$$ $l$Bݜ$ݜ$ݜ$ݜ$BD$,ËRT$($@D$$Ë$RT$ $@ D$Ë$R T$$P@$D$\$Hݜ$D$Hݜ$ݜ$ݜ$ݔ$ݜ$D$Hݔ$ݜ$D$,ƋD$(\$D$$ƋD$ \$@D$ƋD$T$8T$D$T$0D$ݜ$d$@D$\$x\$pD$T$h\$`D$8D$0D$@T$X\$PA݄$܄$݄$D$P\݄$܄$݄$D$`]݄$ 0zp (zp 0zp݄$ (zpܤ$ zp݄$ 8zpܬ$A$NjQ ɋQʋA݄$ 0zp݄$ (zp݄$ 0zp݄$ (zpd$X zpD$P 8zpܬ$\\A$\Q \D$p 0zpD$x (zpD$x 0zpD$p (zp݄$ 8zpܬ$ܤ$ zpA‹Q׋Q A݄$ 0zp݄$ (zp݄$ 0zp݄$ (zpD$` 8zpܬ$d$h zpA\A\\Q\$$$Ƌ$(šzp$$[^_]à D$`zpD$hpD$$ ÐUWVS$$$$$$$ݜ$ݜ$$P׋@(D$ݜ$ݜ$ݜ$$P֋@$D$\$x\$p$P ׋@ D$ \$h\$`\$X\$P$P׋@D$\$H\$@\$8\$0$P֋@D$T$(\$ T$݄$܄$D$hD$H݄$܄$D$PD$0D$ ݄$ zpD$X zpD$8 دzp ЯzpD$x ȯzpD$h zp܄$D$ zpD$H zp zp݄$ zpUӋE zpD$` zpD$@ دzp ЯzpD$p ȯzpD$P zp܄$D$ zpD$0 zp zp݄$ zp ЯzpD$p zp zpD$@ ȯzpD$` دzp݄$ zp܄$D$ zpD$0 zpD$P zp zpUыE$݄$ ЯzpD$x zpD$( zpD$8 ȯzpD$X دzp݄$ zp܄$D$ zpD$H zpD$h zp zp݄$ zpD$x ЯzpD$X ȯzpD$8 zpD$( دzp݄$ zp܄$ zpD$ zpD$H zpD$h zpU(ӋE zpD$p ЯzpD$` ȯzpD$@ zp دzp݄$ zp܄$ zpD$ zpD$0 zpD$P zp݄$ ȯzpD$8 zpD$( zpD$X ЯzpD$x دzpD$h zp܄$D$H zpD$ zp zp݄$ zpU ӋE  ȯzpD$@ zp zpD$` ЯzpD$p دzpD$P zp܄$D$0 zpD$ zp zp݄$ zp دzpD$` zp ȯzpD$@ ЯzpD$p zp zp܄$D$0 zpD$ zpD$P zp݄$ zpUыE݄$ دzpD$X zpD$( ȯzpD$8 ЯzpD$x zp zp܄$D$H zpD$ zpD$h zp݄$ zpӃ$$Ƌ$zp$Ń$Ĵ[^_]à D$zpD$hpD$$ ÐUWVS$$$$ $$0E$QDA DHzpݜ$@zpݜ$ݜ$ݜ$ȋIP(D@D$ DDݜ$lݜ$ݜ$\$D$ݜ$ݜ$l$ݜ$$H PD@,D$DDݜ$ݜ$l\$x\$p\$h$H$PD@D$D\$DD$\$`\$XD$l\$P\$8D$8l$8\$H\$@݄$݄$D$`$B݄$D$@݄$d$`ܤ$ыR ӋA$ܤ$d$@݄$܄$݄$܄$݄$D$hD$X\$0D$xD$pD$PD$H\$(݄$܄$݄$܄$AD$(D$0͋AD$(d$0ƋA(ËA݄$ܤ$݄$ܤ$\$ D$hܤ$d$XD$xd$pD$Pd$H݄$ܤ$݄$ܤ$A͋A,ƋAD$ ʋA D$ Ã$$Nj$ ázp$$$[^_]à D$`zpD$hpD$$V ÐUWVS$$ $$$$$ $C ݜ$ݜ$B ËBݜ$(B0ËB(ËBݜ$ ݜ$ 0zpݜ$BËB ËB$ݜ$ 0zpݜ$B,ËBBËBݔ$ݜ$݄$ܤ$ ݜ$݄$܄$ ݜ$݄$(\$݄$D$ݜ$݄$d$ݜ$(zp܌$ݜ$݄$ݜ$ݜ$ܤ$ zp 0zpݜ$݄$ܤ$ܤ$ zpݜ$ݜ$݄$܄$ 0zp݄$(ݜ$ݜ$B ƋBݜ$B0ƋB(ƋB 0zpݜ$ݜ$ݜ$BƋB ƋB$ 0zpݜ$ݜ$ݜ$B,ƋBݜ$BƋB݄$ݜ$݄$ܤ$ݜ$xݜ$p݄$܄$T$݄$ 0zpܬ$ݜ$hD$݄$ܤ$T$ܤ$ zpݜ$`l$ݜ$X݄$܄$$݄$܄$ݜ$P(zp܌$Pݜ$P$ݜ$H݄$܄$ݜ$@ 0zp݄$ܤ$ zpݜ$8ݜ$0݄$܄$݄$܄$H]݄$@ zp݄$h zp zp zpݜ$ݜ$zp܌$݄$ zpݜ$݄$ zp zp݄$ ذzp݄$ аzp݄$ݜ$Ȱzpݜ$zp܌$݄$ zp\$x݄$ ذzp݄$ аzp zp݄$ zp ȰzpD$x݄$h zp݄$@ zp݄$P zp zp݄$H zpܬ$T$`܄$P\$p\$hD$`D$xD$pA\A0\ܤ$d$pA\ɋA \D$h݄$܄$A\A(\݄$ܤ$D$hA \ʋA$\݄$܄$A\A,\݄$ܤ$‹A\A\݄$ zp݄$ zp݄$ zp݄$ zp\$Xzp܌$x݄$p zp\$P݄$0 ذzp݄$X аzp݄$` zp݄$8 zp ȰzpD$P\$Hzp܌$x݄$p zp\$@݄$8 zp݄$` zp݄$0 аzp݄$X ذzpD$@\$8Ȱzp\$0݄$ zp݄$ zp݄$݄$ zp݄$ zp݄$ zpܬ$T$܄$\$(D$\$ D$(D$ D$@A0ʋAD$8D$XA(AD$ d$(d$PAˋA D$0D$HA,AD$0D$HAʋAD$8D$XA A$ǃ$$$Ƌ$(šzp$[^_]à D$@zpD$ipD$$虻 ÐUWVS$$$ $$l$$Aݜ$ݜ$EDݜ$ݜ$YډȋI$P0T$ $Ћ$RT$ݜ$ݜ$ݜ$ݜ$DDD$ DDݜ$ݜ$ݜ$ݜ$$X$ڋH,@(D$‹$R T$$\$x\$p\$h\$`DDD$DD\$X\$P\$H$X$ڋH4@ D$‹$RT$$\$@\$8\$0DDD$DD\$(\$ ‹$B݄$܄$D$xD$@݄$܄$݄$܄$D$h݄$܄$D$H݄$ zpD$( zpD$X zpD$@ zp܄$D$x zp݄$ zpыR׋A$݄$ zpD$0 zpD$` zp zp܄$ zp݄$ zp݄$ zpD$X zpD$( zp݄$ zp܄$D$@ zpD$x zpQ4׋A݄$ zpD$` zpD$0 zp݄$ zp܄$ zp zp݄$ zpD$( zpD$X zpD$x zp܄$D$@ zp݄$ zpQ,׋A ݄$ zpD$0 zpD$` zp zp܄$ zp݄$ zp݄$ zpD$8 zpD$p zp݄$ zp܄$ zpD$H zpQ֋A ݄$ zpD$ zpD$P zp݄$ zp܄$ zpD$h zp݄$ zpD$p zpD$8 zpD$H zp܄$ zp݄$ zpQ֋A(݄$ zpD$P zpD$ zpD$h zp܄$ zp݄$ zp݄$ zpD$p zpD$8 zp zp܄$D$H zp݄$ zpQ֋A0݄$ zpD$P zpD$ zp zp܄$D$h zp݄$ zp׃$$$ŋ$ ơzp$$$[^_]à D$zpD$ ipD$$ɳ ÐUWVS,$@$D$H$L$X$$$PQӋA( zpݜ$ݜ$zpݜ$ݜ$.ݜ$ݜ$ȋIݜ$P,Ӌ@D$ݔ$ܬ$ݜ$ݜ$ݜ$ݔ$ܬ$$PH$ݜ$P8Ӌ@D$ܬ$ݜ$ݜ$ݜ$ܬ$\$(݄$܄$ݔ$܄$ݔ$ݜ$݄$ݜ$݄$ݜ$݄$܄$ݜ$݄$܄$ݔ$܄$ݔ$ݜ$݄$ݜ$D$(ܤ$ݜ$݄$܄$ݜ$܄$ݜ$D$(܄$ݔ$݄$ݜ$x܄$ݔ$p܄$ݔ$hݜ$`$PH ˋP Ӌ@4D$ݔ$ݜ$ݜ$ݔ$\$x$PH0\$pPӋ@D$T$hl$p\$`\$XT$ \$PD$ D$P܄$D$pD$hݔ$Xݜ$P݄$ݜ$HD$`ݜ$@݄$H܄$@ݜ$8܄$D$Pݜ$0D$xܤ$D$Xݔ$(ݜ$ ݄$D$xݔ$D$Xݔ$ݜ$܄$ݔ$D$`ݔ$ݜ$݄$Pܤ$ zp݄$P܄$T$H (zpܬ$݄$ܤ$ zp zp zp zp݄$D$H]$T@$D$D\$TQ\ȋI0\ɋ@ D$ \݄$0ܤ$ zp݄$0܄$ (zpܬ$݄$ܤ$ܤ$X zp zp zp zp݄$̋T$D݄$8ܤ$ zp݄$8܄$ (zpܬ$݄$ܤ$ܤ$( zp zp zp zpŋ$TIL$@݄$\$T@8D$<\$TR,T$\ዄ$TH\P \݄$ ܤ$ zp݄$ ܄$ (zpܬ$݄$ܤ$݄$Hܤ$@ zp zp zp zp܄$D$@D$D$<݄$ܤ$x zp݄$܄$x (zpܬ$݄$ܤ$݄$pܤ$h zp zp zp zpꋔ$TR(T$8݄$䋄$THϋP4‹@D$4Nj$T@D$݄$ܤ$` zp݄$܄$` (zpܬ$݄$ܤ$݄$ܤ$ zp zp zp zp݄$ˋD$8\\\T$\L$4\$$$\Ƌ$`ǡzp$P$T$$',[^_]à D$@zpD$ipD$$腪 ÐUWVSt$$$$$$l$B ݜ$EDыRӋA0DDݜ$`ݜ$Xݜ$Pݜ$H݄$ݜ$@܄$ݜ$8ݜ$0ݜ$(Q<ӋA\$xDDQ ӋA,DDݜ$ ݜ$D$xݜ$ݜ$ݜ$ݜ$D$xݜ$QӋA(\$pDD\$hQ8ӋADDݜ$D$hݜ$ݜ$D$hݜ$D$pݜ$ݜ$D$pݜ$ݜ$QӋA$\$`\$XDD\$PQӋA4\$HDDD$`D$Hݜ$D$PD$Xݜ$D$Xݜ$D$`d$Hݜ$l$Pݜ$݄$`܄$݄$܄$ $B ݄$H܄$݄$ ܤ$݄$Hܤ$ыR֋A0݄$`ܤ$݄$X܄$݄$Pܤ$݄$݄$ܤ$zpɋA(D$ ljʋỈЋRɋ@8D$݄$Xܤ$݄$܄$Pܤ$݄$܄$ɋT$ ݄$ܤ$݄$@ܬ$@\$@݄$ܤ$݄$(\$8܄$(\$0zpzp݄$݄$݄$\$(݄$݄$݄$$B,D$(D$0̋B D$(D$0ƋB ÐUWVS \$ L$$|$,l$0t$(;l$4WF$GFF $ zpzp$$ zpD$8 zp<;l$4B [^_]à D$ zpD$ipD$$= ÐUWVS$t$8\$NFNFNNݜ$xݜ$pݜ$hݜ$`F ݜ$Fݜ$Fݜ$Fݜ$FN(FN(ݜ$N(ݜ$FN(ݜ$F0Fݜ$FFݜ$FN8N8ݜ$FN8FN8\$݄$ݜ$Xݜ$P݄$D$ݜ$Hݜ$@݄$ݜ$8ܬ$ݜ$0݄$d$ݜ$(ܬ$ݜ$ F(N8ݜ$F8ݜ$F(ܬ$ݜ$݄$x݄$`N8ݜ$ݜ$݄$xN8݄$`ݜ$ݜ$݄$p݄$hN8ݜ$ݜ$݄$pN8݄$hݜ$ݜ$݄$݄$ܤ$ݔ$ݜ$N8܄$ݜ$F8ݜ$ܬ$ݔ$݄$܄$ݔ$N8ݜ$N8ݜ$ܬ$ݜ$݄$ܤ$ݔ$݄$܄$ݔ$N8ݜ$݄$N8ݜ$x݄$܄$ݔ$p݄$ܤ$ݔ$hݜ$`N8܄$`ݜ$`݄$pN8ݜ$X݄$x݄$`N(ݔ$P݄$xN(݄$`ݔ$Hݔ$@N8ݜ$8F8ݜ$0݄$PN8ݜ$(N8܄$(ݜ$(݄$p݄$hN(ݜ$ ݜ$݄$pN(݄$hݔ$ݜ$݄$ ݜ$N8܄$ݜ$݄$N8݄$ݜ$݄$ N8݄$ݜ$݄$ݜ$݄$N8܄$ݜ$W@D݄$8ݜ$܄$ݜ$܌$8ݜ$W Dݜ$݄$܄$ݜ$݄$W`D݄$X݄$P܌$X݄$Pݜ$x܄$݄$ݜ$ݜ$Eܤ$ܬ$ݜ$ݜ$xܤ$݄$xݜ$pݜ$h܄$x݄$Eݜ$`ݜ$XWDݜ$pF܄$pݜ$pFݜ$hWdD݄$ݜ$`݄$܄$`ݜ$`܌$݄$ݜ$XWDD݄$݄$܌$݄$ݜ$PW$DF(F(݄$p݄$`ݜ$Pݜ$H݄$h܄$P݄$Xݜ$@ݜ$8݄$hܤ$Pܤ$`ݜ$0ݜ$(݄$pܤ$Xݜ$ ݜ$W|D݄$ݜ$H݄$܄$Hݜ$H܌$݄$ݜ$@W\D݄$݄$܌$݄$ݜ$8W<D݄$݄$x܌$݄$xݜ$0WD݄$@݄$@݄$Hݜ$ݜ$݄$@܄$0݄$8ݜ$ݜ$݄$Hܤ$8ݜ$ݜ$݄$@ܤ$0ݜ$ݜ$WD݄$pݜ$(݄$h܄$(ݜ$(܌$p݄$hݜ$ W0D݄$݄$܌$݄$ݜ$WPD݄$(݄$0݄$(݄$0WpD݄$(ݜ$݄$8܄$ݜ$܌$(݄$8ݜ$݄$(݄$ݜ$ݜ$݄$ ݄$܄$ݜ$ݜ$ܬ$ ݄$(ݜ$ݜ$݄$݄$ܤ$ݜ$ݜ$WD݄$xݜ$݄$`܄$ݜ$܌$x݄$`ݜ$WhD݄$H݄$0܌$H݄$0ݜ$WHD݄$݄$݄$݄$W(D݄$݄$܌$݄$ݜ$݄$ݜ$ݜ$݄$݄$܄$ݜ$ݜ$xܬ$ݜ$pݜ$h݄$݄$ܤ$ݜ$`ݜ$XWxD݄$ ݜ$݄$@܄$ݜ$܌$ ݄$@ݜ$OXD݄$݄$܌$݄$ݜ$_8D݄$݄$܌$݄$ݜ$WD݄$p݄$h݄$p݄$h݄$ݜ$Pݜ$H݄$܄$݄$ݜ$@ݜ$8݄$ܤ$ݜ$0ݜ$(݄$݄$ݜ$ ݜ$WD݄$݄$܌$݄$ݜ$WTD݄$`݄$X܌$`݄$Xݔ$݄$ݜ$WtD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$W4D݄$ ݄$܌$ ݄$ݔ$݄$݄$݄$ݜ$ݜ$݄$܄$݄$܄$ݜ$ݜ$݄$pzpݜ$pzpݜ$݄$pzpݜ$pzpݜ$W DFFNFݜ$WLD݄$݄$܌$݄$ݔ$݄$ݜ$WlDݜ$xF8܄$xݜ$xF8W,D݄$P݄$H܌$P݄$Hݔ$p݄$x݄$xݜ$ݜ$݄$܄$܄$pݜ$ݜ$݄$pzpݜ$pzpݜ$݄$pzpݜ$pzpݜ$݄$܄$݄$܄$P݄$x܄$8݄$܄$`ݜ$h݄$P܄$݄$܄$݄$8܄$݄$܄$W@݄$h\܄$h]W`\ʋW \݄$ܤ$݄$xܤ$8ݜ$`݄$Pܤ$݄$`ܤ$ݜ$X݄$Pܤ$݄$8ܤ$݄$ܤ$݄$ܤ$ pzpWP͋W pzp\ˋWP\ pzp݄$`Wp݄$`W0 pzp݄$X\݄$XWp\݄$ܤ$݄$܄$Xݜ$P݄$Xܤ$ݜ$H݄$܄$ݜ$@݄$ܤ$݄$H܄$@pzpݜ$8pzpݜ$0݄$܄$݄$܄$ hzp `zp hzp `zp݄$܄$݄$Hܤ$@pzpݜ$(pzpݜ$ ݄$@ܤ$݄$Hܤ$hzpݜ$ `zp܄$ݜ$ `zp hzp݄$@܄$݄$H܄$`zp hzpݜ$ hzp `zpݜ$݄$ܤ$݄$ܤ$ `zp hzp `zp hzpݜ$݄$8݄$W݄$݄$ ܄$H\\ܤ$8ܤ$Wxܤ$݄$Hܤ$ \\݄$@܄$(݄$WHW݄$݄$0܄$P\WH\݄$@ܤ$(݄$WhW(ܤ$݄$Pܤ$0\Wh\݄$ܤ$ pzp݄$p$܄$pݜ$݄$ܤ$ pzp݄$xݜ$ܬ$xݜ$݄$p `zp݄$` hzp݄$0 `zp݄$  hzpݜ$ݜ$݄$܄$݄$܄$XzpPzp݄$0ܤ$݄$ ܤ$Hzp @zpݜ$ @zp Hzp݄$p hzp݄$` `zp݄$  `zphzp܌$0ݜ$ݜ$݄$0܄$݄$ ܄$ݔ$ݜ$݄$ݜ$݄$ܤ$݄$ܤ$ @zp Hzp @zp Hzpݜ$݄$$݄$W\W݄$݄$܄$\W\\$ܤ$ܤ$W|ʋW<ܤ$݄$ܤ$\W|\݄$܄$݄$WLW ݄$݄$܄$\WL\݄$ܤ$݄$WlɋW,ܤ$݄$ܤ$\Wl\݄$܄$ pzp݄$h܄$hݜ$݄$܄$ pzp݄$ݜ$ܬ$ݜ$݄$h hzp݄$X `zp݄$( hzp݄$ `zp\$x\$p݄$܄$݄$܄$Hzp @zp\$h @zp Hzp݄$ܤ$݄$(ܤ$Pzp\$`XzpD$`\$``zp݄$hhzp܌$X݄$ hzp܌$(\$X\$P݄$܄$\$(݄$(܄$T$ HzpD$(\$H@zpD$H\$HL$ D$(\$@݄$ܤ$݄$ܤ$\$D$D$\$8D$xD$`‹WTЋOD$8D$P܄$\\d$xd$8WtЋO4d$`݄$d$P\\݄$D$XD$HD$hWDЋOD$@D$p܄$\\݄$d$XD$@WdЋO$D$hd$H݄$d$p\\$$Ճ@zp<$9$Č[^_]à D$zpD$AjpD$$f ÐUWVSt$$$$D$;$SFOݜ$ GO GO(Oݜ$x O(ݜ$p GOGOO ݜ$h GO(GO(GO GO T$ݜ$hݜ$`݄$p ݜ$X܄$p ݜ$PD$ݜ$Hݜ$@݄$h ݜ$8ܬ$h ݜ$0݄$ ݔ$(O ݜ$ ݄$(O(ݜ$ ܄$ ݔ$ O ݜ$ ݄$ O(ݜ$ ݄$x ݔ$O(ݜ$ ݄$O ܬ$x ݔ$O(ݜ$ O ݜ$ GO8GO8ݜ$ O8ݜ$ GO8G O8ݜ$ G(O8GO0GO0\$GO0O0ݜ$ G(O0G O0ݜ$ ݜ$݄$ D$ݜ$݄$ ݜ$݄$ ݜ$ݜ$݄$ d$ݜ$݄$ ݜ$݄$ ݜ$ܬ$ ݜ$܄$ ݜ$݄$(O0݄$O8ݜ$ݜ$݄$ O0݄$O8ݜ$ݜ$݄$(O8݄$O0ݜ$ݜ$݄$ O8݄$O0ݜ$ݜ$܄$ ݜ$xܬ$ ݜ$p݄$ ܄$ ݔ$hO0ݜ$` ݄$hO8ݜ$X ݄$ ܄$ ݔ$`O8ݜ$P ݄$`O0ݜ$H ݄$0O8ݔ$@ ݄$PO0ݔ$8 ݜ$X݄$0O0ݔ$0 ݄$PO8ݔ$( ݜ$P݄$HO8ݔ$ ݄$`O0ݔ$ ݜ$H݄$ ݔ$@O8ݜ$ ݄$@O0ݜ$ ݄$ ܤ$ ݔ$8O0O8ݜ$ ݄$HO0ݔ$ ݄$`O8ݜ$0܄$ ݔ$(O8ݜ$ ݄$(O0ݜ$ ݄$ ܄$ ݔ$ O0ݜ$ ݄$ O8ݜ$ ݄$hO0ݔ$ ݄$@O8ݜ$݄$8O8ݔ$ ݄$XO0ݜ$݄$8O0ݜ$ ݄$XO8݄$ ݜ$݄$ ܤ$ ݔ$O8O0݄$hO8ݜ$ ݄$@O0\$݄$ d$ݜ$ ݄$ ܤ$ ݔ$ O0ݜ$ ݄$ O8ݜ$ ݄$` ܤ$ ݜ$ ݄$ ܄$ ݜ$ ܬ$ ݜ$ ܄$ ݜ$ ݄$X ܄$ ݄$ ܤ$ ݜ$ D$܄$ ݜ$ ܬ$ ݜ$ ݄$ ݜ$ ݄$ ܄$H ݜ$ ܬ$ ݜ$ ݄$@ ܄$8 ݜ$ ݄$ ݜ$ ݄$P ݜ$ ݄$ ܄$ ݜ$ ݄$0 ܤ$( ݜ$x ܄$P ݄$` ܄$ ݜ$p ݄$X ܤ$ ݜ$h ݄$ ܤ$H ݜ$` ܄$ ݜ$X ݄$ ܄$ ݜ$P ݄$ ܤ$ ݜ$H ܬ$ ݜ$@ GH݄$O@݄$ ݄$X ݜ$8 ݄$@ O@ܬ$8 ݜ$8 ݄$(݄$O@ݜ$0 ݄$x݄$pO@ݜ$( ݄$` O@ݜ$ ݄$ O@ݜ$ ݄$܄$ ݜ$ ݄$ O@݄$(ݜ$ G@݄$` ݜ$ ݄$X O@݄$@ ݜ$ ݄$ݜ$ ݄$ O@ܬ$ ݜ$ ݄$݄$O@ݜ$ ݄$O@݄$ݜ$ ݄$8O@݄$Xݜ$ ݄$hO@ݜ$ ݄$@܄$ ݜ$ ݄$ ݄$O@ݜ$ ݄$8݄$`O@ݜ$ GO@Gݜ$ ݄$(O@ݜ$ ݄$܄$ ݜ$ ݄$8O@݄$`ݜ$ ݄$8݄$XO@ݜ$ GGO@ݜ$ ݄$hݜ$ ݄$@O@ܬ$ ݜ$ ݄$ ݄$(O@ݜ$ ݄$xO@݄$pݜ$ ݄$ O@݄$ݜ$ ݄$P O@ݜ$x ݄$H ܄$x ݜ$x ݄$p O@݄$h ݜ$p ݄$0݄$HO@ݜ$h G G(O@ݜ$` ݄$P ݜ$X ݄$H O@ܬ$X ݜ$X ݄$ ݄$O@ݜ$P ݄$0O@݄$Hݜ$H G O@G(ݜ$@ ݄$Pݜ$8 ݄$XO@ܬ$8 ݜ$8 ݄$p ݄$h O@ݜ$0 ݄$H݄$`O@ݜ$( ݄$hO@݄$@ݜ$ O@ݜ$ G܄$ ݜ$ GO@ݜ$ ݄$0݄$PO@ݜ$ ݄$h݄$@O@ݜ$ ݄$HO@ݜ$ ݄$`܄$ ݜ$ ݄$PO@݄$Xݜ$ ݄$0O@݄$Pݜ$ ݄$ ܌$ ݜ$F@݄$` ݜ$x݄$` 닆݄$ ݄$ ݄$xݜ$ ݜ$ ܤ$ܬ$xݜ$ ݜ$ ݜ$ ݜ$x ݄$ݜ$p ݜ$h F ݄$8݄$X܌$8݄$Xݜ$p݄$ ݄$ ܌$ ݄$ ݔ$h݄$pݜ$`዆݄$ ݄$ ݜ$X܌$ ݄$ ݜ$PF`݄$݄$܌$݄$ݜ$H݄$Xݜ$@݄$Pܤ$H݄$Xݜ$` ݜ$X ݄$p܄$h݄$P܄$Hݜ$P ݜ$H ݄$`݄$@Pzpݜ$@ Pzpݜ$8 ܄$`݄$@Pzpݜ$0 Pzpݜ$( F݄$(݄$݄$(݄$⋆݄$݄$܌$݄$ݜ$8ݜ$0ݜ$(FP݄$X ݄$@ ܌$X ݄$@ ݜ$݄$ ݄$ ݄$ ݄$ ݔ$ ݄$ܬ$ݔ$݄$8ݜ$ ݄$0ݜ$ ݄$(ݜ$Hzp݄$ݜ$ @zpܬ$ ݜ$ ݄$ݜ$ ݄$(܄$ݜ$ ݜ$ ݄$0݄$8ܤ$ ݜ$ ݜ$ ݄$ ݄$ ݜ$݄$ ݄$ Fp݄$݄$܌$݄$݄$ݜ$ݜ$ݜ$ܬ$ݜ$F0݄$h݄$@܌$h݄$@ݜ$݄$ ݄$ ݄$ ݄$ ݄$ܬ$ݜ$݄$ݜ$ ݄$ݜ$ ݄$݄$ܤ$ݜ$ݜ$ ݄$܄$ ݜ$ ݄$ݜ$ ܬ$݄$܄$ݜ$ ܄$ ݜ$ ݜ$ ݄$݄$ݜ$ ݜ$ F݄$ ݄$ݜ$܌$ ݄$ݜ$݄$ ݄$ ݜ$܌$ ݄$ ݜ$݄$܄$ݜ$݄$܄$ݜ$FH݄$x݄$p܌$x݄$pݜ$݄$ ݄$ ݜ$܌$ ݄$ ݔ$݄$ݜ$x݄$ݜ$pF(݄$0݄$P݄$0݄$P⋆݄$H ݄$h ܌$H ݄$h ݜ$hݜ$`ݜ$X݄$ ݄$ ܌$ ݄$ ݜ$HFh݄$݄$܌$݄$ݜ$@݄$H܄$@݄$Hܤ$@ݜ$P݄$܄$xݔ$ ݄$hݔ$ ݜ$ ݄$܄$pݔ$ ݄$`ݔ$ ݜ$x ݄$ܤ$ܤ$ݜ$p ݜ$h ݄$ܤ$xܬ$`ݜ$` ݜ$X ݄$P݄$Xݜ$P Pzp܌$P ݜ$P Pzpݜ$H ܬ$X܄$PPzpݜ$@ ݔ$8 Pzpݜ$8 ݄$ܤ$pܤ$hݜ$0 ݜ$( ݄$ܤ$݄$ܤ$ݜ$ ݜ$ ݄$ ݄$ ݜ$8܌$ ݄$ ݜ$0Fx݄$݄$ݜ$(܌$݄$ݜ$ ݄$8܄$(ݜ$݄$0܄$ ݜ$F8݄$P ݄$H ܌$P ݄$H ݜ$݄$ ݄$8 ݜ$܌$ ݄$8 ݔ$݄$ݜ$݄$ݜ$F݄$H݄$`݄$H݄$`⋆݄$ ݄$ ܌$ ݄$ ݜ$ݜ$ݜ$݄$@ ݄$` ܌$@ ݄$` ݜ$FX݄$p ݄$h ܌$p ݄$h ݜ$݄$܄$݄$ܤ$ݜ$݄$܄$ݔ$ ݄$ݔ$ ݜ$ ݄$܄$ݔ$݄$ݔ$ݜ$݄$0ܤ$ ܤ$ݜ$ݜ$݄$ܤ$݄$ݜ$ݜ$݄$݄$ݜ$Pzp܌$ݜ$Pzpݜ$ܬ$܄$Pzpݜ$ݔ$Pzpݜ$݄$ܤ$ܤ$ݜ$ݜ$݄$8ܤ$(݄$ܤ$ݜ$ݜ$G@ݜ$O@ݔ$F|݄$݄$܌$݄$ݔ$݄$ݜ$ݜ$F<݄$݄$ ܌$݄$ ݜ$݄$ ݄$ ݜ$܌$ ݄$ ݜ$x݄$ݜ$p݄$܄$xݜ$hF݄$ ݄$ݜ$@݄$ ݄$዆݄$ ݄$ ܌$ ݄$ ݄$@ݜ$`ݜ$Xܬ$@ݜ$P݄$ ݄$ ܌$ ݄$ ݜ$8F\݄$݄$݄$݄$݄$8ܬ$8ݜ$H݄$܄$p$݄$`$ݜ$,$ݜ$x݄$ܤ$hܤ$`ݜ$pݜ$h݄$܄$hݜ$`ݜ$X݄$݄$ܤ$xݜ$Pݜ$H݄$Xܤ$P݄$Hݜ$@Pzp܌$@ݜ$@Pzpݜ$8ܤ$H݄$P܄$XPzpݜ$0Pzpݜ$(݄$ܤ$pݜ$ ݜ$݄$ܤ$ܤ$ݜ$ݜ$Fݜ$0G܄$0ݜ$0Gݜ$(݄$ ݄$ ݜ$ ܌$ ݄$ ݔ$݄$0܄$ ݜ$݄$(ݜ$FD݄$P݄$X܌$P݄$Xݜ$݄$x ݜ$݄$X ܄$ݜ$܌$x ݄$X ݔ$݄$ݜ$݄$ݜ$F$G G(G G(⋆݄$p ݄$0 ܌$p ݄$0 ݜ$ݜ$݄$ ݄$( ܌$ ݄$( ݜ$Fd݄$݄$݄$݄$݄$ܬ$ݜ$݄$܄$$݄$$ݜ$,$ݜ$݄$ܤ$$$ݜ$$ݜ$݄$܄$ݜ$ݜ$݄$(ܤ$ܤ$ݜ$ݜ$݄$݄$Pzpݜ$Pzpݜ$ܬ$܄$Pzpݜ$ݔ$Pzpݜ$݄$ܤ$ܤ$ݜ$ݜ$݄$0ܤ$ ݄$ܤ$ݜ$ݜ$F݄$h݄$@݄$h݄$@⋆݄$x ݄$ ܌$x ݄$ ݜ$ݜ$ݜ$F4݄$ ݄$(݄$ ݄$(⋆݄$ ݄$( ܌$ ݄$( ݜ$ݜ$ݜ$FT݄$0݄$H݄$0݄$H⋆݄$ ݄$ ܌$ ݄$ ݜ$ݜ$ݜ$x݄$ ݄$P ܌$ ݄$P ݜ$`Ft݄$݄$݄$݄$ݜ$p݄$`ܬ$`ݜ$h݄$܄$݄$p܄$ݜ$ݜ$x݄$ܤ$݄$ܤ$ݜ$pݜ$h݄$܄$݄$ݜ$`ݜ$X݄$݄$hHzpݜ$P @zpܬ$Pݜ$P Hzp @zpݜ$H݄$݄$x@zpݜ$@ Hzp܄$@ݜ$@ Hzp @zpݜ$8݄$܄$xHzp @zpݜ$0 @zp Hzpݜ$(݄$pܤ$ܤ$ݜ$ ݜ$܄$݄$h@zpݜ$ Hzpܬ$ݜ$ @zp Hzpݜ$F GGGG⋆݄$ ݄$ ܌$ ݄$ ݜ$Xݜ$PF,݄$8݄$`݄$8݄$`⋆݄$ ݄$8 ܌$ ݄$8 ݜ$Hݜ$@ݜ$8FL݄$݄$܌$݄$ݜ$݄$ ݄$ ܌$ ݄$ ݜ$0݄$ݜ$(ܬ$ݜ$ ݄$ ݜ$݄$0 ܄$ݜ$܌$ ݄$0 ݜ$FlG0G8G0G8݄$݄$ܬ$ݜ$ܬ$ݜ$݄$X܄$0\$݄$HD$ݜ$d$ݜ$݄$H݄$@ݜ$ݜ$݄$(܄$@ݜ$ݜ$݄$P݄$ Hzp @zpݜ$ @zp Hzpݜ$݄$݄$ܤ$8Hzpݜ$ @zp܄$ݜ$ Hzp @zpݜ$݄$݄$܄$8@zp Hzpݜ$ @zp Hzpݜ$ܤ$(݄$Xܤ$0ݜ$ݜ$݄$P܄$ @zpݜ$ Hzpܬ$ݜ$ Hzp @zpݜ$݄$ ܄$` ݄$ ܄$ ݄$܄$X݄$X܄$ݜ$ݜ$݄$ ܄$ ݄$H ܄$p ݄$ ܄$ ݄$ ܄$ ݜ$ݜ$݄$܄$݄$܄$ݜ$݄$ܤ$݄$ܤ$Xݜ$ݜ$݄$ܤ$݄$Xܤ$ݜ$݄$ ܄$ $݄$܄$$ݜ$$ݜ$݄$Ƌ݄$܄$݄$݄$ܤ$ܤ$݄$ӋF@܄$ܤ$݄$݄$ PzpӋF ݄$܄$ Pzp݄$ܤ$݄$ܤ$ PzpӋF`ܤ$ Pzpܤ$݄$ ܤ$` ݄$ ܤ$ ݜ$݄$x܄$݄$`܄$@zp Hzpݜ$ @zp Hzp݄$ ܤ$ ݄$p ܤ$H ݜ$ݜ$݄$x ܤ$ ݄$ ܄$Pzpݜ$ Pzp݄$ܤ$x݄$ܤ$`@zp Hzpݜ$x Hzp @zp݄$ ܄$x ݄$ ܤ$Pzpݜ$pPzpݜ$h݄$܄$x݄$܄$`Hzpݜ$` @zp܄$`ݜ$` @zp Hzpݜ$X݄$xܤ$݄$`ܤ$ Hzp @zp Hzp @zpݜ$P݄$݄$x‹ӋF0݄$P݄$h܄$ܤ$ܤ$PӋFpܤ$x݄$ܤ$h݄$܄$p݄$`܄$ӋF݄$X݄$݄$ܤ$p݄$X⋖ӋFP݄$ܤ$`݄$݄$ ܤ$P ݄$ ܤ$ Pzpݜ$Hݜ$@݄$0 Hzp݄$` @zp݄$ Hzp݄$ @zpݜ$8ݜ$0݄$ ܤ$ Pzp݄$h ܤ$X ݜ$(݄$0 @zp݄$` Hzp݄$ Hzp݄$ @zpݜ$ ݜ$݄$ܤ$ Pzp݄$ ݄$ ݄$ܤ$ Pzp݄$p݄$p 8zp 0zp(zpݜ$ zp܄$ݜ$ 8zp 0zp (zp zpݜ$݄$ ܤ$p Pzp݄$܄$ݜ$݄$hܤ$ Pzp݄$݄$0zpݜ$ 8zp܄$ݜ$݄$ (zp zp 8zp 0zp zp܌$ (zpݜ$݄$H܄$8݄$ŋӋF8݄$݄$Hܤ$8㋖ӋFxܤ$ܤ$݄$@܄$ ݄$܄$ӋF݄$݄$0܄$(݄$@ܤ$ ܤ$ӋFX݄$ܤ$݄$(ܤ$0݄$ ܄$P ݄$ ܄$ Pzpݜ$ݜ$݄$( @zp݄$X Hzp݄$ @zp݄$ Hzpݜ$ݜ$݄$ ܄$ Pzp݄$X ܄$h ݜ$ݜ$݄$( Hzp݄$X @zp݄$ @zp݄$ Hzpݜ$ݜ$݄$܄$ Pzp݄$݄$݄$܄$ Pzp݄$h݄$h zp (zp8zp 0zpݜ$ (zp zp 0zpݜ$ 8zpܬ$ݜ$݄$p܄$  Pzp݄$܄$ݜ$݄$h܄$ Pzp݄$݄$ zp (zp 0zp݄$ 8zp zp (zp0zp܌$ݜ$ 8zp܄$ݜ$݄$܄$ŋӋF(݄$܄$݄$ܤ$勖ʋFh݄$ܤ$݄$܄$݄$܄$ӋF݄$݄$܄$݄$ܤ$ܤ$ӋFH݄$ܤ$݄$ܤ$݄$ ܤ$@ ݄$ ܤ$ ݜ$ݜ$݄$ ܤ$ ݄$ ܤ$( ݜ$x݄$p ܤ$P ݄$ ܤ$@ 8zp 0zp 0zp 8zp݄$ܤ$݄$ܤ$ 8zp 0zp 8zp 0zpݜ$pݜ$hݜ$`ݜ$X݄$ܤ$݄$Pܤ$@݄$ܤ$݄$8ܤ$H zp zpݜ$Pzpݜ$H zpܬ$Hݜ$H zp zp zp zpݜ$@݄$Pܤ$@݄$ܤ$݄$ܤ$0݄$ܤ$ zp zpzpݜ$8 zp܄$8ݜ$8 zp zp zp zp݄$܄$p݄$P‹ӋF<݄$h݄$ܤ$p㋖ˋF|ܤ$Pܤ$h݄$܄$`݄$@‹ӋF݄$H܄$8݄$X܄$x݄$ܤ$`݄$Hܤ$8ӋF\ܤ$@݄$xܤ$X݄$x ܤ$0 ݄$ ܤ$ ݜ$0ݜ$(݄$ ܤ$ ݄$ ܤ$8 ݜ$ ݜ$݄$h ܤ$8 ݄$ ܤ$H zp (zp zp (zp݄$ܤ$݄$ܤ$ (zp zp zp (zpݜ$ݜ$ݜ$ݜ$݄$ܤ$݄$ܤ$0݄$ܤ$݄$(ܤ$zp zpݜ$zp zpݜ$ zp zp zp zp݄$Hܤ$(݄$ܤ$݄$ܤ$8݄$ܤ$ zp zpzpݜ$ zp܄$ݜ$ zp zp zp zp݄$0܄$݄$‹ӋF4݄$܄$݄$0ܤ$㋖ˋFtܤ$݄$ܤ$݄$(܄$‹ӋF݄$܄$݄$܄$ ݄$(ܤ$݄$ܤ$ӋFT݄$ ܤ$݄$x ܄$0 ݄$ ܄$ ݜ$݄$ ܄$ ݄$8 ܄$ ݜ$ݜ$݄$h ܄$8 ݄$ ܄$H 0zp8zp݄$܄$݄$܄$ݔ$܌$ݜ$ݜ$ݜ$ݜ$݄$܄$݄$0܄$݄$܄$݄$(܄$zp zpݜ$ zp zp zp zp zp zpݜ$݄$H܄$(݄$܄$\$x݄$܄$8݄$܄$ zp zpzpL$xݜ$ zp܄$ݜ$ zp zpzpL$x zpݜ$݄$݄$ËӋF$݄$܄$ܤ$䋖ʋFdܤ$݄$ܤ$݄$܄$݄$܄$ӋF݄$݄$܄$݄$ܤ$ܤ$ӋFD݄$ܤ$݄$ܤ$݄$ ܄$@ ݄$ ܄$ \$p݄$ ܄$ ݄$( ܄$ \$h\$`݄$p ܄$P ݄$ ܄$@ (zp zp zp (zp݄$܄$݄$܄$ (zp zp (zp zp\$X\$P\$H\$@݄$܄$݄$@܄$P݄$܄$݄$8܄$Hzp\$8 zpD$8\$8 zp zp zp zp zp zp\$0݄$P܄$@݄$܄$\$݄$܄$0݄$܄$ zp zpzpL$\$( zpD$(\$( zp zpzpL$ zp\$ D$XD$8ËӋF,D$PD$`d$X䋖ʋFld$8D$`d$PD$pD$HD$0D$ ӋF D$(D$@D$hD$pd$Hd$(ӋFLD$ d$0D$hd$@у$Pzp4;$t[^_]à D$zpD$L_jpD$$4 UWVS|$$$$D$t$ŋ$9D$tDEEEE$$\$h\$`$\$X\$P\$HCT$L$K \$ D$ \$ SD$h\$D$\$L$h\$l$\$CD$XD$`D$XD$`D$\$@D$ D$\$8D$T$0\$(D$D$ D$PD$(D$HD$@ zp zp zpD$@ zp zp zpD$PʋCʋCD$8 zp zp zpD$8 zpd$0 zpD$( zpl$HCCƃD$t$ƃ zp$9D$t|[^_]à D$zpD$jpD$$ ÐUWVSd$x$|$$$\R$֋$9$\uNFNFNNݜ$Pݜ$HF F(݄$Pݜ$@FFݜ$8Fݜ$0Fܬ$0ݜ$0݄$P݄$Hݜ$(ݜ$ F܄$ ݜ$ Fݜ$ݜ$݄$Hܬ$ݜ$W$D݄$@܌$@ $ݜ$Eݜ$ݜ$Eݜ$WD݄$P\$PD$P\$P܌$P\$Hl$H\$HWDF\$@Fl$@\$@O$DWD݄$8݄$0܌$8݄$0D$Pݔ$ݔ$ݜ$D$Hݔ$D$@ݔ$ݜ$D$Pݔ$ݔ$ݜ$l$Hݔ$d$@ݔ$ݜ$WD\$8݄$HD$8\$8݄$HW DFFN\$0Fl$0\$0_D݄$(݄$܌$(\$(݄$l$(\$(O D݄$ ݄$܌$ \$ ݄$l$ \$ D$8ݔ$D$(ݔ$D$ D$0T$x\$pD$8T$hT$`\$Xd$(D$ d$0݄$ Pzp܄$ Xzpܬ$݄$ܤ$T$ Hzp @zpHzpL$ @zpT$݄$ɋWW W$W݄$ Pzp܄$ Xzpܬ$ܤ$݄$ܤ$ Hzp @zp Hzp @zp܄$W\W \\W\W$\D$Xܤ$ PzpD$X܄$ Xzpܬ$݄$ܤ$݄$d$x Hzp @zp Hzp @zp݄$WWWD$pܤ$ PzpD$p܄$ Xzpܬ$݄$ܤ$D$hd$` Hzp @zp Hzp @zp݄$]W\W\‹W\\$\$̓0zp<$9$\d[^_]à D$zpD$ĨjpD$$ ÐUWVSd$x$|$$$\$Ӌ$9$\KCKCKKݜ$Pݜ$Hݜ$@ݜ$8CK(CK(K(CK(K \$CK CK CK D$ݜ$0ݜ$(ݜ$ ݜ$ݜ$ݜ$ݜ$D$ݜ$݄$8K(݄$@K ݜ$ݜ$݄$8K ݄$@K(ݜ$ݜ$݄$PK ݄$HK(݄$PK(݄$HK ݜ$ݜ$݄$PK0݄$HK8C0ݜ$C8܄$ݜ$݄$8K8݄$@K0ݜ$݄$PK8݄$HK0ݜ$݄$8K0ݜ$݄$@K8܄$ݜ$K8CK0ݜ$CK8CK0ݜ$C8ݜ$C0ܬ$ݜ$K0CK8CK0CK8ݜ$W(D݄$0݄$܌$0݄$ݜ$WDݜ$܄$ݜ$W<D݄$݄$݄$ݜ$ݜ$xEܤ$ܬ$ݜ$pݜ$hݜ$`ݜ$X݄$Eݜ$Pݜ$HW D݄$݄$݄$݄$WHD݄$݄$ݜ$ݜ$ݜ$ݜ$WDD݄$݄$݄$݄$WD݄$݄$܌$݄$ݜ$ݜ$ݜ$W4D݄$݄$܌$݄$ݜ$W DCCCC݄$ܬ$ݜ$W0D݄$ݜ$݄$ ܄$ݜ$܌$݄$ ݜ$WD݄$8݄$@܌$8݄$@݄$݄$$ܬ$ܬ$݄$ݜ$@݄$ݜ$8݄$@܄$8ݜ$0݄$ݜ$($ܤ$ݜ$ ݄$(܄$ ݜ$܄$ݔ$$܄$ݜ$܄$ݜ$܄$ݔ$܄$ݔ$ݜ$݄$ݔ$ݔ$ݜ$ܬ$ݔ$ݔ$ݜ$݄$܄$ݔ$݄$ݔ$ݜ$݄$ܤ$ݔ$ܤ$ݔ$ݜ$WD݄$P݄$H݄$P݄$HO8D݄$݄$݄$݄$ݜ$\$x\$p\$hWDCCW,D݄$݄$܌$݄$\$`\$X\$PW$DC C(C C(WLDC0C8K0C8\$H\$@\$8W@D݄$݄$݄$݄$wD݄$(݄$܌$(݄$T$0\$(\$ ݄$d$Hd$`ݔ$D$xd$@D$(d$X$D$xD$@ݜ$xD$(D$Xݜ$p݄$x܄$pݜ$h݄$D$Hݜ$`D$0D$`ݜ$X݄$`܄$Xݜ$PD$pݜ$Hݜ$@݄$H܄$@ݜ$8l$pݔ$0ݔ$(ݜ$ D$hD$8ݔ$D$ D$Pݔ$ݜ$D$hd$8ݔ$D$ d$Pݔ$ݜ$݄$0 zp܄$0 zpܬ$݄$(ܤ$ T$$$ zp zp zpD$ zp݄$ʋW(WʋWH݄$ zp܄$ zpܬ$H݄$@ܤ$8ܤ$ zp zp zp zp܄$HW(\\\W\WH\݄$Pܤ$ zp݄$P܄$ zpܬ$x݄$xܤ$p݄$ܤ$ zp zp zp zp݄$xW0W WW@݄$hܤ$ zp݄$h܄$ zpܬ$P݄$`ܤ$X݄$ܤ$ zp zp zp zp݄$P]W \W0\‹W\W@\݄$ܤ$ zp݄$܄$ zpܬ$`݄$ܤ$݄$Hܤ$@ zp zp zp zp݄$`ˋW<W,WL‹W W݄$8ܤ$ zp݄$8܄$ zpܬ$h݄$ܤ$݄$ܤ$ zp zp zp zp݄$hˋW<\W,\WL\W \W\݄$ܤ$ zp݄$܄$ zpܬ$X݄$0ܤ$(݄$ܤ$ zp zp zp zp݄$XˋWW4WD‹WW$݄$ ܤ$ zp݄$ ܄$ zpܬ$p݄$ܤ$݄$ܤ$ zp zp zp zp݄$pˋW\W4\WD\W\W$\$\$Ճ@zp<$9$\Rd[^_]à D$zpD$jpD$$c ÐUWVS$$ $$$$$$9$$T$X@T$P@T$H@\$@L$@D$XL$@ݜ$ݜ$ݜ$ݜ$@(T$8D$PD$HL$8D$XL$8D$@L$8@ \$0D$XL$0D$@L$0D$PL$0D$HL$0T$ݜ$ݜ$ݜ$D$ݜ$ݜ$ݜ$݄$L$0ݜ$݄$L$8݄$ݜ$݄$L$0ݔ$݄$L$8݄$L$8ݔ$݄$L$0ݜ$݄$L$8\$݄$L$0D$ݜ$ܬ$ݜ$xD$ݜ$p܄$ݜ$hܬ$ݜ$`@0T$(@8T$ ݄$݄$ݜ$X݄$݄$L$(ݜ$P݄$݄$L$(ݜ$H݄$ݜ$@݄$L$(ܬ$@ݜ$@D$HL$(D$@L$ ݜ$8D$XL$(D$PL$ ݜ$0D$XL$ D$PL$(ݜ$(݄$L$(݄$L$ ݜ$ D$0L$ ݜ$D$8L$(ܬ$ݜ$D$0L$(D$8L$ D$HL$ D$@L$(ݜ$D$(݄$L$ ݜ$D$(݄$L$ ݜ$݄$L$(ݜ$݄$L$ ܄$ݜ$݄$L$ D$(ݜ$D$ ݄$L$(ݜ$݄$L$(݄$L$ ݜ$݄$L$ ݜ$݄$L$(ܬ$ݜ$݄$L$(D$ ݜ$D$ ݄$L$(ݜ$Eݜ$FD݄$݄$FPD݄$Xݜ$ ݄$P܄$ ݜ$ ܌$X݄$Pݔ$݄$ ݜ$ݜ$F(D݄$ݜ$܄$ݜ$܌$ݜ$F<D݄$݄$݄$݄$݄$ݜ$zp܌$ݜ$݄$ݜ$zp܌$ݜ$܄$ݔ$ zp/ݜ$܄$ݔ$ zpܬ$ݜ$xܤ$ ݄$zp zpݜ$p zp zpݜ$hܤ$݄$zp zpݜ$` zp zpݜ$XF DD$Hݜ$D$@܄$ݜ$L$HD$@ݜ$F D݄$݄$FHD݄$ ݄$@ݜ$܌$ ݄$@ݜ$F\D݄$0݄$(܌$0݄$(ݜ$F4D݄$`݄$p݄$`݄$p݄$݄$݄$ݜ$ݜ$܄$܄$ݔ$ݔ$܄$݄$ݜ$P݄$ݜ$H zp zp zp zp zp zp݄$ݜ$@ݜ$8ݜ$0ݜ$(݄$ zp݄$ zp݄$ zp݄$ zpܤ$ zp݄$ zp݄$ݜ$ ݜ$ݜ$ݜ$FDD$Xݜ$D$P܄$ݜ$L$XD$Pݜ$FD݄$݄$܌$݄$ݜ$xF@D݄$ݜ$p݄$܄$pݜ$p܌$݄$ݜ$hFTD݄$8݄$܌$8݄$ݜ$`F,D݄$x݄$h݄$x݄$h݄$xܤ$`݄$h݄$pݜ$݄$x܄$`ݔ$܄$hݔ$ݜ$܄$p݄$ݜ$݄$܄$ݜ$ zp zp zp zp zp zp݄$ݜ$ݜ$ݜ$ݜ$ zp݄$ zp݄$ zp zp݄$ܤ$ zp݄$ zpܬ$ݜ$ݜ$ݜ$ݜ$VD݄$ݜ$X݄$܄$Xݜ$X܌$݄$ݜ$PF$DD$0D$8L$0D$8ݜ$(FLD݄$ݜ$ ݄$܄$ ݜ$ ܌$݄$ݜ$^`DD$(D$ L$(D$ ݜ$N8D݄$݄$݄$݄$݄$(ܤ$݄$݄$ ݜ$H݄$(܄$ݔ$@܄$ݔ$8ݜ$0܄$ ݄$Xݜ$݄$P܄$0ݜ$ zp zp zp zp zp zp݄$Xݜ$ݜ$ݜ$ݜ$ zp݄$H zp݄$H zp zp݄$@ܤ$8 zp݄$0 zp݄$Pݜ$ݜ$xݜ$pݜ$hFD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$FD݄$݄$܌$݄$ݜ$FDD݄$݄$H܌$݄$Hݜ$FXD݄$݄$܌$݄$ݜ$F0D݄$݄$݄$݄$݄$ܤ$݄$ݜ$ݜ$݄$܄$ݔ$܄$ݔ$ݜ$݄$݄$܄$ݜ$` zp zp zp zp zp zp݄$ݜ$Xݜ$Pݜ$Hݜ$@݄$ zp݄$ zp݄$ zp݄$ zp݄$ܤ$ zp݄$ zp݄$ݜ$8ݜ$0ݜ$(݄$ܤ$݄$`ܤ$H zp zp zp zp܄$ݜ$݄$܄$݄$P zp zpܬ$܄$F(ˋF<FPF݄$ܤ$ܤ$P zp zp zp zp݄$܄$݄$܄$݄$`܄$H zp zp]F(\̋F<\F\ɋFP\݄$܄$݄$`ݜ$ܤ$`ݜ$݄$܄$x݄$pݜ$܄$pݜ$݄$ zpzp݄$݄$ zp݄$ zp\$݄$X zp݄$8 zp݄$@ zp݄$  zpD$ݜ$l$zpݜ$ݜ$݄$ zp݄$ zp݄$ xzp݄$p pzpݜ$@݄$0 hzp݄$ `zp݄$H Xzp Pzpݜ$x݄$@zpݜ$pܬ$@ݜ$hzp܌$ݜ$8݄$ zp܄$8ݔ$8݄$ pzp݄$p xzpT$ Xzp݄$H Pzp݄$ hzp݄$0 `zpݜ$`D$ zp܄$8ݜ$Xzp܌$ݜ$0݄$ܬ$0ݔ$0zp܌$݄$ zpݔ$(݄$8 zp݄$X zp݄$  zp݄$@ zp$݄$0ܤ$(ݜ$P$ݜ$Hzp܌$Hݜ$H$݄$܄$F݄$\݄$܄$`݄$h܄$\݄$P zp zp zp݄$P zpݜ$ ݄$ zpܬ$݄$ܤ$ݜ$FT݄$܄$ F@ɋF݄$ܤ$ F,݄$ zp zp zp݄$ zp zp݄$݄$H݄$HF\F@\̋FT\ʋF,\݄$x zp zp zp݄$x zp݄$` zpܬ$‹FLʋF$݄$X zp zp zp݄$X zp݄$h zpܬ$݄$p݄$p\FL\\\݄$ܤ$݄$Xݜ$܄$Xݜ$݄$xܤ$݄$hݜ$ܤ$hݜ$݄$ zp݄$ zp݄$h Xzp݄$ Pzp\$݄$@ zp݄$( zpHzp݄$(@zp݄$D$ݜ$l$zpݜ$ݜ$݄$ zp݄$ zp݄$ hzp݄$x `zpݜ$݄$0݄$P݄$8 xzp݄$ pzpݜ$݄$zpݜ$܄$ݜ$zp܌$݄$ zpݔ$݄$x hzp݄$ `zpݜ$Hzp݄$P@zp݄$0݄$ xzp݄$8 pzp$݄$$ݜ$ݜ$݄$$$ݜ$zp݄$ݜ$ܬ$ݜ$݄$ zp݄$ zp\$x݄$ Xzp\$p݄$h PzpD$pT$pD$x݄$( zp݄$@ zp܌$݄$(D$xD$pݜ$ݜ$‹F݄$܄$݄$\F ݄$܄$݄$܄$\zp݄$zp݄$\$h݄$ zpܬ$݄$ܤ$\$`^XߋNDD$`D$hϋFNjV0D$`d$h݄$݄$ zp݄$݄$݄$\\\\݄$݄$݄$ zpܬ$݄$݄$^\ߋNHϋF NjV4݄$݄$݄$݄$݄$ zpܬ$݄$݄$\\\\$$ Ń$@zp4$9$|[^_]à D$zpD$jpD$$\ UWVS,t$@\$Dl$T|$H;l$XT$LB\$ \$T$PJ΍\$$\$$GD$D$L$L$GD$ D$L$L$ ˃D$\ÃzpD$LD$P;l$X",[^_]à D$`zpD$jpD$$ ÐUWVS4$H$L$\$,@$PƋ$`9$,$TIL$ݜ$ ݔ$EDݜ$ݜ$$TP׋H L$ݜ$ݜ$DDݜ$ݜ$$X@D$ D$D$4ݜ$ݜ$D$ DL$4Dݜ$ݜ$ЉD$0NjD$ D$D$,ݜ$ݜ$D$0DL$,Dݜ$ݜ$$X@D$D$D$(ݜ$ݜ$D$DL$(Dݜ$ݜ$ЉD$$Nj\$\$ݜ$\$xDD\$p\$h$XA NjL$L$\$`\$XDD\$P L$ ϋL$L$T$H\$@L$ DL$D\$8݄$ ܄$݄$܄$]݄$܄$݄$܄$\݄$܄$T$݄$D$h\L$\D$`݄$܄$ܤ$F F(\D$`d$HFF\݄$ܤ$݄$܄$FD$ \݄$ ܤ$݄$ܤ$FFT$\D$x܄$݄$d$pF F(L$\D$Pd$@D$XD$8FD$,\݄$ܤ$݄$ܤ$FFT$$\݄$d$x݄$D$pFL$4\݄$ܤ$݄$d$hFFD$(\D$@D$PD$Xd$8F F(T$\݄$ܤ$݄$܄$FL$0\݄$܄$݄$ܤ$F F(D$ \ǃ$,$dŃ0zp$T$X$`9$,i4[^_]à D$zpD$jpD$$ ÐUWVS$$$$+$$Ƌ$9$3$IL$Tݜ$ED$@D$PNj$RT$LDDݜ$xݜ$pݜ$hݜ$`݄$ݜ$Xݜ$Pݜ$H܄$ݜ$@$@D$H$Z׋$IL$D DDݜ$$@D$@׋$I L$< DDݜ$8ݜ$0ݜ$(ݜ$ ݄$ݜ$ݜ$ݜ$ܬ$ݜ$$@D$8D$Tݜ$xT$8DDT$P$t׋L$8L$L$pDDݜ$ݜ$ݜ$ݜ$݄$xݜ$ݜ$ݜ$܄$xݜ$$HD$H׋D$DDDݜ$hD$@׋D$<DDݜ$ݜ$ݜ$ݜ$݄$hݜ$ݜ$ݜ$ܬ$hݜ$D$HNjT$DDDݜ$`D$@NjT$<DDݜ$xݜ$pݜ$hݜ$`݄$`ݜ$Xݜ$Pݜ$Hܬ$`ݜ$@ߋT$Tݜ$XDDT$P\$LDDݜ$8ݜ$0ݜ$(ݜ$ ݄$Xݜ$ݜ$ݜ$܄$Xݜ$D$8D$H$LNjD$8D$Dዔ$LDDݜ$PD$8D$@$HNjT$8T$<$DDDݜ$ݜ$ݜ$ݜ$݄$Pݜ$ݜ$ݜ$ܬ$Pݜ$ϋT$Tݜ$8DDT$PL$LDDݜ$ݜ$ݜ$ݜ$݄$8ݜ$ݜ$ݜ$܄$8ݜ$$@D$4D$Tݜ$0T$4DDD$PT$L$,DDݜ$xݜ$pݜ$hݜ$`݄$0ݜ$Xݜ$Pݜ$H܄$0ݜ$@$X L$H ׋L$D DDݜ$ D$@׋L$< DDݜ$8ݜ$0ݜ$(ݜ$ ݄$ ݜ$ݜ$ݜ$ܬ$ ݜ$$@D$0D$Tݜ$T$0DDD$PT$L$DDݜ$ݜ$ݜ$ݜ$݄$ݜ$ݜ$ݜ$܄$ݜ$$HD$H׋D$DDDݜ$D$@׋D$<DDݜ$ݜ$ݜ$ݜ$݄$ݜ$ݜ$ݜ$ܬ$ݜ$D$4D$H$NjD$4D$Dዔ$DDݜ$D$4D$@$NjD$4D$<ዔ$DDݜ$xݜ$pݜ$hݜ$`݄$ݜ$Xݜ$Pݜ$Hܬ$ݜ$@ߋT$Tݜ$DDT$P\$LDDݜ$8ݜ$0ݜ$(ݜ$ ݄$ݜ$ݜ$ݜ$܄$ݜ$\$0\$HߋD$0D$DDDݜ$T$0T$@׋D$0D$<$DDݜ$ݜ$ݜ$݄$ݜ$ݜ$ݜ$ܬ$ݜ$ϋD$Tݜ$DDݜ$D$PȉD$ L$LDDݜ$ݜ$ݜ$݄$ݜ$݄$ݜ$ܬ$ݜ$܄$ݜ$݄$x܄$x݄$h܄$h]݄$8܄$8D$H݄$(܄$(\݄$8܄$8L$<݄$x܄$xD$P݄$h܄$h\݄$(܄$(\݄$܄$L$L݄$܄$\݄$܄$D$D\݄$܄$݄$‹L$T\݄$܄$݄$܄$D$@݄$܄$\݄$Hܤ$H݄$pܤ$pFPFXL$8\݄$ܤ$݄$ܤ$F0F8\݄$ܤ$݄$ܤ$FPFX鋄$p\݄$ܤ$݄$0ܤ$0FPFX鋔$L\݄$ܤ$݄$ܤ$FPFX鋌$H\݄$ܤ$݄$ܤ$F0F8$\݄$8ܤ$8݄$(ܤ$(F0F8\݄$܄$݄$܄$FF鋔$\݄$܄$݄$܄$FF鋌$,\݄$H܄$H݄$p܄$pFFD$4\݄$xܤ$x݄$hܤ$hF0F8T$0\݄$܄$݄$0܄$0FF鋌$\݄$Hܤ$H݄$pܤ$pFPFX鋄$t\݄$ܤ$݄$0ܤ$0FPFX鋔$D\݄$8ܤ$8݄$(ܤ$(F0F8$ɋ$@ D$,$J\݄$ܤ$݄$F0F8$X\݄$݄$ܤ$FPFX$RT$($@D$T$(\݄$ܤ$݄$ܤ$FPFX\݄$ܤ$݄$ܤ$F0F8T$(\݄$xܤ$x݄$hܤ$hF0F8$@D$$\݄$H܄$H݄$p܄$pFF$BL$$\݄$݄$܄$FFL$(\݄$܄$݄$܄$FF\݄$܄$݄$0܄$0FFD$,\݄$ܤ$zp݄$܄$ݜ$݄$ܤ$݄$݄$F`Fh$@D$ \F F($R T$݄$\܌$݄$`ܤ$X݄$`܄$`ݜ$݄$@ܤ$P݄$X݄$XF`FhL$ \F F(݄$\܌$݄$܄$݄$܄$ݜ$݄$܄$݄$݄$F@FH$@D$$RT$D$\F$HT$݄$܌$\݄$`ܤ$X݄$`܄$`ݜ$݄$@ܤ$P݄$X݄$XF`FhD$ D$$\F F(D$D$$݄$\܌$݄$܄$݄$܄$ݜ$݄$܄$݄$݄$F@FHD$\F݄$܌$\݄$܄$݄$܄$ݜ$݄$܄$݄$݄$F@FHD$D$(\FT$(݄$܌$\݄$ܤ$݄$܄$ݜ$݄$ܤ$݄$݄$F`Fh$XD$ \F F(D$݄$\܌$݄$܄$ ݄$܄$ݜ$݄$܄$݄$݄$F@FHD$D$,\FT$,݄$܌$\݄$X܄$`݄$@܄$@ݜ$݄$@܄$P݄$P݄$PF@FHD$\F݄$܌$\݄$܄$ ݄$܄$ݜ$݄$܄$݄$݄$F@FH$PD$\F݄$܌$\݄$ܤ$݄$܄$\$x݄$ܤ$݄$݄$F`FhD$ D$\F F(D$D$D$x\L$x݄$ܤ$݄$܄$\$p݄$ܤ$݄$݄$F`FhD$ D$(\F F(D$D$(D$p\L$p݄$ ܤ$݄$ ܄$ \$h݄$ܤ$݄$݄$F`FhD$ \F F(T$D$h\L$h݄$ ܤ$݄$ ܄$ \$`݄$ܤ$݄$݄$F`FhD$ D$,\F F(D$D$,D$`\L$`݄$X܄$`݄$@܄$@\$X݄$@܄$P݄$P݄$PF@FHD$D$$\FT$$D$XL$X\݄$܄$݄$݄$݄$܄$݄$݄$F@FHD$\F\$$Ńpzp$$$9$Č[^_]à D$ zpD$,jpD$$; ÐUWVS$$$$$׋$9$$SЋKL$ ݔ$hzp(ݜ$`zpݜ$Eݔ$DDݔ$ݜ$ݜ$$K\$x\$$؋\$ ˉ\$ T$pl$x\$hD\$$D\$ DT$`\$X\$P$[\$DD\$ \$DT$H\$@\$8\$؋\$T$0\$($܄$݄$܄$]D$xD$pD$`\D$HT$ \D$0݄$܄$݄$܄$G\D$(d$@D$8GG\D$hd$XD$PGG\D$hD$XD$PGL$$\D$(D$@D$8G\$ \݄$ܤ$݄$ܤ$GGT$\$$̓ zp\$$$$9$[^_]à D$zpD$kpD$$设 ÐUWVS<$P$T$d$4$X׋$h9$4 $\RT$Ћ$\I L$ዔ$\RT$Ћ$\IL$ zpݜ$(zpzpݜ$ ݜ$ݔ$ zp(ݜ$Eݜ$T$DL$DT$DL$Dݜ$܄$ݜ$ݜ$ܬ$ݜ$zpݜ$ݔ$ zpܬ$ݜ$$`RT$ ݜ$T$T$lЋT$ T$T$hL$ L$L$dȋT$ T$T$`ݜ$zp܌$ݜ$ݜ$ܬ$ݜ$ݜ$ݔ$ zpܬ$ݜ$T$ Dݜ$T$lDL$hDT$dDL$`Dݜ$܄$ݜ$ݜ$ܬ$ݜ$zpݜ$ݔ$ zpܬ$ݜ$x$`RT$ݜ$pT$T$\ЋT$T$T$XL$L$L$TȋT$T$T$Pݜ$hzp܌$hݜ$hݜ$`ܬ$`ݜ$`ݜ$Xݔ$P zpܬ$pݜ$HT$Dݜ$@T$\DL$XDT$TDL$PDݜ$8܄$8ݜ$8ݜ$0ܬ$0ݜ$0zpݜ$(ݔ$  zpܬ$@ݜ$$`QDݜ$L$щL$LDL$щL$HDL$щL$DDL$щL$@Dݜ$܄$ݜ$ݜ$ܬ$ݜ$zpݜ$ zpܬ$ݜ$ݜ$L$LȋL$HL$DȋL$@ݜ$zp܌$ݜ$ݜ$ܬ$ݜ$ݜ$ݔ$ zpܬ$ݜ$$`q ݜ$L$؋L$L$<L$L$8ȋL$L$ݜ$zp܌$ݜ$ݜ$ܬ$ݜ$ݜ$ݔ$ zpܬ$ݜ$DDL$T$XD$DT$<~pD$@ jD$P)D$@\$Pؙ|$X9l$<~JL$`T$D\$L$$RD$hD$`t$H9\$@}T$PL$X$T$L$뮋\$D$?D;l$T|D$T9D$<}(|$<~Tl$X)̓D9L$<\$\|$|$$S8L$PT$8D$XD$"|p|$ L$T$$~HS\$Kd $SD$|C@D$[lVS$\$0t$4S@T$C`D$K\L$SPT$ CLD$zp4$D$SDC@9tT$D$zp4$C@Sd9t;SDtT$D$zp4$t$0D$4)N$[^L\$E}  8EЉ} )EMǍZ9|ыME~{]U<]؉UM+EE‹EԋU܉]~ AJ9|EUME\}9]|؍e[^_]UWVS,EpDPHxLX@.U }M0U D$EE܉~:E}  8E} )؃EǍMZ9|ՋME]U<]؉UM+EE‹EԋU܉]~ AJ9|EUME\}9]|؍e[^_]S\$ KD@D$zpA\$L$‰L$ D$D$$$"[ÃT$ L$$BDD$ zpRPtzpD$D$zp $Ã\$t$|$t$(|$ \$$uS:t1\$t$|$ËCuR у)ȃủ$itW9Su@t s~{Rkpv/SkpD$D$zp$Xszp^@@XDNHHOV HPPLS$X zpXX/S\$D$zp$ @D$$:D$zp$ @$D$[ÐUWVSLt$`\$dnT~`FDl$@|$<1VHD$HNdF\;|$@T$DL$8VPnXD$4Љ+D$<D$0 L$<L$,D$(L$H\$\$ $Q8T$8D$~PT$`FhVXT$PD$dVtFTL$hN\D$XT$X$LL$1҉Fl|$lD$8FDT$lL$4;D$NHV`)Ӊ^d^$ E\$D$FdM +F`yD$d$L$8T$d\$$L$D$4\$\$d$D$l$PUt ndF +n`l$Xl$dU$^ 1Ʌ1|$Xt|$X?1;|$XÅtN4FD$0T$XD$D$$o$$$$$$$$$$$Nj$ ډ$1$$$DŽ$$D;$|胼$$1$$t)$$ȅ҉u$$$$D$t$lt$$\$)胼$D$pD$x$L$lT$$L$T$$$$L$xT$lȋ$T$\$$$#$$$ Ë$‰t$\t$ $t$D$k$$L$x$4D$t$4$T$4T$t$+ދ\$t\$x$$‰));$D$t} $1$9D$x}$T$x$9;\$p$$D$tt$x[؋$t$dDD$x\t$tD$`L$`D\$$L$x닔$$T$$L$pD$XDZ$$$$$:$$$T$lƋ$T$t$$p$D$x$T$l$T$t$$?$9$$$D$$)t$9$~)$$9.t;$|^9D$ 19T$ 8$D$<ș$D$<)9D$@19T$@u9dJ$<+苌$$$$9$t$x$$[^_]4j$$$t$xA\B\ \$|$l$t$D$$\$,H,[|$0t9t$ T$4lD$t4RPpT$D$ D$pD$8T$(u$~79l$ t[,|$ZHt7D$\$t$|$l$ ét‹D$\$t$|$l$ 9qu9suR;Pt {)9u;9yuD$뗋{;yu9|׉t̋L$ ADQHA A@P$Y Ã\$\$$t$\$t$ Nd $<~\$Vh$-~\$$Fl\$t$D$ ~VS$\$0t$4KHL$SDT$C@D$ KpQB D$Pzp4$D$Cdu#Chu4CluEt$0D$4\zp$[^D$D$^zp4$Cht̉D$D$^zp4$Clt4$D$D$^zpt$0D$4\zp$[^S\$Kl $}Sh$}CdD$[}UWVSLT$dB9B t 1҃L[^_]ËZ uj}l$0WwكD$8.~ˉl$$1ۃt$$L$0t$($T$0vP;P  9l$8)9\$8u.tuŋD$(D$4(9ʼnl$,D$ouT$49Qul$(9UuT$9T$,T$(jl$ D$D$49D$ sl$,l$49iaL$8\$Dt$@L$H|$htnT$0:tevt4$StT$HRl$d]K $5t|$HÍEP$t\$$w9nl$h\$dt$HS\$D v[|9|9D$`L$$D$ $hD$d.L$\ $XD$ht$p\$l|$Xt$\$$D$\ËE$hML$t$DUT$T$@ut$MщL$ U \$$T$$D$,$ŋD$`.HD$kp$uU9U iND$,$Q'U$YzpD$JL$$nWU;BVS1ۃt$ D$zp$ XD$4$AvՃ[^Ð,T$0BPD$$JLL$ BHD$JDL$L$L$@B@L$ L$8D$D$uD$4$I tɋFkpu^kp9^ t,kpT$D$tzp$P&ËFtb{LtBOKw s WSGCOKwsW S G$C$؋\$t$|$ÍKL${@44$a׍SHCDK@T$ D$L$V$]FvF$ܜN L$V$T$踸|$(<$D$g1.F D$zp$"D$D$$s Ð,\$ t$$|$(|$0t$<\$@W@D$8L$4\$t$ D$L$$R8GD\$@t$<\$8t$4D$0\$ t$$H8|$(,,\$t$ |$$l$(|$0t$D$4$|$躑t$4$ƅ|$$ CD$|$$.4${ 4$ؓC|$(<$|k t$$l$L$ T$CsKSk؋t$0\$,|$4l$8<Ë\$,t$0|$4l$8<陁T$ ,$T$DʼnD$ <$VT,D$HL$@T$<\$ t$$\$Dt$0|$(D$|$4D$8\$L$T$ |$4$D$4Ét$<$<؋t$$\$ |$(,Ã,\$t$ |$$l$(t$0\$8l$4|$Dtw] @B BT$@|$|$C)ƍtt$P}L$L+} $o?9~B D$zp$vD$D$$kv ÐU1WVSL$0D$~RR|$0 qYV$>NjF$>|$$B؍m\$\$09|9 D$[^_]Í4RT$0D$4|$4\$nD$ \$l$<$^T$ى$s>n؋D$$\>\$,$AD$D$[^_]ÐU1WVS,|$@l$Dw~ÉB 9BuY A9|_ … кu$u(tm|;| Ӄ,[^_]Ã,1[^_]É4$uwD$ D$ [\D$D$( T$$D$ T$L$L$IDD$W$LmD$OQ;Q t9T$f1ۃ\$<$.TO96  $<ŋD$$$1$$$$Ĭ9>u׋N $9Auȋ$$DŽ$D$CT$ D$Ћ$T$D$xD$$D$t$D$pD$ $T$t$D$h$T$lT$T$h$D$dD$T$`$$N $T$SD$ DŽ$D$‹$D$D$lT$\T$T$pT$ D$T$dD$`T$$L$\$F T$ T$\L$$T$L$T$pL$lT$ L$T$dL$`D$T$ $AF $$D$X$D$ $щD$D$x$+$D$D$$D$D$tT$hD$ D$tT$L$h $D$L$X$tC؋$|$ ljT$$D$Aҁ$'d$$$L$bD$T$$ $D$bD$P$$T$$kb$$D$LL$$MbD$Ha<$D$D$D$D$a$T$T$L$T$L$PT$LL$L$HT$ T$DL$T$$D$ $M$,$$L$T$@$aD$<$$,$D$a$T$@D$8L$$paD$4$,$D$Ya`D$0|`$‹D$<ɉD$D$4l$$D$ L$L$8L$L$0L$$D$,$L$<$j$zkpu8kpD$D$Hzp$xr$xLŋJ@lH@$<$D$]]P$EdU\$$UpMTO$E`<$D$r]$Eh$$UDMHUEXT$,$)FL$,D$CL$‹N y$$S*$$L$,$L$T$.*$t$,$t$L$$ *$ptE $S$] V $9BGD$D$D$$H$D$$$$L$ D$H$L$ $D$[$N DŽ$D$ CD$D$D$$$ЉT$|$T$$D$$T$D$  $T$|F L$ $T$L$$$DŽ$D$D$T$ L$D$$$<$D$D$U]mD$Bkp$,$*$<$* ,t$ t$<\$|$$\$8l$(t$D$ vkpl$0|$4$ T$xX@D$,$$Zt$D$ vkp$ D$xX@\$l$0D$4t$ |$$l$(,YÐUWVS|$t$T$\$(l$8L$0~/CD$4ƍꡜzp[^_]à D$zpD$pkpD$$o ÐUWVS\$T$ l$(|$,L$4~tD$EG (zpɋt$0v4$ zpD$$D$8D$D$<D$$zpD$0[^_]à D$@zpD$kpD$$o ÐUWVSt$\$ T$$L$0|$8~}D$,@D$͋A‹l$4m,$ɋD$(AD$<ËD$@D$(zpD$,D$4[^_]à D$zpD$kpD$$=n ÐUWVSL$(T$0l$4|$8t$V@D݇݇ݜ$(ݜ$ V DGpGxV`D݇p݇x܄$(ݜ$(ݜ$ Eܤ$ ݜ$ݜ$ܤ$(ݜ$ݜ$݄$ Eݜ$ݜ$VDGݜ$܄$ݜ$ݜ$VdD݇݇ݜ$܄$ݜ$VDD݇݇V$T$D݇݇L$݄$݄$ݜ$ݜ$݄$ݜ$ݜ$݄$ݜ$ݜ$݄$ܤ$ݜ$ݜ$V|D݇݇ݜ$܄$ݜ$ݜ$V\D݇`݇hݜ$܄$ݜ$V<D݇݇ݜ$܄$ݜ$VDG`Gh݄$܄$݄$ݜ$ݜ$݄$ݜ$ݜ$݄$ܤ$ݜ$ݜ$݄$ܤ$ݜ$xݜ$pVDG0G8ݜ$܄$ݜ$V0D݇݇ݜ$܄$ݜ$VPD݇0݇8VpT$D݇݇ݜ$܄$ݔ$L$݄$܄$ݜ$hݜ$`ݜ$Xݜ$P݄$ݜ$Hݜ$@݄$ܤ$ݜ$8ݜ$0VDGGݜ$܄$ݜ$ݜ$VhD݇݇ݜ$܄$ݜ$VHD݇݇V(T$D݇݇L$݄$݄$ݜ$(ݜ$ ݄$ݜ$ݜ$݄$ݜ$ݜ$݄$ܤ$ݜ$ݜ$VxD݇݇ݜ$܄$ݜ$ݜ$VXD݇P݇Xݜ$܄$ݜ$V8D݇݇ݜ$܄$ݜ$VDGPGX݄$܄$݄$ݜ$ݜ$݄$ݜ$ݜ$݄$ܤ$ݜ$ݜ$݄$ܤ$ݜ$ݜ$VDG@GHݜ$܄$ݜ$ݜ$VTD݇@݇Hݜ$܄$ݔ$݄$ݜ$x݄$ݜ$pVtD݇݇V4$D݇݇ $݄$܄$ݜ$ݜ$݄$ݜ$ݜ$݄$x܄$pzpݜ$zpݜ$݄$xܤ$pzpݜ$xzpݜ$pV DG G(ݜ$h܄$hݜ$hݜ$`NLD݇ ݇(ݔ$X݄$hݜ$P݄$`ݜ$HVlD݇݇^,D݇݇ ݄$h܄$Xݜ$hݜ$`݄$`ݜ$Xݜ$P݄$Pܤ$Hzpݜ$Hzpݜ$@݄$P܄$Hzpݜ$8zpݜ$0݄$(܄$h݄$(܄$݄$܄$݄$P܄$ݜ$@݄$܄$݄$܄$h݄$܄$P݄$܄$V<\V`ˋV\\V ݄$@V@܄$@V|\V\݄$@܄$0 zp݄$܄$ݜ$8݄$Hܤ$8 zp݄$ݜ$0ܬ$ݜ$(݄$ zp݄$ zp݄$ zp݄$ zpݜ$ ݜ$݄$p܄$@݄$܄$0 xzp pzp pzp xzp݄$ܤ$p݄$ܤ$hzpݜ$ `zp܄$ݜ$ `zp hzp݄$ zp݄$ zp݄$ zp݄$ zpݜ$ݜ$݄$܄$p݄$܄$xzp pzpݜ$ pzp xzpݜ$݄$pܤ$@݄$ܤ$0 hzp `zp `zp hzpݜ$݄$ ݄$V0\V ݄$݄$܄$(Vp\ܤ$݄$(ܤ$VlVP\ܤ$ ܄$ʋV\݄$8ܤ$݄$V \Vܤ$݄$܄$0V|V@\݄$݄$0ܤ$V\V`\݄$8܄$݄$V<]݄$(ܤ$h݄$ܤ$ݜ$݄$(ܤ$݄$ܤ$Pݜ$݄$ܤ$݄$ܤ$݄$ܤ$h݄$ܤ$P zp\͋V zp݄$VP܄$Vl\ zp݄$V0݄$V \ zpVp\݄$ ܤ$X݄$`܄$ݜ$݄$ܤ$`ݜ$݄$ ܄$Xݜ$݄$ ܄$݄$ܤ$zpݜ$zpݜ$݄$܄$`݄$܄$X zp zp zp zp݄$ ܤ$݄$܄$zpݜ$zpݜ$݄$ܤ$݄$ܤ$zpݜ$ zp܄$ݜ$ zp zp݄$܄$݄$܄$zp zpݜ$ zp zpݜ$݄$ܤ$X݄$ܤ$` zp zp zp zpݜ$݄$݄$V4\V݄$݄$܄$VHVt\ܤ$݄$ܤ$VhVT\ܤ$܄$V(ʋV\݄$܄$݄$V8V\݄$݄$܄$VxVD\ܤ$݄$ܤ$VXVd\݄$ܤ$݄$V$\V݄$H܄$8 zp݄$܄$\$x݄$0ܤ$@ zp݄$\$pܬ$\$h݄$ zp݄$ zp݄$ zp݄$ zp\$`݄$x܄$8݄$܄$H pzp xzp pzp xzp\$X݄$ܤ$݄$ܤ$xhzp `zp\$P hzp `zp݄$ zp݄$ zp݄$ zp݄$ zp\$H\$@݄$܄$x݄$܄$xzp pzp\$8 xzp pzp\$0݄$ܤ$H݄$xܤ$8 `zp hzp `zp hzp\$(D$`D$PV4V\D$(D$@D$hVtVH\d$PD$hd$@VTVh\d$`D$(V(\VD$xD$HD$8ËV8\VD$Xd$0D$p‹VDЋVx\d$8D$pVdЋVX\D$xd$HD$0D$XV$ЋV\$4$h)Ձzp4$d9$4<[^_]à D$zpD$lpD$$' ÐUWVSd $x $| $ $ $\ +$\ $ Á$ 9$\ 7݃݃ݜ$0ݜ$(E@݃݃⋅݃݃܄$0ݜ$P ݜ$H ܤ$(ݜ$@ ݜ$8 ܤ$0ݜ$0 ݜ$( ݄$(ݜ$ ݜ$ E CpCxݜ$ ݜ$݃p݃xݜ$܄$ݔ$݄$ ݜ$݄$ݜ$݃p݃xE`ݔ$݃p݃x܌$݄$ ܄$ݜ$ ݜ$ ܄$ݜ$ ݜ$ ݄$ܤ$pzpݜ$ pzpݜ$ ݄$܄$pzpݜ$ pzpݜ$ EC0C8⋅݃0݃8ݜ$ݜ$ݜ$EP݃0݃8⋅ݜ$݃0݃8݄$܌$݄$ݜ$ ݄$ݜ$ ݄$hzpݜ$ `zpܬ$ ݜ$ hzp `zpݜ$ ݄$`zp hzpݜ$ `zp hzpݜ$ ݄$݄$ݜ$ ݜ$ ݃݃Ep݃݃ݜ$ݜ$ݜ$E0݃݃⋅ݔ$݃݃܌$݄$ݜ$ ݄$ݜ$ ݄$`zpݜ$ hzp܄$ ݜ$ `zp hzpݜ$x ݄$hzp `zpݜ$p hzp `zpݜ$h ݄$݄$ݜ$` ݜ$X ECCݜ$ݜ$݃݃ݜ$܄$ݔ$ݜ$݄$ݜ$݄$܄$ݜ$EH݃݃ݜ$ݜ$x݃݃ݜ$p܄$pݔ$pݜ$h݄$ݜ$`݄$x܄$hݜ$XE(݃݃⋅݃݃ݜ$Pݜ$Hݜ$@鋅݃݃Ehݜ$8݄݃݃$8܌$8݄$܄$`ݔ$P ݄$Pݔ$H ݜ$@ ݄$܄$Xݔ$8 ݄$Hݔ$0 ݜ$( ݄$ܤ$݄$xܤ$hݜ$ ݜ$ ݄$ܤ$X݄$Pݜ$ ݜ$ ݄$@pzpݜ$ pzpݜ$݄$@pzpݜ$pzpݜ$݄$ܤ$`ܤ$Hݜ$ݜ$݄$ܤ$݄$ܤ$pݜ$ݜ$݃݃ݜ$0ݜ$(Ex݃݃ݜ$ ܄$ ݔ$ ݜ$݄$0ݜ$݄$(܄$ݜ$E8݃݃ݜ$ݜ$݃݃ݜ$܄$ݔ$ݜ$݄$ݜ$݄$܄$ݜ$ECPCX⋅݃P݃Xݜ$ݜ$ݜ$鋅݃P݃XEXݜ$݃P݃X݄$܌$݄$܄$ݔ$݄$ݔ$ݜ$݄$܄$ݔ$݄$ݔ$ݜ$݄$0ܤ$ ݄$ܤ$ݜ$ݜ$݄$ܤ$ܤ$ݜ$ݜ$x݄$pzpݜ$ppzpݜ$h݄$pzpݜ$`pzpݜ$X݄$ܤ$݄$ݜ$Pݜ$H݄$(ܤ$݄$ܤ$ݜ$@ݜ$8݃݃ݜ$ݜ$E|݃݃ݜ$܄$ݔ$ݜ$݄$ݜ$݄$܄$ݜ$E<݃݃ݜ$ݜ$x݃݃ݜ$p܄$pݔ$pݜ$h݄$ݜ$`݄$x܄$hݜ$XEC`Ch⋅݃`݃hݜ$Pݜ$Hݜ$@鋅݃`݃hE\ݜ$8݃`݃h݄$8܌$8݄$܄$`݄$Pݜ$0ݜ$(݄$ܤ$`݄$Hݜ$ ݜ$݄$܄$X݄$Hݜ$ݜ$݄$ܤ$݄$xܤ$hݜ$ݜ$݄$@pzpݜ$pzpݜ$݄$@pzpݜ$pzpݜ$݄$ܤ$X݄$Pݜ$ݜ$݄$ܤ$݄$ܤ$pݜ$ݜ$ECݜ$0ݜ$(݃݃ݜ$ ܄$ ݔ$ ݜ$݄$0ݜ$݄$(܄$ݜ$ED݃݃ݜ$ݜ$݃݃ݜ$܄$ݔ$ݜ$݄$ݜ$݄$܄$ݜ$E$݃݃⋅݃݃ݜ$ݜ$ꋅ݃݃ݜ$܄$ݜ$Edݔ$݃݃܌$݄$݄$݄$܄$T$݄$ݜ$l$ݜ$݄$ܤ$݄$ݜ$ݜ$݄$܄$݄$ݜ$ݜ$݄$(ܤ$݄$ܤ$ݜ$ݜ$xݜ$ppzp܌$pݜ$ppzpݜ$hpzpݜ$`pzpݜ$X݄$ܤ$ܤ$ݜ$Pݜ$H݄$0ܤ$ ݄$ܤ$ݜ$@ݜ$8EC@CH⋅݃@݃Hݜ$ݜ$ݜ$ݜ$E4݃݃⋅݃݃ݜ$ݜ$ݜ$ݜ$xET݃@݃H⋅݃@݃Hݜ$pݜ$hݜ$`鋅݃݃ݜ$Xܬ$Xݜ$XEt݄݃݃$X݄$X݄$܄$p݄$ݜ$0ݜ$(݄$݄$ݜ$ ݜ$܄$݄$܄$hݜ$ݜ$݄$܄$`݄$hzp `zpݜ$ hzp `zpݜ$݄$݄$xhzpݜ$ `zpܬ$ݜ$ `zp hzpݜ$܄$x݄$hzp `zpݜ$ hzp `zpݜ$݄$ܤ$p݄$ܤ$hݜ$ݜ$݄$ܤ$`݄$`zp hzpݜ$ hzp `zpݜ$E C C(⋅݃ ݃(ݜ$Pݜ$Hݜ$@ݜ$8E,݃݃⋅݃݃ݜ$0ݜ$(ݜ$ ݜ$EL݃ ݃(⋅݃ ݃(ݜ$ݜ$ݜ$݃݃ݜ$ܬ$ݜ$El݄݃݃$݄$݄$P܄$݄$0ݜ$ݜ$݄$Pܤ$݄$Hܤ$ݜ$ݜ$݄$(݄$H܄$ݜ$ݜ$݄$@݄$8܄$hzpݜ$ `zpܬ$ݜ$ hzp `zpݜ$x݄$ ݄$`zpݜ$p hzp܄$pݜ$p hzp `zpݜ$h܄$݄$ hzp `zpݜ$` hzp `zpݜ$Xܤ$0݄$(ݜ$Pݜ$H݄$8ܤ$݄$@`zp hzpݜ$@ hzp `zpݜ$8݄$P ܄$ ݄$ ܄$ ݄$܄$݄$܄$ݜ$݄$ ܄$ ݄$ ܄$ ݜ$݄$P ܄$H ݄$܄$ݜ$ݜ$݄$܄$0݄$0܄$ݜ$݄$ܤ$0݄$ܤ$ݜ$ݜ$݄$0ܤ$݄$ܤ$ݜ$݄$܄$$݄$8 ܄$0 $ݜ$$ݜ$݄$݄$E|܄$݄$܄$ዅˋ݄$ܤ$ዅܤ$݄$E@܄$E<݄$݄$ pzpE\E ܤ$ pzp݄$ዅ݄$ܤ$ pzpܤ$ዅƋ܄$݄$܄$ pzpU`֋E݄$0 ܄$ ݄$ ܄$ ݜ$ݜ$݄$ ܤ$x ݄$ ܄$@ ݜ$ݜ$݄$ ܄$ ݄$܄$ Xzp Pzp Pzp Xzp݄$܄$p݄$@܄$` Xzp Pzp Pzp Xzpݜ$ݜ$xݜ$pݜ$h݄$܄$p݄$܄$݄$@܄$`݄$܄$Hzp @zpݜ$`8zp 0zpݜ$X Hzp @zp 8zp 0zp݄$܄$݄$܄$p݄$܄$݄$x܄$h @zp Hzp0zpݜ$P 8zpܬ$Pݜ$P @zp Hzp 0zp 8zp݄$܄$݄$`݄$x܄$ዅܤ$`݄$ܤ$x݄$ܤ$E\E ݄$܄$pE|݄$Pܤ$X݄$h܄$ዅ݄$ܤ$hዅ݄$ܤ$p݄$X܄$PE@E<݄$P ܤ$ ݄$ ܤ$ ݜ$H݄$܄$݄$(܄$ `zp hzp `zp hzpݜ$@݄$ ܤ$ ݄$ ܤ$ ݜ$8ݜ$0݄$@ ܄$( ݄$ܤ$pzpݜ$( pzp݄$ܤ$(݄$ܤ$`zpݜ$  hzp܄$ ݜ$  `zp hzp݄$@ ܤ$( ݄$܄$pzpݜ$pzpݜ$݄$܄$݄$܄$(hzpݜ$ `zpܬ$ݜ$ hzp `zpݜ$݄$(ܤ$݄$ܤ$ hzp `zp hzp `zpݜ$݄$(݄$ ElNjE݄$݄$܄$0ܤ$ ݄$0ܤ$ܤ$(܄$EPʋE,݄$H܄$݄$‹EpE ݄$@ܤ$݄$8Ëܤ$݄$8⋅݄$Hܤ$݄$܄$@ELNjE0݄$H ܄$ ݄$ ܄$X pzpݜ$ݜ$݄$ hzp݄$ `zp݄$x `zp݄$H hzpݜ$ݜ$݄$ ܤ$` pzp݄$ ܄$ ݜ$݄$ hzp݄$ `zp݄$H `zp݄$x hzpݜ$ݜ$݄$܄$P pzp݄$݄$݄$܄$H pzp݄$݄$ (zp zpPzpݜ$ Xzp܄$ݜ$ zp (zp Xzp Pzpݜ$݄$܄$ pzp݄$H܄$Hݜ$݄$܄$  pzp݄$݄$ (zp zpPzp܌$ݜ$ Xzpܬ$ݜ$ zp (zpXzp܌$ Pzpݜ$݄$܄$ċEdNjE݄$ƋƋܤ$Ƌ݄$ܤ$EXƋE$݄$ܤ$݄$܄$EDNjE8݄$ܤ$݄$܄$Ƌ݄$ܤ$݄$ܤ$Ƌ݄$܄$݄$܄$ExƋE݄$H ܤ$ ݄$ ܄$` pzpݜ$ݜ$݄$ `zp݄$ hzp݄$P hzp݄$ `zpݜ$ݜ$x݄$X ܤ$ pzp݄$ ܤ$ ݜ$pݜ$h݄$ `zp݄$ hzp݄$ hzp݄$P `zpݜ$`ݜ$X݄$Pܤ$ pzp݄$݄$݄$ܤ$H pzp݄$ ݄$  zp (zpPzpݜ$P Xzp܄$Pݜ$P zp (zp Pzp Xzpݜ$H݄$ܤ$  pzp݄$P܄$Pݜ$8݄$ܤ$ pzp݄$݄$ (zp zp݄$8 Xzp Pzp (zp zp Xzp݄$8 Pzpݜ$@݄$܄$ƋEhƋE݄$X܄$hƋ݄$hܤ$XƋ݄$ܤ$‹ETNjE(݄$܄$`݄$@܄$HEtNjE݄$P݄$x܄$pƋ݄$Hܤ$@݄$pܤ$xƋ݄$ܤ$`܄$PEHƋE4݄$( ܤ$ ݄$ ܄$h ݜ$0ݜ$(݄$ ܤ$p ݄$8 ܤ$ ݜ$ ݜ$݄$ܤ$݄$ ܤ$ (zp zp (zp zp݄$ܤ$X݄$8ܤ$h zp (zp zp (zpݜ$ݜ$ݜ$ݜ$݄$xܤ$X݄$ܤ$݄$8ܤ$h݄$ܤ$ zp zpݜ$ zp zpݜ$ zp zp zp zp݄$ܤ$݄$Xܤ$8݄$ܤ$݄$@ܤ$` zp zpzpݜ$ zpܬ$ݜ$ zp zp zp zp݄$0܄$݄$‹EhNjE݄$܄$Ƌܤ$݄$ܤ$Ƌ݄$0ܤ$‹ETˋE(݄$(܄$ËEtƋE݄$ܤ$݄$܄$ Ƌ݄$ ܤ$Ƌ݄$(ܤ$݄$܄$EHNjE4݄$( ܄$ ݄$ ܄$p ݜ$ݜ$݄$h ܤ$ ݄$ ܄$8 ݜ$ݜ$݄$ ܄$݄$܄$XzpPzp݄$8܄$h݄$܄$Xݜ$ݜ$ݜ$ݜ$݄$8܄$h݄$܄$݄$x܄$X݄$܄$Hzp@zpݜ$0zpݜ$8zpܬ$ݜ$ Hzpݜ$݄$܄$݄$@܄$`\$x݄$܄$݄$8܄$X\$p HzpD$xݜ$D$p܄$ݜ$ HzpD$xD$p݄$ܤ$݄$ŋEXNjE$ܤ$݄$܄$Ƌ݄$ܤ$Ƌ݄$܄$ËEdƋE݄$܄$݄$‹ExNjE݄$ܤ$݄$܄$Ƌ݄$݄$ܤ$Ƌ݄$ܤ$݄$܄$EDƋE8݄$0 ܤ$ ݄$ ܄$x \$h\$`݄$ ܤ$ ݄$@ ܤ$ \$X\$P݄$ ܤ$ ݄$ܤ$ zp(zp݄$ܤ$p݄$@ܤ$`\$H\$@\$8\$0݄$@ܤ$`݄$ܤ$݄$ܤ$p݄$ܤ$ zp zp zp zp zp zp zp zp\$(݄$ܤ$݄$xܤ$h\$݄$ܤ$݄$pܤ$ zp zpzpL$\$ zpD$ \$ zp zpzpL$ zp\$D$hd$HËEPNjE,D$@D$PƋD$Pd$@ƋD$hD$H‹ElƋED$`D$8D$(D$EpNjE D$ D$0D$XƋD$d$(D$Xd$0ƋD$`d$8D$ ELƋE0ǃ$\ $ )ǁzpl$ 9$\ d [^_]à D$zpD$lpD$$\ ÐUWVS$$$$$i0$ׁ0$9$ V(D݇݇^DG@GHݜ$܄$ݜ$ݜ$V<D݄݇݇$ݜ$ݜ$E݄$ݜ$ݜ$݄$ݜ$ݜ$E݄$ݜ$ݜ$xV DGpGx^HD݇݇ݜ$ݜ$ݜ$ݜ$VDD݇݇^DG`Ghݜ$ݜ$ݜ$ݜ$V4D݇݇^ DG G(ݜ$ݜ$V0D݇݇ݜ$܄$ݜ$ݜ$VDGG݄$݄$ܬ$ܬ$݄$ܤ$ݜ$p݄$ݜ$h݄$p܄$hݜ$`݄$ܤ$ݜ$X݄$ݔ$Pܤ$Xݜ$H݄$܄$ݔ$@܄$ݔ$8ݜ$0݄$܄$ݔ$(܄$ݔ$ ݜ$݄$ݔ$݄$ݔ$ݜ$݄$ݔ$݄$ݔ$ݜ$܄$ݔ$܄$ݔ$ݜ$܄$ݔ$܄$ݔ$ݜ$VDG0G8^8D݇݇ݜ$ݜ$ݜ$ݜ$NDGV,D݇݇ݜ$\$x\$p\$hV$D݇݇^LD݇ ݇(\$`\$X\$PV@D݇݇\$HD$H\$H^DGPGXD$HD$H݄$d$`ݔ$݄$ݔ$݄$d$X$D$x$ݜ$݄$D$Xݔ$D$xݔ$ݜ$݄$D$`ݔ$܄$ݔ$xݜ$p݄$ݔ$hD$pݔ$`ݜ$X݄$d$PD$hݔ$Pݜ$H܄$ݔ$@D$pݔ$8ݜ$0݄$D$Pݔ$(l$hݔ$ ݜ$݄$` zp܄$` zpܬ$݄$X܄$P\$@$D$@ zpzp zpD$@݄$ˋV$\V\V\݄$0ܤ$ zp݄$0܄$T$8 zpܬ$ܤ$P݄$ܤ$ zp zp݄$D$8VV\\ɋ^$݄$pܤ$ zp݄$p܄$ zpܬ$݄$ܤ$݄$@ܤ$8 zp zp݄$V\^ V^ \݄$Xܤ$ zp݄$X܄$T$0 zpܬ$݄$(܄$ ݄$ܤ$ zp zp݄$D$0\ɋV]^ \݄$܄$H zp݄$Hܤ$T$( zp܄$݄$ܤ$݄$pܤ$h zp zpD$(ܤ$V(^HVD\^8V4\݄$Hܤ$ zp݄$H܄$T$ zpܬ$݄$ܤ$݄$@ܤ$8 zp zpD$ ܄$\V(\ɋ^H\V4^D݄$ܤ$0 zp݄$܄$0T$ zpܬ$x݄$ܤ$x݄$(ܤ$  zp zpD$܄$xVL\^@V<\^0V,\݄$܄$ zp݄$ܤ$T$ zp܄$݄$hܤ$`݄$ܤ$ zp zpD$ܤ$V<\ˋ^@\V,^L؃$$)Ձ0zp4$9$6[^_]à D$ zpD$mpD$$ZO ÐUWVS$$$$$|@$Ɓ$9$|Eݜ$pCDF@FHݔ$SPD݆0݆8ݜ$܄$ݔ$ݜ$ݜ$C(D݆݆ݜ$ܬ$ݜ$S<T$8D݆݆L$8݄$݄$ݜ$hzp܌$hݜ$h݄$ݜ$`zp܌$`ݜ$`܄$ݔ$X zp/ݜ$P܄$ݔ$H zpܬ$pݜ$@݄$ܤ$zpݜ$8 zpܬ$8ݜ$8 zp zpݜ$0݄$zp zpݜ$( zp zpݜ$ C DF F(ݜ$܄$ݜ$ݜ$C DFpFxݜ$܄$ݜ$CHD݆݆ݜ$܄$ݜ$C\D݆`݆hݜ$x܄$xݜ$xC4T$0D݆݆L$0݄$ܤ$x݄$ݜ$ݜ$݄$܄$xݔ$܄$ݔ$݄$ݜ$݄$ݜ$ zp zp zp zp zp zp݄$ݜ$ݜ$ݜ$ݜ$݄$ zp݄$ zp݄$ zp݄$ zp݄$ zp݄$ zpܬ$ݜ$ݜ$ݜ$ݜ$CDFݜ$p܄$pݜ$pݜ$hCDFPFXS@D݆݆ݜ$@܄$@ݜ$@CTD݆@݆Hݜ$8܄$8ݜ$8C,T$(D\$ ݆݆D$ L$ L$(ݜ$`݄$@ݜ$X݄$8ݜ$Pݜ$H܄$8܄$@݄$pݜ$݄$h܄$Hݜ$݄$` zp zp zp݄$` zp zp zpܬ$pݜ$ݜ$ݜ$ݜ$݄$P zp݄$X zp݄$X zp݄$P zp zp݄$H zpܬ$hݜ$ݜ$ݜ$ݜ$SDF0F8ݜ$0ݜ$(K$D݆݆ݜ$܄$ݜ$CLD݆ ݆(ݜ$܄$ݜ$C`D݆p݆xݜ$܄$ݜ$C8T$D݆݆L$݄$ܤ$݄$ݜ$ ݜ$݄$܄$ݔ$܄$݄$0ݜ$x݄$(ݜ$pzpݜ$ zpܬ$ݜ$ zp zp zp zpܬ$(݄$ݜ$hݜ$`܄$ݜ$Xݜ$P݄$ zp݄$  zp݄$  zp݄$ zp݄$ zp zpܬ$0ݜ$Hݜ$@ݜ$8ݜ$0CDFFݜ$܄$ݜ$ݜ$CDF`Fhݜ$CDD݆݆ݜ$CXD݆P݆Xݜ$܄$ݜ$C0ݜ$D݆݆݄$܌$݄$ܤ$݄$ݜ$ݜ$݄$܄$ݔ$܄$ݔ$݄$ݜ$(݄$ݜ$  zp zp zp zp zp zp݄$ݜ$ݜ$ݜ$ݜ$݄$ zp݄$ zp݄$ zp݄$ zp݄$ zp݄$ zp݄$ݜ$ݜ$ݜ$݄$ܤ$p݄$ ܤ$ zp zp zp zp܄$X݄$܄$x݄$(܄$ zp zpC(\\C݄$h܄$P݄$(ݜ$܄$(ݜ$݄$`܄$@݄$0ݜ$܄$0ݜ$݄$ zp݄$ zp݄$h zp݄$H zp݄$ zp݄$ zp݄$ zp݄$ zpݜ$xݜ$pzpݜ$h݄$ zpzp݄$݄$X zp݄$8 zpݜ$(݄$ zp zp݄$ xzp݄$ pzpݜ$`݄$( zp܄$(ݜ$Xzp܌$݄$ݔ$ ݄$8 zp݄$X zp\$ zp݄$ zp݄$ xzp݄$ pzpD$ݜ$Pl$zpݜ$Hܤ$ ݜ$@zp܌$݄$ zpݔ$zp܌$Hݜ$݄$h zp܄$ݔ$݄$ zp݄$ zp݄$ zp݄$ zp\$݄$ܤ$ݜ$8D$ݜ$0D$ zp݄$܄$x݄$X܄$C\\݄$0܄$SP\݄$܄$PC݄$8 zp zp zp݄$8 zpݜ$݄$x zpܬ$݄$hܤ$hݜ$]݄$܄$S\݄$ܤ$C(\݄$@ zp zpzp܌$@ zpݔ$݄$X zpܬ$C@SH\ˋC4\ˋST zp݄$p zp zp݄$p zp݄$0 zpܬ$C8S<\ɋCLS`݄$` zp zp zp݄$` zp݄$P zpܬ$݄$H݄$HC \ËS \ʋCS,݄$xܤ$݄$(ܤ$ zp zp zp zp݄$H܄$p݄$܄$p݄$ ܄$ zp zpʋC`\SPʋCL\S<C8\݄$Pܤ$h݄$ ݜ$ܤ$ ݜ$݄$@ܤ$`݄$8ݜ$ܤ$8ݜ$݄$ xzp݄$ pzp݄$P zp݄$0 zp$hzp݄$`zp݄$݄$ zp݄$ zp$ݜ$ݜ$,$zpݜ$ݜ$݄$ zp݄$ zp݄$@ zp݄$` zp݄$ zp݄$ zp݄$݄$ݜ$ zpzp܌$݄$ zpT$hzp܌$`\$`݄$@ zpl$`T$`\$X݄$ zp݄$ zp݄$݄$\$D$XD$ݜ$ݜ$D$Xd$zpݜ$D$`d$hݜ$xzp܌$݄$ pzp\$P݄$0 zp݄$P zpD$P\$H܌$݄$݄$ zp݄$ zpD$Pݜ$D$Hݔ$\$xl$Hzp\$p݄$܄$C ݄$‹SX\܄$CT\݄$܄$S݄$ zpzp݄$݄$\$@zp݄$l$@\$@ zp݄$CDD$@\ʋS0\CXD$@݄$݄$݄$ zpܬ$݄$݄$C\C\݄$D$xD$x݄$݄$ zpܬ$݄$݄$C\C\C NjC,\݄$݄$܌$݄$݄$ zpܬ$D$pD$p‹C4NjC@\CHNjC\ǃ$|$)Łƀzp$9$|EĄ[^_]à D$ zpD$LmpD$$6 ÐUWVS,t$@\$Dl$LD$PD$$|$Hǃ D$T9D$$GGGG\$M$$\$ E\$D$\$U GGD$D$d$D$d$D$˃D$$D$X)à zplD$T9D$$,[^_]à D$zpD$7mpD$$4 ÐUWVS$$$$$@$Ã0$9$CCCKKݜ$ݜ$C(K Cݜ$C ݜ$ݜ$CK ܬ$ݜ$C \$xD$x\$xFD݄$݄$܌$݄$\$pE\$h/\$`E\$XFDC K \$l$\$V DCC\$PD$\$Hl$\$@FDVD݄$݄$܌$݄$\$8\$0\$(NDC \$Cl$\$FDD$x݄$D$x݄$D$\$ l$T$D$pD$8D$PF \D$PD$XʋF\D$`d$(D$hd$0$D$@zpF $\]$$VD$ D$HD$XFʋV\D$pd$8D$Hd$ F\D$`D$(D$0D$hD$d$@\ËV\Fǃ$$)Ń0zp4$9$Ĵ[^_]à D$zpD$9mpD$$0 ÐUWVS4$H$L$T$X$,$Pփ@$\9$,u NFNFNNݜ$ ݜ$ݜ$FN(FN(ݜ$N(FN(N ݜ$FN FN FN ݄$ݜ$݄$ݜ$ݜ$ݜ$܄$ݜ$ܬ$ݜ$N0FN8N8ݜ$FN0ܬ$ݜ$݄$ N(݄$N ݜ$ݜ$݄$ N ݄$N(ݜ$ݜ$F(݄$N ݜ$ݜ$F ݄$N(ݜ$ݜ$W D݄$݄$ݜ$Eݜ$x(ݜ$pEݜ$hWD݄$ \$x݄$D$x\$x݄$ ݄$W0D݄$݄$D$xݜ$`l$xݜ$Xݜ$Pݜ$HWD݄$݄$W(D݄$݄$܌$݄$ݜ$@ݜ$8ݜ$0ݜ$(W8D݄$݄$WD݄$݄$݄$݄$ݜ$ ݜ$ݜ$ݜ$W<DF0\$pF8D$p\$pN0F8\$hO,D݄$݄$݄$݄$_D݄$݄$݄$݄$W DFFNFD$pݔ$ݔ$ݜ$D$hݔ$ݔ$ݜ$D$hݜ$ݜ$D$pݜ$WDFF\$`W4D݄$݄$܌$݄$\$XW$DF F(N F(\$PWD݄$݄$܌$݄$ݔ$ݔ$ݜ$D$`D$Pݔ$D$Xݔ$ݜ$D$Xݜ$D$`d$Pݜ$݄$pܤ$P݄$0܄$ 0zp\$H݄$(ܤ$ 0zp݄$X܄$x\$@݄$ (zp zp݄$ zp (zp\$8 (zp݄$ zp zp݄$ (zpD$Hd$8W0\D$HD$8]W\D$@W<D$@W \W ݄$܄$`݄$@܄$ ݄$8܄$݄$H܄$h݄$܄$݄$܄$\$0݄$܄$\$ ݄$܄$D$ D$ \$(\D$0W0D$0\WD$(W D$(ʋW<\W \݄$p܄$P݄$(܄$ 0zp\$݄$ܤ$0 0zp݄$xܤ$X\$݄$ zp (zp݄$ (zp݄$ zp zp݄$ (zp݄$ (zp݄$ zpW\D$W4D$W(\ˋWD$WW$ɋW8\D$W\݄$ܤ$`݄$ܤ$8\$݄$@ܤ$ ݄$hܤ$H݄$܄$݄$ܤ$ 0zp 0zp݄$ܤ$݄$܄$ 0zp 0zpW\W(̋W4\WD$WW8ɋW$\D$W\$,$`)Ճ@zp<$\9$,4[^_]à D$`zpD$=mpD$$% ÐUWVSt$$$$$l$Ã@$9$lKCKCKKݜ$`ݜ$Xݜ$Pݜ$HC ݜ$Cݜ$Cݜ$Cݜ$CK(CK(ݜ$K(ݜ$CK(ݜ$C0Cݜ$CCݜ$CK8K8ݜ$CK8CK8$݄$ݜ$@ݜ$8݄$$ݜ$0ݜ$(݄$ݜ$ ܬ$ݜ$݄$$$ݜ$ܬ$ݜ$C(K8ݜ$C8ݜ$C(ܬ$ݜ$݄$`݄$HK8ݜ$ݜ$݄$`K8݄$Hݜ$ݜ$݄$X݄$PK8ݜ$ݜ$݄$XK8݄$Pݜ$ݜ$݄$ݔ$݄$ܤ$C8ݜ$݄$K8ݜ$ܬ$ݜ$ܬ$ݔ$݄$܄$ݔ$K8ݜ$K8ݜ$݄$ܤ$ݔ$x݄$܄$ݔ$pݜ$hK8܄$hݜ$h݄$xK8ݜ$`݄$܄$ݔ$X݄$ܤ$ݔ$PK8ݜ$H݄$XK8݄$Pݜ$@݄$`݄$HK(ݔ$8݄$`K(݄$Hݔ$0ݔ$(K8ݜ$ C8ݜ$ܬ$ݜ$݄$8K8݄$0݄$(K8ݜ$݄$X݄$PK(ݜ$ݜ$݄$XK(݄$Pݔ$ݜ$݄$ݜ$K8܄$ݜ$݄$K8݄$ݜ$݄$K8݄$ݜ$݄$ݜ$݄$K8܄$ݜ$F@D݄$ ݜ$x܄$xݜ$x܌$ ݜ$pF D݄$܌$ݜ$hF`D݄$@݄$8܌$@݄$8ݜ$`܄$xݜ$xݜ$pEܤ$pݜ$hݜ$`ܤ$x݄$hܤ$`ݜ$Xݜ$P݄$h܄$`݄$pEݜ$Hݜ$@FDݜ$XC܄$Xݜ$X Cݜ$PFdD݄$ݜ$H݄$܄$Hݜ$H܌$݄$ݜ$@FDD݄$݄$܌$݄$ݜ$8F$DC(C(݄$X݄$Hݜ$8ݜ$0݄$P܄$8݄$@ݜ$(ݜ$ ܬ$Xܤ$@ݜ$ݜ$݄$Pܤ$8ܤ$Hݜ$ݜ$F|D݄$ݜ$0݄$܄$0ݜ$0܌$݄$ݜ$(F\D݄$݄$܌$݄$ݜ$ F<D݄$h݄$`܌$h݄$`ݜ$FD݄$(݄$(݄$0ݜ$ݜ$݄$(܄$݄$ ݜ$ݜ$݄$(ܤ$ݜ$ݜ$݄$0ܤ$ ݜ$ݜ$FD݄$Xݜ$݄$P܄$ݜ$܌$X݄$Pݜ$F0D݄$x݄$p܌$x݄$pݜ$FPD݄$݄$܌$݄$ݜ$FpD݄$݄$ ݄$݄$ ݄$ݜ$ݜ$݄$݄$܄$ݜ$ݜ$݄$݄$ܤ$ݜ$ݜ$݄$ݜ$ݜ$FD݄$`ݜ$݄$H܄$ݜ$܌$`݄$Hݜ$FhD݄$0݄$܌$0݄$ݜ$FHD݄$݄$܌$݄$ݜ$F(D݄$݄$݄$݄$݄$ݜ$xݜ$p݄$܄$݄$ݜ$hݜ$`݄$݄$ݜ$Xݜ$P݄$ܤ$ݜ$Hݜ$@FxD݄$ݜ$݄$(܄$ݜ$܌$݄$(ݜ$FXD݄$݄$܌$݄$ݜ$F8D݄$݄$܌$݄$ݜ$FD݄$X݄$P݄$X݄$P݄$ݜ$8ݜ$0݄$܄$݄$ݜ$(ݜ$ ݄$ܤ$ݜ$ݜ$݄$݄$ݜ$ݜ$FD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$FTD݄$H݄$@܌$H݄$@ݜ$݄$ݜ$݄$ܤ$FtD݄$݄$܌$݄$ݜ$F4D݄$݄$܌$݄$ݔ$݄$݄$ݜ$ݜ$݄$܄$݄$܄$ݜ$ݜ$݄$ݜ$zp܌$ݜ$zpݜ$݄$zpݜ$zpݜ$F DCݜ$C܄$ݜ$KCݜ$xNLD݄$݄$܌$݄$ݔ$p݄$ݜ$h݄$xVlDC8C8F,D݄$8݄$0܌$8݄$0ݔ$`݄$ݜ$ݜ$܄$`݄$x܄$pݜ$ݜ$݄$hݜ$zp܌$ݜ$zpݜ$݄$hzpݜ$zpݜ$݄$x܄$݄$x܄$8݄$`܄$ ݄$܄$Hݜ$X݄$8܄$݄$܄$݄$܄$݄$ ܄$F<\F`ˋF\\F ݄$XF@܄$XF|\F\݄$܄$ zp݄$P܄$Pݜ$P݄$ܤ$ zp݄$hݜ$Hܬ$hݜ$@݄$@ zp݄$P zp݄$ zp݄$ zpݜ$8ݜ$0݄$܄$݄$܄$ zp zp zp zpݜ$(݄$ܤ$݄$ܤ$zpݜ$ zp܄$ ݜ$ ݄$P zp݄$@ zp݄$ zp݄$ zpݜ$ݜ$݄$܄$݄$܄$zpݜ$ zp܄$ݜ$ zp zpݜ$݄$ܤ$݄$ܤ$ݜ$݄$݄$ݜ$݄$8݄$ F0\F ݄$݄$܄$@Fp\ܤ$ ݄$@ܤ$FP\ܤ$8܄$F,ɋF\݄$Pܤ$݄$F \Fܤ$݄$0܄$HF|F@\݄$(ܤ$݄$Hܤ$0F\F`\݄$P܄$݄$܄$(F<]݄$xܤ$݄$ ܤ$`ݜ$݄$xܤ$8݄$Hܤ$ݜ$݄$8ܤ$݄$ ܤ$݄$ܤ$݄$ܤ$ zpF,\͋F zp݄$FP܄$\ zp݄$F0݄$F \ zpFp\݄$pܤ$݄$܄$@ݜ$݄$@ܤ$ݜ$݄$p܄$ݜ$݄$p܄$h݄$0ܤ$(zpݜ$zpݜ$݄$܄$݄$܄$ zp zp zp zp݄$pܤ$h݄$0܄$(zpݜ$zpݜ$݄$(ܤ$݄$0ܤ$zpݜ$ zp܄$ݜ$ zp zp݄$0܄$݄$(܄$zp zpݜ$ zp zpݜ$݄$ܤ$݄$ܤ$ zp zp zp zpݜ$݄$݄$F4\F݄$݄$܄$FHFt\ܤ$݄$ܤ$FhFT\ܤ$܄$F(ʋF\݄$܄$݄$F8F\݄$݄$܄$FxFD\ܤ$݄$ܤ$FXFd\݄$ܤ$݄$F$\F݄$܄$ zp݄$X܄$Xݜ$݄$ܤ$ zp݄$`\$xܬ$`\$p݄$X zp݄$H zp݄$ zp݄$ zp\$h\$`݄$܄$݄$܄$ zp zp zp zp\$X݄$ܤ$݄$ܤ$zp\$Pzpl$P\$Pzp݄$Hzp܌$X݄$ zp܌$\$H\$@݄$܄$\$݄$܄$T$zpD$\$8zpD$8\$8L$D$\$0݄$ܤ$T$݄$ܤ$D$\$(D$hD$P‹F4NjF\D$(D$@D$pFtNjFH\d$PD$pd$@FTNjFh\d$hD$(F(\F݄$D$HD$8‹F8\FD$Xd$0D$`D$xFDNjFx\d$8D$xd$`FdNjFX\݄$d$HD$0D$XF$NjF\$l$)Ń@zp4$9$lt[^_]à D$zpD$GmpD$$ ÐUWVSt$$$$D$l$Ń $9T$l4EEEE$$\$`\$X$\$P\$H\$@S C \$D$\$KD$`\$D$\$L$`\$l$\$CD$PD$XD$PD$XD$\$8D$\$0D$D$T$(\$ D$D$D$HD$8 Pzp Hzp PzpD$8 Hzp @zp XzpD$HD$ D$@ HzpD$0 Pzp PzpD$0 HzpD$ Xzpl$@d$( @zpS σD$l$)ƃ zp$9D$lt[^_]à D$zpD$empD$$ ÐUWVS$$$$$$Ӄ@$9$KCKCKKݜ$ݜ$ݜ$ݜ$CK(CK(ݜ$K(CK(K CK CK CK T$ݜ$݄$ݜ$ݜ$xl$ݜ$pݜ$hܬ$ݜ$`ݜ$X݄$K(݄$K ݜ$Pݜ$H݄$K ݄$K(ݜ$@ݜ$8݄$K ݄$K(ݜ$0݄$K(݄$K ݜ$(ݜ$ ݄$K0݄$K8݄$0K0C8ݜ$݄$K8݄$K0ݜ$݄$K8ݜ$݄$K0ܬ$ݜ$݄$K0݄$K8ݜ$K8CK0ݜ$CK8ݜ$CK0ܬ$ݜ$݄$0K8C0ݜ$K0CK8CK0CK8ݜ$W(D݄$x݄$xwD݄$0ݜ$0܄$0ݜ$0܌$0ݜ$(W<D݄$݄$݄$0ݜ$ݜ$Eܬ$0ݜ$ݜ$݄$(ݜ$ݜ$E݄$(ݜ$ݜ$W D݄$X݄$h݄$X݄$hwHD݄$݄$ݜ$ ݜ$ݜ$ݜ$WDD݄$݄$݄$݄$wD݄$8݄$H܌$8݄$Hݜ$ݜ$ݜ$W4D݄$(݄$ ܌$(݄$ ݜ$w DCCCC݄$ܬ$ݜ$W0D݄$pݜ$݄$܄$ݜ$܌$p݄$ݜ$WD݄$݄$܌$݄$݄$݄$$ܬ$ܬ$݄$ ݜ$݄$ݜ$݄$܄$ݜ$݄$ݜ$x݄$$$ݔ$pܤ$xݜ$h܄$ݔ$`$܄$ݜ$X܄$Xݜ$P܄$ ݔ$H܄$ݔ$@ݜ$8݄$ܤ$ݔ$0݄$ݔ$(ݜ$ ݄$ݔ$ݔ$ݜ$݄$܄$ݔ$܄$ݔ$ݜ$܄$ݔ$ݔ$ݜ$WD݄$݄$݄$݄$w8D݄$݄$݄$݄$ݜ$ݜ$ݜ$ݜ$ODCCW,D݄$@݄$P݄$@݄$Pݜ$ݜ$ݜ$W$DC C(K C(\$pwLDC0C8K0C8D$pl$pݜ$W@D݄$\$h݄$D$h\$h܌$݄$\$`wD݄$݄$`܌$݄$`D$hݔ$D$`ݔ$l$h\$xl$`݄$ݔ$ܤ$ݔ$݄$T$ݜ$܄$ݔ$܄$ݔ$ݜ$܄$ݔ$݄$܄$ݜ$܄$ݜ$݄$ܤ$ݜ$D$xܤ$ݜ$݄$܄$ݜ$x݄$݄$ݔ$pݜ$h݄$܄$ݜ$`D$x܄$ݜ$X݄$`܄$Xݜ$P܄$ݔ$Hܬ$ݔ$@ݜ$8݄$ zp܄$ zpܬ$݄$x܄$pT$XD$ zpzp zpD$X݄$ˋW$\W\W\݄$Pܤ$ zp݄$P܄$T$P zpܬ$ܤ$p݄$ܤ$ zp zp݄$D$PWW\\w$݄$ܤ$8 zp݄$܄$8T$H zpܬ$݄$ܤ$݄$`ܤ$X zp zp݄$D$HW\ɋw Ww \݄$xܤ$  zp݄$x܄$ T$@ zpܬ$݄$H܄$@݄$ܤ$ zp zp݄$D$@\ɋW]w \݄$܄$h zp݄$hܤ$T$8 zp܄$݄$ܤ$݄$ܤ$ zp zpD$8ܤ$W(wHWD\w8W4\݄$hܤ$ zp݄$h܄$T$0 zpܬ$݄$ܤ$݄$`ܤ$X zp zpD$0܄$\W(\ɋwH\W4wD݄$ܤ$P zp݄$܄$PT$( zpܬ$݄$ܤ$݄$Hܤ$@ zp zpD$(܄$WL\w@W<\w0W,\݄$8܄$ zp݄$8ܤ$T$ zp܄$݄$ܤ$݄$0ܤ$( zp zpD$ ܤ$W<\ˋw@\W,wL$$)Ճ@5zp<$9$ļ[^_]à D$zpD$hmpD$$ ÐUWVS$$$$$$Ã@$9$KCKCKKݜ$ݜ$ݜ$ݜ$CK(CK(K(CK(K CK CK CK T$ݜ$ݜ$ݜ$xD$ݜ$pݜ$hݜ$`ݜ$X݄$K ݜ$݄$K(݄$ݜ$P݄$K ݔ$݄$K(݄$K(ݔ$݄$K ݜ$H݄$K(݄$K ܬ$ݜ$@ݜ$8܄$ݜ$0ܬ$ݜ$(݄$K0ݜ$ ݄$K8܄$ ݜ$ ݄$K8݄$K0݄$PK8݄$HK0ݜ$݄$pK8݄$XK0ݜ$CK0CK8ݜ$K0ݜ$CK8܄$ݜ$K8CK0ݜ$݄$pK0݄$XK8ݜ$C K8C(K0ݜ$C K0C(K8CK8ݜ$CK0ܬ$ݜ$݄$`K0݄$hK8ݜ$C0C8ݜ$݄$PK0ݜ$݄$HK8܄$ݜ$݄$xK8C0ݜ$C8C0ݜ$݄$K0ݜ$݄$K8܄$ݜ$݄$K8݄$K0ݜ$݄$xK0C8ݜ$݄$`K8ݜ$݄$hK0ܬ$ݜ$Eݜ$xFDݜ$܄$ݜ$FPD݄$ ܌$ ݔ$݄$ݜ$ݜ$F(D݄$x܌$xݜ$F<D݄$݄$݄$݄$ݜ$pzp܌$pݜ$p݄$ݜ$hzp܌$hݜ$h܄$ݔ$` zp/ݜ$X܄$ݔ$P zpܬ$xݜ$H݄$zp zpݜ$@ zp zpݜ$8ܤ$݄$zp zpݜ$0 zp zpݜ$(F DCݜ$C܄$ݜ$KCݜ$F D݄$`݄$h܌$`݄$hݜ$FHD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$xF\D݄$ݜ$p݄$܄$pݜ$p݄$݄$F4D݄$(݄$8݄$(݄$8݄$p݄$݄$x݄$ݜ$܄$ݔ$܄$xݔ$܄$p܄$ݔ$݄$ݜ$ ݄$ݜ$ zp zp zp zp݄$ܤ$ zp zpܬ$ݜ$ݜ$ݜ$ݜ$݄$ zp zp zp݄$ zp zp݄$ zp݄$ݜ$ݜ$ݜ$ݜ$FDݜ$hC܄$hݜ$h Cݜ$`FD݄$p݄$X܌$p݄$Xݜ$8F@D݄$ݜ$0݄$܄$0ݜ$0܌$݄$ݜ$(FTD݄$݄$܌$݄$ݜ$ F,D݄$@݄$0݄$@݄$0݄$8ܤ$ ݄$(݄$0ݜ$X݄$8܄$ ݔ$P܄$(ݔ$Hݜ$@܄$0݄$hݜ$݄$`܄$@ݜ$ zp zp zp zp zp zp݄$hݜ$ݜ$ݜ$ݜ$݄$X zp zp zp݄$X zp݄$Pܤ$H zp݄$@ zpܬ$`ݜ$ݜ$ݜ$ݜ$VD݄$݄$ݜ$܌$݄$ݜ$N$DC C(K C(ݜ$FLD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$F`DC0C8K0C8ݜ$F8D݄$݄$݄$݄$݄$݄$݄$ܤ$ݜ$݄$܄$ݔ$܄$ݔ$܄$݄$ݜ$݄$ݜ$xzpݜ$ zpܬ$ݜ$ zp zp݄$ܤ$ zp zpܬ$݄$ݜ$pݜ$h܄$ݜ$`ݜ$X݄$ zp zp zp݄$ zp zp zp݄$ݜ$Pݜ$Hݜ$@ݜ$8FD݄$݄$ݜ$܌$݄$ݜ$FD݄$P݄$H܌$P݄$Hݜ$FDD݄$ݜ$݄$܄$ݜ$܌$݄$ݜ$FXD݄$݄$ݜ$݄$݄$F0D݄$݄$݄$݄$݄$݄$݄$݄$ݜ$܄$ݔ$܄$ݔ$܄$܄$ݔ$݄$ݜ$0݄$ݜ$( zp zp zp zp݄$ܤ$ zp zpܬ$ݜ$ ݜ$ݜ$ݜ$݄$ zp zp zp݄$ zp zp݄$ zp݄$ݜ$ݜ$ݜ$ݜ$݄$ܤ$x݄$(ܤ$ zp zp zp zp܄$`݄$܄$݄$0܄$  zp zpF(\\F݄$p܄$X݄$0܄$0ݜ$x݄$h܄$H݄$8ݜ$p܄$8ݜ$h݄$ zp݄$ zp݄$p zp݄$P zp݄$  zp݄$ zp݄$ zp݄$ zpݜ$`ݜ$Xzpݜ$P݄$ xzppzp݄$݄$` zp݄$@ zpݜ$݄$ hzp݄$ `zp݄$ Xzp݄$ Pzpݜ$H݄$ zp܄$ݜ$@xzp܌$݄$ݔ$݄$@ zp݄$` zpݜ$݄$ hzp݄$ `zp݄$ Xzp݄$ Pzp\$݄$D$ݜ$8ݜ$0݄$d$zpݜ$(ܤ$ݜ$ zp܌$݄$ zpݔ$zp܌$P݄$p zpݔ$zp܌$ݜ$݄$ zp܄$ݜ$݄$ zp݄$  zp݄$݄$ܤ$ݜ$ݔ$ܬ$ zp݄$`݄$@܄$pF\\܄$hFP\݄$x܄$8F݄$ zp zp zp݄$ zpݜ$݄$` zp݄$Pܤ$P]݄$F\ܤ$F(\݄$  zp݄$0 zp݄$  zp݄$0 zp݄$@ zpܬ$pF@FH\ˋF4\ɋFT zp݄$X zp zp݄$X zp݄$ zpܬ$hF8F<\ˋFLF`݄$H zp zp zp݄$H zp݄$8 zpܬ$x݄$(݄$(F \ËF \ʋFF,݄$ܤ$݄$0ܤ$  zp zp zp zp݄$P܄$x݄$܄$x݄$(܄$ zp zpʋF`\FPʋFL\F<F8\݄$Xܤ$p݄$(ݜ$ܤ$(ݜ$݄$Hܤ$h݄$@ݜ$ܤ$@ݜ$݄$ Xzp݄$ Pzp݄$X zp݄$8 zp$Hzp݄$@zp݄$݄$ zp݄$ zp$ݜ$ݜ$,$zpݜ$ݜ$݄$ hzp݄$ `zp݄$H zp݄$h zp݄$ zp݄$ zp݄$݄$ݜ$ zphzp܌$݄$ `zpT$Hzp܌$h\$@݄$H zpl$@T$@\$8݄$ zp݄$ zpHzp݄$@zp݄$\$D$8D$ݜ$ݜ$D$8d$\$xzpD$x\$xD$@d$H\$p݄$ Xzp݄$ Pzp\$0݄$8 zp\$(݄$X zpD$(T$(D$0\$ ݄$݄$݄$ zp݄$ zpD$0D$(\$hD$ T$`\$Xl$ \$PF ݄$܄$NjNX݄$\FT܄$\݄$܄$FzpD$pzp݄$D$p\$݄$l$\$ zp݄$FDD$\ɋV0\D$݄$݄$݄$ zpܬ$D$xD$xF\F\D$hD$XD$XD$h݄$ zpܬ$݄$݄$F\F\F NjF,\݄$݄$܌$݄$D$` zpܬ$D$PD$P‹F4NjF@\FHNjF\ǃ$$)Ń@zp4$9$Iļ[^_]à D$zpD$ ympD$$O ÐUWVS|$t$\$L$ l$8T$0~)D$4ƍ[^_]à D$`zpD$XmpD$$ ÐUWVSL$T$l$ |$$t$(\$0~^D$GF zp] zpD$4D$D$8šzpƅ[^_]à D$zpD$̖mpD$$: ÐUWVSt$\$ L$$T$(l$4|$8~D$,@D$zpʋD$0@$ED$<ËD$@¡zpD$,D$0Ņ[^_]à D$ zpD$tmpD$$k ÐUWVSL$0l$4T$8|$fÐUWVS$$$$$$@+$$ǁ$9$Eݜ$ݜ$$@D$Dݜ$ዄ$@D$ݜ$\$DD$ݜ$D$+ݜ$ݜ$݇݇ݜ$ܬ$ݜ$ݜ$G0G8݄$ݜ$܌$GpGx݄$݄$܌$܌$݄$ݜ${pݜ$ݜ$ܬ$ݜ$xG@GHG݄$݄$܌$܌$ݜ$pݜ$hݜ$`ݜ$X$@ D$Dݜ$ݜ$ዄ$PDݜ$ݜ$ݜ$@D$ݜ$Dݜ$GXGP܌$ݜ$Pܬ$Pݜ$POP܌$ݜ$HG(G ݜ$@܄$@ݜ$@ݜ$8ܬ$8ݜ$8݄݇݇$݄$ݜ$݄$܌$GG݄$݄$܌$܌$݄$ݜ$0ݜ$(ݜ$ ܬ$ݜ$G`Gh݄$܌$݄݇݇$܌$ݜ$ݜ$ݜ$݄$܄$݄$P܄$0ݜ$݄$8݄$܄$Xݜ$݄$܄$@݄$܄$p\$x݄$܄$݄$H܄$ ݄${pɋD$ܤ$ˋD$\D$x݄$\D$x܄$݄${p݄$݄$x܄$x\$p݄$X݄$݄$h\$h܄$h\$`݄$8݄$܄$\$X݄$H݄$ ݄$\$P܄$\$H݄$@݄$݄$\$@܄$\$8݄$݄$݄$܄$\$0݄$P݄$0݄$(܄$(\$(݄$܌$p݄$`܄$`\$ D$PD$@D$D$hD$D$\d$@]d$PD$hD$0d$(D$ d$8T$D$\D$pd$HD$Xd$`D$pD$HD$8D$ D$(D$0D$XD$`\$$))Łǰzp$$$9$b[^_]ÃD$ D${pD$`}npD$ $^ÐUWVS,$@$D$H$L$T$X$$$ $$)$ $ $P$\9$$ Qݜ$ݜ$ݜ$ݜ$EpEx݄$܌$݄$ݜ$݄$ݜ$܄$ݜ$ܬ$ݜ$EE݄$܌$݅݅ݜ$ݜ$ݜ$ݜ$QQݜ$ݜ$E8E0ݜ$ܬ$ݜ$M0ݜ$݄݅݅$݄$܌$܌$݄$ݜ$ܬ$ݜ$݄$ݜ$ܬ$ݜ$E@EH݅݅ݜ$ݜ$ݜ$ݜ$QQݜ$ݜ$EEݜ$ܬ$ݜ$Mݜ$݄݅݅$݄$܌$܌$݄$ݜ$݄$ݜ$܄$ݜ$ܬ$ݜ$xE E(݅݅ݜ$pݜ$hݜ$`ݜ$XQQ ݜ$ݜ$݅݅ݜ$ܬ$ݜ$܍ݜ$EPEX݄$݄$܌$܌$݄$ݜ$Pܬ$ݜ$H݄$ݜ$@ܬ$ݜ$8݅݅E`Ehݜ$0ݜ$(ݜ$ ݄$܄$P݄$܄$ݜ$݄$`݄$܄$ݜ$݄$ܤ$݄$p܄$0ݜ$݄$܄$݄$܄$@݄${pܤ$ˋQ݄$ɋQ ݄$܄$ɋQ܄$݄$@ܤ$݄$ܤ$ݜ$݄$ܤ$݄$ܤ$P\$xܤ$`݄$pܤ$0\$p݄$܄$݄$ܤ$\$hD$p{p‹QˋQD$hD$xD$xQd$pQˋQd$h݄$ܤ$Q݄$ܤ$݄$܄$\$`݄$ܤ$݄$܄$\$X݄$xܤ$݄$8܄$H\$P\$H݄$܄$݄$ܤ${p\$@{pl$@\$@\$8݄$܄$x݄$8ܤ$H\$0\$(݄$X܄$ ݄$(ܤ$h\$ ݄$ ܤ$X݄$h܄$(\$D$\$\$݄$ܤ$݄$܄$\$D$D$D$PD$ QD$XD$0QD$Xd$0d$ QɋQd$PɋQD$(D$`D$D$@Q QD$HD$D$8Q d$HD$@d$QD$`d$(D$d$8$$$`))Ёzp $\9$$,[^_]ÃD$ D$@{pD$npD$ $;SÐUWVSd$x$|$$$$\+$\$Ł$9$\$@D$Lݜ$Hݜ$@݅݅ݜ$8ݜ$0ݜ$(ݜ$ EEݜ$ܬ$ݜ$ݜ$$@0D$Hݜ$ݜ$݅݅⋔$R T$Dݜ$ݜ$݄݅݅$܌$݄$݄$8ݜ$Pݜ$H݄$0݄$ݜ$@ݜ$8ܤ$8݄$ݜ$0ݜ$(܄$݄$0ݜ$ ݜ$݄݅݅$܌$݄$(ݜ$݄$ ݜ$܄$ ݜ$ܬ$(ݜ$EpEx݄$H݄$@݄$@܌$H݅p݅x݄$݄$܌$܌$ݜ$ݜ$ݜ$ݜ$$@D$@E0E8ݜ$ܬ$ݜ$ݜ$E@EHݜ$ݜ$$@D$<݅݅ݜ$ܬ$ݜ$ݜ$݅݅ݜ$ݜ$$@(D$8݅0݅8ݜ$ܬ$ݜ$ݜ$݅@݅H⋄$@8D$4ݜ$݅݅܌$܍܌$ݜ$݅݅܍݄$܄$ݜ$݄$܄$ݜ$݄$܄$ݜ$݄$ݜ$݄$݄$ݜ$ݜ$݄$݄$ݜ$ݜ$݄$ܤ$ܤ$ݜ$ݜ$݄$݄$ݜ$ݜ$xܤ$݄$ݜ$pݜ$h݄$ܤ$݄$ܤ$ݜ$`ݜ$X$@D$0EEݜ$ܬ$ݜ$ݜ$E E(ݜ$xݜ$p$@4D$,݅݅ݜ$hܬ$hݜ$hݜ$`݅݅ݜ$Xݜ$P$@$D$(݅݅ݜ$Hܬ$Hݜ$Hݜ$@݅ ݅(ݜ$8ዄ$@D$$ݜ$0݄݅݅$0܌$0݅݅܍݄$܄$Hݔ$P݄$hݔ$Hݜ$@݄$܄$@ݔ$8݄$`ݔ$0ݜ$(݄$x܄$8݄$Xݜ$ ݜ$݄$Pܤ$Xݜ$ݜ$݄$p݄$Pݜ$ݜ$݄$ܤ$@ܤ$hݜ$ݜ$݄$8ܤ$x݄$pݜ$ݜ$݄$ܤ$Hܤ$`ݜ$ݜ$$@qÐUWVS4|$Ht$L\$PL$TD$`D$@T$Xƒ0l$d9l$2l$\E\$(\$ \$\$D$(\$D$(BD$ D$L$L$ BBD$D$L$L$B B(D$D$h))0zpll$\D$d9D$4[^_]ÃD$ D$;{pD$`rqpD$ $oÐUWVS$$$$D$|$P$9T$|sE$C\$pSDD(<{p\$h\$`T$X <{p\$PT$Hl$p׋$\$\$@\$8\$0D$T$(l$@\$ l$T$D$8D$XD$@\$D$`$A $]D$d$D$PD$0D$hD$ A0A8d$`D$(A@AH\D$Pd$0D$ d$hAAD$pD$HD$8d$A A(\փD$|$))É$Pzp$$$9\$|Ą[^_]ÃD$ D$`<{pD$tqpD$ $lÐUWVS$$$$$$+$$Ãp$9$_$@ D$\$Eዄ$Pы@D$ DD$ݜ$ݜ$ݜ$ݜ$\$xl$\$p\$h\$`\$DD$D\$X\$P\$H\$@D$\$8<{pD$8\$8\$0D$T$(\$ ݄$D$XD$PD$`݄$D$8D$xC]D$pd$@D$hd$HCPCX݄$d$0D$ ܄$C`Ch\݄$d$XD$`d$PC0C8݄$d$(D$xd$8C@CH\D$pD$@D$HD$hCC݄$D$0݄$d$ C C(D$ \ƃ$$))ƃpzp$$$9$Ĭ[^_]ÃD$ D$<{pD$vqpD$ $hÐUWVS$$$$$$|$Ɓ$9$|$@D$Dݜ$pݜ$hEዄ$@ D$D$Pݔ$‹@D$Dݜ$ݜ$DD$݄$\$݄$ݔ$ݜ$`={p܌$`ݜ$`D$ݜ$X={p܌$Xݜ$XD$ݔ$P ={pܬ$pݜ$H܄$ݔ$@ ={pܬ$hݜ$8ܬ$ܤ$={p ={pݜ$0 ={p ={pݜ$(݄$={pݜ$  ={p܄$ ݜ$  ={p ={pݜ$D$ݜ$ݜ$D$ݔ$ݜ$D$T$D$ݔ$$ݜ$ݜ$={p܌$ݜ$݄$ܤ$ݜ$={p܌$ݜ$ݔ$ ={pܬ$݄$܄$ݔ$ ={pܬ$ݜ$D$ ={p ={p ={p ={p܄$܄$ ={p ={p ={p ={p݄$p܄$Pݜ$݄$܄$ݜ$݄$݄$ ݜ$ܤ$ ݄$܄$݄$(ݜ$܄$(\$x݄$`܄$8\$p݄$X܄$H\$h\$`݄$Hܤ$X\$X\$Pܤ$݄$\$H܄$\$@݄$ܤ$݄$0\$8ܤ$0\$0݄$8ܤ$`\$(\$ ݄$h܄$@݄$܄$FHF@F݄$D$pL$p܌$݄$݄$݄$]ܤ$F0F8D$h݄$L$h܌$D$\FFD$XD$8L$XL$8F F(D$HD$(L$(L$H\FpFxD$PD$0L$PL$0݆݆T$\FPFXD$`D$xL$`L$xF`FhD$@D$ L$ L$@D$\ǃ$|$))ǁƐzp$$$9$|HĄ[^_]ÃD$ D$@={pD$zqpD$ $]aÐUWVS$$$$$$@+$$ǁ$9$$@D$<\$HD\$@$@D$8$R T$ݜ$={pT$Dݜ$ʋ$P֋@D$4ݜ$D={p݄$ݜ$d$ݜ$d$@ݜ$xݜ$p݄$l$Hݜ$hݜ$`݄$)ݜ$Xݜ$Pܤ$D$@ݜ$Hݜ$@܄$D$H܄$ݜ$8ݜ$0D$\$$D$4\$(D\$ D$8ݜ$DEыD$<ݜ$ݜ$݄$l$ݜ$(ݜ$ ݄$l$(ݔ$ݜ$D$ ݄$ݜ$܄$ݜ$$ݜ$ݜ$$d$ ݜ$D$܄$D$(܄$ݜ$݄$8݄$Hݜ$݄$ܤ$x݄$(ݜ$ݜ$݄$Xܤ$h݄$ܤ$ݜ$݄$8ܬ$HGPGXG݄$݄$܌$܌$݄$ܤ$]G`Gh݄$܌$D$\݄$P܄$`݄$ ܄$ݜ$ݜ$݄$܄$p݄$ܤ$\$x\$p݄$@ܤ$݄$0܄$G G(݄$܄$@݄$0ܤ$݇݇GG݄$D$x܌$L$x\GpGx݄$D$p܌$L$pD$8\݄$X܄$h݄$(܄$\$h݄$Pܤ$`݄$܄$\$`݄$܄$x݄$܄$\$X݄$ܤ$p݄$ ܤ$\$PG0G8G@GHT$4\݇݇D$hD$XL$hL$X݇݇D$PD$`L$`L$PD$<\$$))Łǰzp$$$9$Ĝ[^_]ÃD$ D$={pD$@qpD$ $YÐUWVSt$$$$$$l$l)ʉ$h$Ձ$9 $IL$,ݜ$xݜ$pݜ$hݜ$`$JˋR T$(ݜ$Xݜ$P鋔$RT$ Ӌ$RT$$ݜ$HT$ ֋T$$ݜ$@鋔$RT$ ׋$RT$T$ $T$ݜ$8$$݄$hݜ$`ܬ$hݜ$X݄$p܄$Pݜ$P݄$pܤ$Pݜ$H݄$x܄$XT$ݜ$@l$ݜ$8݄$`ݜ$0ݜ$(݄$`ݜ$ ݜ$݄$H܄$@݄$8ݜ$>{p܌$ݜ$>{pݜ$݄$xܤ$Xݜ$ݜ$݄$Hܤ$@ܤ$8>{pݜ$>{pݜ$T$ ӋT$ݜ$0T$ ֋T$ݜ$(ݜ$ T$$ӋT$ ݜ$T$$֋T$ ݜ$ݜ$T$,ݜ$ݜ$ݜ$T$(ݜ$ݜ$ݜ$݄$0܄$݄$܄$ݜ$ݜ$݄$(݄$ݜ$>{pݜ$>{p݄$܄$ݜ$݄$ݜ$݄$݄$ݜ$ݜ$݄$܄$ݜ$݄$ݜ$܄$(ܤ$ݜ$ܤ$ܤ$ݜ$݄$0ܤ$݄$ ܤ$ݜ$ݜ$݄$ܤ$݄$ܤ$ݜ$ݜ$݄$ ܄$݄$܄$ݜ$݄$@܄$ݜ$݄$ ݜ$݄$`܄$݄$܄$ݜ$ݜ$݄$܄$Hݜ$ݜ$݄$@ܤ$݄$ EpExEE݄$݄$܌$܌$݄$݄$݄$ܤ$݄݅݅$݄$܌$܌$݄$`ܤ$ݜ$ݜ$݄$ܤ$݄$Hܤ$ݜ$\$x݄$8܄$݄$܄$E0E8݄$8ܤ$݄$ܤ$݅݅E@EH݄$݄$܌$܌$T$ ݄݅݅$D$xL$x܌$L$݄$܄$ >{p݄$ܬ$\$p݄$܄$ >{p݄$0ܬ$0\$h݄$X܄$݄$ܤ$\$`݄$܄$݄$Pܤ$\$XEEE E(D$`D$XL$XL$`T$ ݅݅D$pD$hL$pL$h݅݅L$$݄$ܤ$ >{p݄$ܬ$\$P݄$ܤ$ >{p݄$(ܬ$(\$H݄$Xܤ$݄$ܤ$\$@݄$܄$P݄$܄$\$8EPEXE`EhT$(݅݅D$PD$HL$PL$H݅݅D$@D$8L$8L$@L$,ȃ$l$))Ё zp$$$9$lt[^_]ÃD$ D$@>{pD$؉qpD$ $ENÐUWVS$$$$$$+$$Ł$9$y$@{pD$ݜ$l$ݜ$݄$܄$T$݄$p >{pݜ$D$ݜ$݄$܄$ܤ$p >{pݜ$xݜ$p >{p݄$ܤ$ݜ$hݜ$`݄$ܤ$ݜ$Xݜ$Pܤ$x݄$ܤ$ݜ$Hݜ$@݄$܄$ݜ$8ݜ$0D$TT$LыD$Pݜ$hݜ$`ݜ$XD$TӋT$Pݜ$Pݜ$Hݜ$@ݜ$8D$HT$Dݜ$ݜ$D$@ƋT$<݄$ݜ$0ݜ$(ܬ$ݜ$ ݄$ݜ$ܤ$݄$h܄$0ݜ$(݄$8ݜ$ ݄$`ܤ$P݄$ >{pݜ$ݜ$݄$(݄$Hܤ$ >{pݜ$ >{p܄$ݜ$ >{p >{pݜ$ >{p݄$Xܤ$@ݜ$ݜ$܄$(݄$ ܄$H>{pݜ$ >{p܄$ݜ$ >{p >{pݜ$݄$X܄$@݄$ >{pݜ$ݜ$݄$hܤ$0݄$8ݜ$ݜ$ >{p݄$`܄$Pݜ$ݜ$$@D$8$R8T$4$@$D$0$RT$,ݜ$ݜ$ݜ$ݜ$D$8ËT$4D$0ËT$,ݜ$ݜ$ݜ$$Pы@(D$(ݜ$鋄$@D$$Ƌ$@4D$ݜ$D$$NjD$݄$ݜ$ݜ$ܤ$݄$ݜ$ݜ$ܤ$݄$܄$ݜ$ݜ$݄$܄$݄$ܤ$ >{pݜ$ݜ$݄$ܤ$݄$>{pݜ$ >{pܬ$ݜ$ >{p >{pݜ$ >{p݄$ܤ$ݜ$xݜ$p݄$܄$܄$>{pݜ$h >{pܬ$hݜ$h >{p >{pݜ$`݄$܄$݄$܄$ >{pݜ$Xݜ$P݄$ܤ$ݜ$Hݜ$@݄$ܤ$ >{pݜ$8ݜ$0D$$D$ݜ$D$$ËD$D$(ݜ$ݜ$ݜ$ݜ$xݜ$p݄$ݜ$h݄$ܤ$ݜ$`D$8ƋT$4ݜ$(ݜ$XD$,T$0ݜ$Pݜ$H݄$(ݜ$@܄$(݄$Xܤ$Hݜ$8݄$Pݜ$0݄$܄$܄$Pݜ$(ݜ$  >{p݄$p >{p >{p >{pݜ$ݜ$݄$p >{p >{p >{p >{pݜ$ݜ$݄$ >{p݄$x >{p >{p݄$@ >{pݜ$ݜ$݄$x >{p݄$ >{p >{p݄$@ >{pݜ$݄$`ܤ$h݄$0܄$8>{pݜ$>{pݜ$݄$`܄$h݄$8ܤ$0>{pݜ$>{pݜ$܄$݄$X܄$Hݜ$݄$܄$(݄$܄$(ݜ$ ݄$܄$ ݄$8ݜ$ݜ$݄$ܤ$(ܬ$8ݜ$ݜ$݄$ܤ$(݄$ ܤ$ݜ$ݜ$݄$h݄$xܤ$ݜ$>{p݄$x>{p݄$݄$݄$ݜ$݄$ݜ$ݜ$܄$ݜ$݄$x܄$ܬ$h\$݄$݄$x݄$݄$D$ݜ$ݜ$D$ݜ$EE݄$܌$݄$ܤ$݅p݅x݄$݄$܌$܌$݄݅݅$݄$܌$܌$D$D݄݅݅$ ݄$܌$ ܌$݄݅݅$݄$܌$܌$T$PEpEx݄$݄$܌$܌$݄݅݅$݄$܌$܌$D$@݄$P܄$݄$܄$ݜ$ݜ$݄$܄$݄$܄$@ݜ$݄$ܤ$݄$@ܤ$ݜ$ݜ$݄$Pܤ$݄$ܤ$ݜ$ݜ$x݄$ܤ$݄$ܤ$݄$P݄$0݄$݄$ݜ$pݜ$hݜ$`ݜ$X݄$܄$݄$܄$ݜ$@݄$0݄$P݄$݄$݄$@ݜ$Pܬ$@ݜ$HEPEX݄$܌$E`Eh݄$p܌$pD$H݄݅݅$x݄$܌$x܌$݄݅݅$h܌$hT$T݅P݅X݄$݄$܌$܌$݅`݅h݄$P݄$`܌$`܌$PD$<݄݅݅$݄$܌$܌$݄݅݅$X݄$H܌$H܌$XT$L݄$܄$݄$H܄$ >{pݜ$8ݜ$0݄$@܄$ >{p݄$ ܄$0ݜ$(݄$Hܤ$ >{p݄$0ܤ$ ݜ$ ݜ$݄$ܤ$݄$ܤ$@ >{pݜ$ݜ$݄$܄$`݄$pܤ$>{p݄$p>{p݄$݄$݄$ݜ$ݜ$ݜ$ݜ$݄$p܄$݄$`ܤ$ݜ$݄$݄$p݄$݄$ݜ$݄$ݜ$ݜ$܄$ݜ$E0E8݄$8܌$8E@EH݄$݄$܌$܌$D$$݄݅݅$݄$܌$܌$݄݅݅$݄$܌$܌$T$4݅0݅8݄$0݄$(܌$0܌$(݅@݅H݄$݄$܌$܌$D$(݄݅݅$݄$ ܌$܌$ ݄݅݅$݄$܌$܌$T$,݄$X܄$݄$h܄$ݜ$ݜ$݄$`܄$݄$܄$Hݜ$݄$hܤ$݄$Hܤ$ݜ$ݜ$݄$Xܤ$݄$ܤ$`ݜ$ݜ$݄$܄$݄$ܤ$݄$X݄$8݄$݄$ݜ$\$x\$p\$h݄$܄$݄$ܤ$݄$8݄$X݄$݄$\$`\$XEE݄$܌$E E(݄$܌$䋔$B݄݅݅$݄$܌$܌$݅݅D$xL$xB4݄݅݅$݄$܌$܌$݅ ݅(D$`D$pL$pL$`B$݄݅݅$݄$܌$܌$݅݅D$hD$XL$XL$hBǃ$$))ǁzp$$9$ļ[^_]ÃD$ D$>{pD$XqpD$ $13ÐUWVSl$$$$$$$di0$`$0$9$d5Q$ݜ$(QӋQQ֋Q݄$(ݜ$Xݜ$Pݜ$Hݜ$@ݜ$8ܬ$(ݜ$0ݜ$(ݜ$ ӋQݜ$XQ֋QQ$݄$Xݜ$ ݜ$ݜ$ݜ$ݜ$ܬ$Xݜ$ݜ$Q׋Qݜ$Pݜ$HQЋQ׋QQЋQ݄$Pݜ$ݜ$݄$Hݜ$ݜ$܄$Hݜ$ܬ$Pݜ$ݜ$ݜ$Q ׋Qݜ$@ݜ$8Q ЋQQӋQ Q֋Q ݄$@ݜ$ݜ$݄$8ݜ$ݜ$ܬ$8ݜ$ܬ$@ݜ$ݜ$xݜ$pӋQQ ֋Qݜ$0Q׋Q ݜ$(QЋQ \$݄$(݄$0ݜ$hݜ$`܄$0ܤ$(D$D$݄$ܤ$ݜ$݄$ܤ$ݜ$݄$ݜ$݄$ݜ$݄$ݜ$݄$h܄$ݜ$݄$܄$ݜ$݄$pݜ$݄$ݜ$݄$`ܤ$ݜ$݄$ܤ$ݜ$݄$ܤ$ݜ$݄$ ܤ$ݜ$݄$ܤ$xݜ$݄$ݜ$݄$ݜ$݄$܄$T$܄$ݜ$l$0?{pݜ$݄$ ܄$T$܄$ݜ$l$ݜ$݄$܄$\$݄$`܄$D$ݜ$xl$ݜ$p܄$p܄$ݜ$h݄$܄$܄$ݜ$`ݜ$X݄$ܤ$݄$hܤ$ݜ$Pݜ$H݄$܄$x܄$ݜ$@ݜ$8݄$܄$܄$ݜ$0݄$X܄$ݜ$ ݄$h܄$ ݜ$݄$@݄$X܄$8E@EHݜ$܄$ݜ$݄$ (?{p ?{p݄$݄$݄$ (?{p݄$h 8?{p݄$ ݜ$ݜ$ݜ$ݜ$݄$݄$ (?{p݄$ (?{p݄$݄$X 8?{pܬ$8݄$`ܤ$`ݜ$ݜ$ݜ$݄$݄$ (?{p݄$ (?{p݄$ 8?{pܬ$@݄$0ܤ$0$ݜ$ݜ$,$ݜ$݄$ (?{p݄$݄$݄$ (?{p݄$ 8?{pܬ$X݄$$܄$ݜ$ݜ$,$ݜ$ݜ$EE݄$܌$݄$ ݄$݄$ ܤ$E0E8݄$݄$܌$܌$݄$Q܄$EpEx݄$݄$܌$܌$݄݅݅$܌$Q݄݅݅$݄$܌$܌$݄݅݅$݄$܌$܌$Q݄݅݅$݄$܌$܌$݄݅݅$݄$܌$܌$Q ݄$0܄$݄$@܄$(݄݅݅$P܄$P݄$x܄$H݅݅ݜ$܄$ݜ$݄$ (?{p݄$݄$݄$ (?{p݄$ 8?{pܬ$0݄$T$܄$ݜ$ݜ$ݜ$D$\$x݄$ (?{p݄$݄$݄$ (?{p݄$x 8?{pܬ$H݄$pT$܄$p\$p\$hl$\$`\$X݄$ (?{p݄$݄$݄$ (?{p݄$P 8?{pܬ$P݄$HT$܄$H\$P\$HD$\$@\$8݄$ (?{p݄$݄$݄$ (?{p݄$@ 8?{pܬ$(݄$8܄$8\$0\$(\$ ݅݅D$8D$XL$XL$8Q݄݅݅$D$(܌$L$(݄$Q܄$EE݄$D$0܌$L$0E E(D$PD$pL$pL$PQEPEX݄$D$ ܌$L$ E`EhD$@D$`L$`L$@Q ݅݅D$xL$x݅ ݅(D$HD$hL$hL$HQ$Ѓ$d$))Ё0zp $9$dl[^_]ÃD$ D$`?{pD$lqpD$ $Z#ÐUWVS4|$Ht$L\$PL$TD$`D$@T$Xƒ0l$d9l$2l$\E\$(\$ \$\$D$(\$D$(BD$ D$L$L$ BBD$D$L$L$B B(D$D$h))0zpll$\D$d9D$4[^_]ÃD$ D$?{pD$DqpD$ $!ÐUWVS$$$$$$+$$Ãp$9$_$@ D$\$Eዄ$Pы@D$ DD$ݜ$ݜ$ݜ$ݜ$\$xl$\$p\$h\$`\$DD$D\$X\$P\$H\$@D$\$8@{pD$8\$8\$0D$T$(\$ ݄$D$XD$PD$`݄$D$8D$xC]D$pd$@D$hd$HCPCX݄$d$0D$ ܄$C`Ch\݄$d$XD$`d$PC0C8݄$d$(D$xd$8C@CH\D$pD$@D$HD$hCC݄$D$0݄$d$ C C(D$ \ƃ$$))ƃpzp$$$9$Ĭ[^_]ÃD$ D$ @{pD$qpD$ $ÐUWVSt$$$$$$l$l)ʉ$h$Ձ$9 $IL$,ݜ$xݜ$pݜ$hݜ$`$JˋR T$(ݜ$Xݜ$P鋔$RT$ Ӌ$RT$$ݜ$HT$ ֋T$$ݜ$@鋔$RT$ ׋$RT$T$ $T$ݜ$8$$݄$hݜ$`ܬ$hݜ$X݄$p܄$Pݜ$P݄$pܤ$Pݜ$H݄$x܄$XT$ݜ$@l$ݜ$8݄$`ݜ$0ݜ$(݄$`ݜ$ ݜ$݄$H܄$@݄$8ݜ$p@{p܌$ݜ$p@{pݜ$݄$xܤ$Xݜ$ݜ$݄$Hܤ$@ܤ$8p@{pݜ$p@{pݜ$T$ ӋT$ݜ$0T$ ֋T$ݜ$(ݜ$ T$$ӋT$ ݜ$T$$֋T$ ݜ$ݜ$T$,ݜ$ݜ$ݜ$T$(ݜ$ݜ$ݜ$݄$0܄$݄$܄$ݜ$ݜ$݄$(݄$ݜ$h@{pݜ$`@{p݄$܄$ݜ$݄$ݜ$݄$݄$ݜ$ݜ$݄$܄$ݜ$݄$ݜ$܄$(ܤ$ݜ$ܤ$ܤ$ݜ$݄$0ܤ$݄$ ܤ$ݜ$ݜ$݄$ܤ$݄$ܤ$ݜ$ݜ$݄$ ܄$݄$܄$ݜ$݄$@܄$ݜ$݄$ ݜ$݄$`܄$݄$܄$ݜ$ݜ$݄$܄$Hݜ$ݜ$݄$@ܤ$݄$ EpExEE݄$݄$܌$܌$݄$݄$݄$ܤ$݄݅݅$݄$܌$܌$݄$`ܤ$ݜ$ݜ$݄$ܤ$݄$Hܤ$ݜ$\$x݄$8܄$݄$܄$E0E8݄$8ܤ$݄$ܤ$݅݅E@EH݄$݄$܌$܌$T$ ݄݅݅$D$xL$x܌$L$݄$܄$ p@{p݄$ܬ$\$p݄$܄$ p@{p݄$0ܬ$0\$h݄$X܄$݄$ܤ$\$`݄$܄$݄$Pܤ$\$XEEE E(D$`D$XL$XL$`T$ ݅݅D$pD$hL$pL$h݅݅L$$݄$ܤ$ p@{p݄$ܬ$\$P݄$ܤ$ p@{p݄$(ܬ$(\$H݄$Xܤ$݄$ܤ$\$@݄$܄$P݄$܄$\$8EPEXE`EhT$(݅݅D$PD$HL$PL$H݅݅D$@D$8L$8L$@L$,ȃ$l$))Ё zp$$$9$lt[^_]ÃD$ D$@{pD$qpD$ $=ÐUWVS$$$$$$+$$Ł$9$y$@D$D$$> ÐUWVSL\$`t$d|$h\$HKDkH\$Hl$8t$DkLsP|$@{TL$<KXt$,T|$(L$$$T$4eD$0T$,9T$0D-\$4hD$\$T$ 1ۋT$4|$T$HL$LD$DT$L$ D$O $k2T$LT$G$3OQ D$,D$4T$D$$c3D$(G3L$,T$(L$ D$T$\$$2T4$D$@D$<.$D$x#rpD$O{p$`JL\$8D$@wXLT$FPT$hD$Tl$l$T)$H%^L$T$BËT$D$JJABAÃ\$t$|$~jD$D$=rp$L$ ÉHD$ D$<$R $D$ $Et8D$D$=rp$Tp\$<$P $t\$t$|$ËL$D$QD$T$I\$t$|$t$ |$$D$D$>rp$ is{\$$R \$ t$\$|$ D$T$D$ D$ J$L$ à D$T$H$L$D$} U(M@ D$$ËT$D$ioKL$ T$$D$L$T$D$$0?rpÃT$$L$(D$T$L$D$$S?rpLT$ à 'KT$ à L$$kgQ|p D$ DT$D$IUWVS,|$D\$Pl$@|$$\$t$LT$$L$Tl$(t$ L$|$Hl$X$1ɉڋ)ʃD9|]L$l$ \$T$|$$l$t$D$T$ $TL$(t$@,[^_]L$4T$0D$D$, T$(D$L$ T$L$$$_QT$ ÃD$8L$4T$T$0L$,T$ D$L$D$$L$(T$$RQT$ ÃT$Dt$H$趿|$`L[^_]馿UWVS\|$t$$|$TD$p\$,T$D$T$TD$X\$8$$$D$@[l$x$L$Lt$H$$l$P|$|$p\[^_].UHM u]u]PAD$L$ B+B t$$D$S8]u]US4]MPED$E D$ B+B \$ $؉D$Q8]UWVS,\$Pl$D|$@\$ ]t$LL$TT$X|$(t$$L$|$HT$$1ɉڋ)ʃD9|]1 ȨtJl$L$ T$$E|$L$ T$t$$D$Rl$(E<$t$@,[^_]<<$苼1҉؋|$)ЋD9|ϋ]넃L$4T$0D$D$, T$(D$L$ T$L$$$PT$ ÃT$&t$pD$D$lt$$2ƒ,[^_]ËD$D랋D$D댐uGN;L$,>u=E,t;D$4>u/E0t;D$8>u!E4t;D$@>uE8t;D$D>u\$ t$|$l$Ã\$ t$|$l$\$$l$ t$,I1  uzD$H umD$4ufD$8u_D$@uXD$DuQS;T$(>uGN;L$0>u=E,t;D$4>u/E0t;D$8>u!E4t;D$@>uE8t;D$D>u\$ t$|$l$Ã\$ t$|$l$\$(l$ t$0e1 u| utulD$H u_D$4uXD$DuQS;T$$>uGN;L$,>u=E,t;D$4>u/E0t;D$8>u!E4t;D$@>uE8t;D$D>u\$ t$|$l$Ð\$ t$|$l$\$$l$ t$,蕣1 u| utulD$H u_D$4uXD$DuQS;T$(>uGN;L$0>u=E,t;D$4>u/E0t;D$8>u!E4t;D$@>uE8t;D$D>u\$ t$|$l$Ð\$ t$|$l$\$$t$(|$,l$0D$蹢D$H     u{D$41Ƀ|$@te|$8>u]D$DuVD$<uO\$ C,t;D$4>u=t$ F0t>u,|$ G4t;D$@>ul$ E8t;D$D>uD$D$\$ t$|$l$Ð\$ t$|$l$|$ \$(l$,虡1t^ uYuTD$D uGu?D$0u8D$@u1S;T$$>u'G0t9>uG4t;D$0>u G8t;D$@t\$ t$|$l$þ㐐\$ t$|$l$|$ \$$l$,1t^ uYuTD$D uGu?D$0u8D$@u1S;T$(>u'G0t9>uG4t;D$0>u G8t;D$@t\$ t$|$l$þ㐐\$ t$|$l$\$ l$$t$,I1t D$D uu C0t9t\$ t$|$l$ËC4u*C8t;D$@u֍U;T$(u uŃu;D$0u΃\$ t$|$l$\$ l$$t$,谟1t[D$D uNuFD$@u?C0uNC4t;D$0>u*C8t;D$@>uU;T$(>u u u\$ t$|$l$9u묃\$ t$|$l$\$ l$(t$,1t D$D uu C0t9t\$ t$|$l$ËC4u*C8t;D$@u֍U;T$$u uŃu;D$0u΃\$ t$|$l$\$ l$(t$,v1t[D$D uNuFD$@u?C0uNC4t;D$0>u*C8t;D$@>uU;T$$>u u u\$ t$|$l$9u묃\$ t$|$l$t$ |$$\$,՝1tD$D uu F0t9t\$ t$|$l$ËF4u9F8t;D$@u֍W;T$(u uŃuL$4@;D$0u뿃\$ t$|$l$t$ |$(\$,01tD$D uu F0t9t\$ t$|$l$ËF4u9F8t;D$@u֍W;T$$u uŃuL$4@;D$0u뿐\$ t$|$l$\$$l$ t$(艜1txD$D uk ufua uYuTD$,1Ƀ|$@t>D$4u7D$8u0D$<u)E0t;D$,>uE4t;D$0>u E8t;D$@t\$ t$|$l$ÿUWVS|$$t$(l$4L$T$\$,~Af( Gf(Ff(f\f)fXf) D$0 ꡜzpƅ[^_]à D$ S{pD$ܽrpD$$  ÐUWVSt$$\$(l$4f(-`S{pf(%pS{pL$T$|$,f( Ff(Ff(f(fXf\f(fYf(f(@R{pfWff(fXf)f(fYf\ȋCf(f\f)‹CfXf) ƒD$0 ꡜzpÅn[^_]à D$S{pD$hrpD$$ ÐUWVSt$$\$(l$4L$T$|$,f(Ff(f(f\fXЋFf(F f($f(f\f( @R{pfWffX܋Cf(f\f)f(fXf)C fXf),‹Cf\f)ƒD$0 ꡜzpÅf[^_]à D$T{pD$XrpD$$2 ÐUWVSl$$$f(@T{pf)D$Pf(PT{pf)D$@f(`T{pf)D$0f(pT{pf)D$ $$$2f()Ff(4Ff(f(fXFf($F f( f(fXf(f\f)$f(D$ fY$f)D$f\fXf\f(fXf)f(D$@fYf(L$0fYfXf(@R{pf(fWff(D$0fYf(L$@fYf\fWff(D$PfYf\f(L$fXf\l$Cf(f\f)‹C f(f\f)‹CfXf)‹CfXf)ƒ$ ꡜzpÅl[^_]à D$T{pD$@rpD$$b ÐUWVSf()F(f(F]f(f(f(fff(fYf(%@R{pf(fWffYf\M f(f(O f(fff(fYf(fWffYf\f)\$ Uf(f(O0f(fff(fYf(fWffYf\Ef(f(Of(fff(fYf(fWffYf\f(f\f)D$f(f\D$ f)$fXfX\$ f(fXf(fXf)f(D$PfY$f(L$@fYL$fXf(fWff(D$@fY$f(L$PfYL$f\fWff\f(L$`fYf(D$pfYf\f(fXf\f(f\f)f(f\f)fXf)fXf) D$<$4ƃ@zpl$9D$< Č[^_]à D$ {pD$ upD$$) ÐUWVS|f(`{pf)D$`f( p{pf)L$P$$D$L$ŋ$9T$LBf(?$X f(f(M f(fff(fYf(-@R{pf(fWffYf\f(f\f)D$0fXp4f(f(M0f(fff(fYf(fWffYf\Pf(f(Mf(fff(fYf(fWffYf\f(f\f)L$ fXH f(f(Mf(fff(fYf(fWffYf\@ljD$ f(f(M@f(fff(fYf(fWffYf\f(f\fXf(D$ f\f(L$PfYf(fWffX\$ f(D$`fYf(L$0f\f(D$0fXf)f(fXf)f\f)f(f\f(L$PfYfWffXf(D$`fYf(f\fXf)?f(fXf)f\f) D$L$<ǃPzp$$$9D$L|[^_]à D${pD$upD$$& ÐUWVS$f({pf)$f( {pf)$f({pf)$f( {pf)$f( {pf)D$pf( 0{pf)L$`$$D$\@$Nj$9T$\f(}N LL$Xf(f(O f(fff(fYf(-@R{pf(fWffYf\ًNLf(f(O0f(fff(fYf(fWffYf(f\f(fXf)D$@f\f)T$0FDD$,f(f(f(fff(fYf(fWffYf\ً^\f(f(OPf(fff(fYf(fWffYf\f(fXf)D$f\VTf(f(Of(fff(fYf(fWffYf\ًFDf(f(O@f(fff(fYf(fWffYf\f(fXf) $f\f(fXD$@f(L$fXf(f(fXf)Mf(D$pfYD$0f($fYf\f(L$`fYfXf(fWff($fYD$f(f\f(f($fYL$@f\f($fY $fXf(f\f) fX‹L$Xf)f(D$pfYf(L$`fYf\f($fYL$0f\f(fWff($fYD$f(f\f(f($fY $f\f($fYL$@fXf(f\f)fXf)f(D$`fYD$0f(L$pfYfXf($fYfXfWff($fY$f\f($fYD$@f\f($fYD$fXf(f\f)fXD$,f)8D$\$l`zp4$9L$\f[^_]à D${pD$upD$$Y" ÐUWVS$f({pf)$$$D$|+D$|$Nj$9D$|f(mFDD$xf(f(O0f(fff(fYf(%@R{pf(fWffYf\f(f\f)D$`fXf)l$PFDD$Lf(f(Of(fff(fYf(fWffYf\^\f(f(OPf(fff(fYf(fWffYf\f(f\f)D$0fXFDD$,f(f(f(fff(fYf(fWffYf\NLf(f(O@f(fff(fYf(fWffYf\f(f\f)D$fXVTf(f(O`f(fff(fYf(fWffYf\ًF DD$ f((f(O f(fff(fYf(fWffYf\f(f\fXf(D$PfXf(fXf(f\ʋD$xf)fXf)Ef(T$Pf\f\f(fWff(f\f) fXЋD$Lf)f(D$fXf($fYf(\$`fXf(t$`f\f\l$f($fYf(f\D$0f(fWff(D$0fXfWff(f\f)f(fXċD$ f)fXًD$,f)f(f\f)D$|$lpzp4$9D$|Ĝ[^_]à D$ {pD$upD$$ ÐUWVS$f(`{pf)$f( p{pf)$f({pf)$f({pf)$f({pf)$pf( {pf)$`f({pf)$Pf(Ќ{pf)$@f({pf)$0f( {pf)$ f({pf)$f({pf)$f( {pf)$f( 0{pf)$$$$$Nj$9$f(Ef)$F D$f(f(O f(fff(fYf(-@R{pf(fWffYf\^\f(f(OPf(fff(fYf(fWffYf\f(fXf)$f\f($fYf)$FD$f(f(f(fff(fYf(fWffYf(f\FD$f(f(O`f(fff(fYf(fWffYf\FD$f(f(O0f(fff(fYf(fWffYf\f(f\f)D$pfXf(fXf($fYf\f)t$`VTf(f(Of(fff(fYf(fWffYf\F DD$ f(f(Opf(fff(fYf(fWffYf\NLf(f(O@f(fff(fYf(fWffYf\f(f\f)L$PfXf(fXf($fYf\f(f\f($fYf(f(fWff($fX$fXf($fYf(f\f(fXf)Ef(fX‹$f)f\f) f($fYD$Pf($0fYL$`f\f($ fYL$pf\f($fYf\f\$f(fWff($@fYd$pf($PfYD$`f\f($ fYL$Pf($0fYf\f)L$@f(fXf)D$0f($pfY|$pf($`fYD$`fXf($fY\$Pf($fYfXf(fXf)L$ f($fY$f($f\f)L$f($fYD$pf\f(f($fYf\f($fYL$Pf\f($fYL$`fXf(f\ʋ$f)fXf)f(T$fXT$ f($fXD$0fWff(f\ȋD$ f)fX‹$f)f($fYD$ f(T$f\f\d$@f($fYfXf\f($fYf($fYL$0f\f($fXfWff(f\f)f(fXŋ$f)$$lzp4$9$q[^_]à D${pD$upD$$ ÐUWVSl$f({pf)$Pf(Ѝ{pf)$@f({pf)$0f({pf)$ $$$$Nj$9$nf(eFD$f(f(O@f(fff(fYf(=@R{pf(fWffYf\f(f\f)$fXf)$FD$f(f(O0f(fff(fYf(fWffYf(f\FD$f(f(f(fff(fYf(fWffYf\V$T$f(f(f(fff(fYf(fWffYf\ًFD$f(f(OPf(fff(fYf(fWffYf(f\f(f\f)$f(f\f)$f($fX$f)$fXf)$fXf)$f(fXf)$^\f(f(Of(fff(fYf(fWffYf\f)\$pV Tf(f(O f(fff(fYf(fWffYf\f)\$`FDD$ f(f(O`f(fff(fYf(fWffYf\N Lf(f(Opf(fff(fYf(fWffYf\f(\$pf\f(f\L$`f(fXf(T$pfXf)T$PfXt$`fXf)T$@f(f\$f($ fYfX$f($0fYf($f\f)T$0f\f($f\$f)D$ f($PfYD$ f($@fYfXf(fWff($@fYD$ f($PfYf\fWff($fX̋$f)f(\$0f\f(f\f) fXËT$ f)fXl$0f(f\‹$f)fXՋ$f)f(D$@f\$f($ fYf(D$@fX$f)D$f($0fYD$f($f\f($f\$f(D$Pf\f(f($@fYf($PfYf\f(fWff($PfYf($@fYfXfWff($fXD$f)Ef(fXf(fXȋ$f)f\Nj$f)f\f(fXf)f\f)$$lǐzp4$9$l[^_]à D$@{pD$upD$$ ÐUWVSt$ |$(l$,T$L$$\$9}hf(Ff( f( f(fff(fYf(@R{pfWffYf\f(f\f)fXf)zp49|[^_]à D${pD$upD$$ ÐUWVSt$]f(f(f(fff(fYf(%@R{pf(fWffYf\M f(f(O f(fff(fYf(fWffYf\f)\$ Uf(f(O0f(fff(fYf(fWffYf\Ef(f(Of(fff(fYf(fWffYf\f(f\f)D$f(f\D$ f)$fXfX\$ f(fXf(fXf)f(D$PfY$f(L$@fYL$fXf(fWff(D$@fY$f(L$PfYL$f\fWff\f(L$`fYf(D$pfYf\f(fXf\f(f\f)f(f\f)fXf)fXf) D$<$4ƃ@zpl$9D$< Č[^_]à D$ {pD$upD$$ ÐUWVS|f(`{pf)D$`f( p{pf)L$P$$D$L$ŋ$9T$LBf(?$X f(f(M f(fff(fYf(-@R{pf(fWffYf\f(f\f)D$0fXp4f(f(M0f(fff(fYf(fWffYf\Pf(f(Mf(fff(fYf(fWffYf\f(f\f)L$ fXH f(f(Mf(fff(fYf(fWffYf\@ljD$ f(f(M@f(fff(fYf(fWffYf\f(f\fXf(D$ f\f(L$PfYf(fWffX\$ f(D$`fYf(L$0f\f(D$0fXf)f(fXf)f\f)f(f\f(L$PfYfWffXf(D$`fYf(f\fXf)?f(fXf)f\f) D$L$<ǃPzp$$$9D$L|[^_]à D${pD$upD$$ ÐUWVS$f({pf)$f( {pf)$f({pf)$f( {pf)$f( {pf)D$pf( 0{pf)L$`$$D$\@$Nj$9T$\f(}N LL$Xf(f(O f(fff(fYf(-@R{pf(fWffYf\ًNLf(f(O0f(fff(fYf(fWffYf(f\f(fXf)D$@f\f)T$0FDD$,f(f(f(fff(fYf(fWffYf\ً^\f(f(OPf(fff(fYf(fWffYf\f(fXf)D$f\VTf(f(Of(fff(fYf(fWffYf\ًFDf(f(O@f(fff(fYf(fWffYf\f(fXf) $f\f(fXD$@f(L$fXf(f(fXf)Mf(D$pfYD$0f($fYf\f(L$`fYfXf(fWff($fYD$f(f\f(f($fYL$@f\f($fY $fXf(f\f) fX‹L$Xf)f(D$pfYf(L$`fYf\f($fYL$0f\f(fWff($fYD$f(f\f(f($fY $f\f($fYL$@fXf(f\f)fXf)f(D$`fYD$0f(L$pfYfXf($fYfXfWff($fY$f\f($fYD$@f\f($fYD$fXf(f\f)fXD$,f)8D$\$l`zp4$9L$\f[^_]à D${pD$|upD$$] ÐUWVS$f({pf)$$$D$|+D$|$Nj$9D$|f(mFDD$xf(f(O0f(fff(fYf(%@R{pf(fWffYf\f(f\f)D$`fXf)l$PFDD$Lf(f(Of(fff(fYf(fWffYf\^\f(f(OPf(fff(fYf(fWffYf\f(f\f)D$0fXFDD$,f(f(f(fff(fYf(fWffYf\NLf(f(O@f(fff(fYf(fWffYf\f(f\f)D$fXVTf(f(O`f(fff(fYf(fWffYf\ًF DD$ f((f(O f(fff(fYf(fWffYf\f(f\fXf(D$PfXf(fXf(f\ʋD$xf)fXf)Ef(T$Pf\f\f(fWff(f\f) fXЋD$Lf)f(D$fXf($fYf(\$`fXf(t$`f\f\l$f($fYf(f\D$0f(fWff(D$0fXfWff(f\f)f(fXċD$ f)fXًD$,f)f(f\f)D$|$lpzp4$9D$|Ĝ[^_]à D$ {pD$upD$$ ÐUWVS$f(`{pf)$f( p{pf)$f({pf)$f({pf)$f({pf)$pf( {pf)$`f({pf)$Pf(В{pf)$@f({pf)$0f( {pf)$ f({pf)$f({pf)$f( {pf)$f( 0{pf)$$$$$Nj$9$f(Ef)$F D$f(f(O f(fff(fYf(-@R{pf(fWffYf\^\f(f(OPf(fff(fYf(fWffYf\f(fXf)$f\f($fYf)$FD$f(f(f(fff(fYf(fWffYf(f\FD$f(f(O`f(fff(fYf(fWffYf\FD$f(f(O0f(fff(fYf(fWffYf\f(f\f)D$pfXf(fXf($fYf\f)t$`VTf(f(Of(fff(fYf(fWffYf\F DD$ f(f(Opf(fff(fYf(fWffYf\NLf(f(O@f(fff(fYf(fWffYf\f(f\f)L$PfXf(fXf($fYf\f(f\f($fYf(f(fWff($fX$fXf($fYf(f\f(fXf)Ef(fX‹$f)f\f) f($fYD$Pf($0fYL$`f\f($ fYL$pf\f($fYf\f\$f(fWff($@fYd$pf($PfYD$`f\f($ fYL$Pf($0fYf\f)L$@f(fXf)D$0f($pfY|$pf($`fYD$`fXf($fY\$Pf($fYfXf(fXf)L$ f($fY$f($f\f)L$f($fYD$pf\f(f($fYf\f($fYL$Pf\f($fYL$`fXf(f\ʋ$f)fXf)f(T$fXT$ f($fXD$0fWff(f\ȋD$ f)fX‹$f)f($fYD$ f(T$f\f\d$@f($fYfXf\f($fYf($fYL$0f\f($fXfWff(f\f)f(fXŋ$f)$$lzp4$9$q[^_]à D${pD$upD$$ ÐUWVSl$f({pf)$Pf(Г{pf)$@f({pf)$0f({pf)$ $$$$Nj$9$nf(eFD$f(f(O@f(fff(fYf(=@R{pf(fWffYf\f(f\f)$fXf)$FD$f(f(O0f(fff(fYf(fWffYf(f\FD$f(f(f(fff(fYf(fWffYf\V$T$f(f(f(fff(fYf(fWffYf\ًFD$f(f(OPf(fff(fYf(fWffYf(f\f(f\f)$f(f\f)$f($fX$f)$fXf)$fXf)$f(fXf)$^\f(f(Of(fff(fYf(fWffYf\f)\$pV Tf(f(O f(fff(fYf(fWffYf\f)\$`FDD$ f(f(O`f(fff(fYf(fWffYf\N Lf(f(Opf(fff(fYf(fWffYf\f(\$pf\f(f\L$`f(fXf(T$pfXf)T$PfXt$`fXf)T$@f(f\$f($ fYfX$f($0fYf($f\f)T$0f\f($f\$f)D$ f($PfYD$ f($@fYfXf(fWff($@fYD$ f($PfYf\fWff($fX̋$f)f(\$0f\f(f\f) fXËT$ f)fXl$0f(f\‹$f)fXՋ$f)f(D$@f\$f($ fYf(D$@fX$f)D$f($0fYD$f($f\f($f\$f(D$Pf\f(f($@fYf($PfYf\f(fWff($PfYf($@fYfXfWff($fXD$f)Ef(fXf(fXȋ$f)f\Nj$f)f\f(fXf)f\f)$$lǐzp4$9$l[^_]à D$@{pD$|upD$$ ÐUWVSL$lf({pf)$0f( {pf)$ $`$p$@+$$hNj$t9$F D$f(f(Opf(fff(fYf(5@R{pf(fWffYf\ًFD$f(f(O0f(fff(fYf(fWffYf(f\f(f\f)$fXf)$f($ fYf(Mf\f)$F$D$f(f(f(fff(fYf(fWffYf\f)$FD$f(f(O@f(fff(fYf(fWffYf\ًFD$f(f(f(fff(fYf(fWffYf(f\f(f\f)$fXf)$f($ fYf($f\f)$FDD$|f(f(OPf(fff(fYf(fWffYf\f)\$`VTT$\f(f(Of(fff(fYf(fWffYf\ً^(\f(f(f(fff(fYf(fWffYf\f(f\f)D$@fXf($ fYf(L$`f\f)L$0F DD$ f(f(O f(fff(fYf(fWffYf\N,Lf(f(f(fff(fYf(fWffYf\VTf(f(O`f(fff(fYf(fWffYf\f(f\f)D$ fXf($ fYf(f\f)L$f(MfX$f(D$`fXf(f\f(fXfXf($fX$f(f\f(fWffXf(f\$f)f(fXf)EfXًD$ f)f(f\ċD$|f)f($fX\$0f(D$fX$f(f\fXf(l$ fX$f($fXL$@f(f\f($0fYf(f(fWffXf($0fYf(fWff(f\f)f(fX$f)fXD$\f) f\ً$f)f($f\L$0f(\$ f\$f($0fYf(f\f(fXf($f\L$@f($0fYf(f(\$f\$fXfWff\fWff(f\ȋ$f)f(f\f) fXf)fX$f)2$$xlǰzp4$t9$L[^_]à D${pD$upD$$ ÐUWVS$f( {pf)$f( 0{pf)$f(@{pf)$pf(%P{pf)$`f(`{pf)$Pf( p{pf)$@f({pf)$0f(%{pf)$ f({pf)$f( {pf)$$$$+$$Ƌ$9$0 f(/E(f(f(f(fff(fYf(=@R{pf(fWffYf\Ef(f(N@f(fff(fYf(fWffYf\f(f\f)$fXf(fXf)$f($fYf\f)$E lj$f(f(N f(fff(fYf(fWffYf\f)$]f(f(NPf(fff(fYf(fWffYf\f)$pM$ f(f(f(fff(fYf(fWffYf\f)$`U0f(f(f(fff(fYf(fWffYf\f)$PE f(f(Npf(fff(fYf(fWffYf\ыE4f(f(f(fff(fYf(fWffYf(f\f(fXf)$@f\f)$0E,f(f(f(fff(fYf(fWffYf\ыEf(f(f(fff(fYf(fWffYf(f\f(fXf)$ f\f)$E8f(f(f(fff(fYf(fWffYf\ыEf($f(N0f(fff(fYf(fWffYf\f(fXf)$f\ڋEf(f(Nf(fff(fYf(fWffYf\Ef(,f(N`f(fff(fYf(fWffYf\f(fXf\f($f\f)$f($0f\f)$f($fX$@f($PfXf)$f(fXf($0fXf)$f($fXf)$fXf)$f($fY$@f($f\f)$f($fYf($Pf\f)$fXf)$f($pfX$ f($`fX$f(fXf($fY$ f($pf\f)d$pf($fY$f($`f\f)d$`f(D$pfXf)$f(f\f($fYf)d$PfXf($ fYf($f\f\f\$f($0fYf($@fYf\f(fWff($@fYf($0fYfXfWff($fXf)f(\$PfXf(f\f) fXf)f\d$Pf(f\‹$f)fXf)f($PfY$f($`fY$f\f)L$@f($`fY$f($PfY$fXf)L$0f($fX$f($pfYfWff($f\$f($fYf($pfY$f($fY$f\f(f\f)T$ fXf(T$pf\T$`f($f\$f($0fYf($@fYf\f)L$f($@fYf(f($0fYfXf)$f($f\$f($fYf($fX$f($ fYf($f\f(f(f\f($fXfXEf(f\f)NjE(f(fXf)f(f\T$@f(D$f\D$ f(@R{pfWfE f(f\f) NjEfXf)f(f\T$0f($fXfWfE,f(f\f) NjEfXf)fXd$0f\4$f(fWfE8f(f\f) NjEfXf)$fXl$@f(D$fXD$ fWfE4f(f\f)NjEfXf),ǃ$$<ǁzpl$9$Ĭ[^_]à D$ {pD$8upD$$ UWVS|$f(`{pf)$`f( p{pf)$Pf({pf)$@$$$<+$<$Ƌ$9$<f(eG D$f(f(Npf(fff(fYf(5@R{pf(fWffYf\f(f\f)$ fXf)$GD$f(f(N0f(fff(fYf(fWffYf(f\G0f(\f(f(fff(fYf(fWffYf\f(f\f)$fXf)$G8DD$|f(f(f(fff(fYf(fWffYf\_(\f(f(f(fff(fYf(fWffYf\OLf(f(NPf(fff(fYf(fWffYf\WTf(f(Nf(fff(fYf(fWffYf\f(fXf)D$`f(fXf)L$Pf\f\f(f\f($@fYf)$fXf($@fYf)$G_f(fYf(f(fWffYf\O f( f(ff)$ff(fY$f)D$@f(fWffYf(D$@f\f)D$0Wf( f(fff(fYf(fWffYf\ӋGf(f(fff(fYf(fWffYf\f(f\f)D$ f(f\l$0fXfX\$0f(fXf)D$f(fXD$f)f(D$pfYf(L$`fYL$ fXf(fWff(D$`fYf(L$pfYL$ f\fWff\f($fYf($fYD$f\f(fXf\f(f\f)f(f\f)fXf)fXf) D$\$4ƃ zp<$9D$\Ĭ[^_]à D$@{pD$vpD$$ ÐUWVS $,f({pf)$f( {pf)$f({pf)$f({pf)$$ $0$@$($$49$$f(8f(pf(ff)$ff(fYf( @R{pf)$f(fWff(fYf(f\fXf(h f(ff)$pff)$`f(fYf($fWff($`fYf\f)$Pf(ff)$@ff(fY$@f(fYf\f(fY$f(fYf\f)$0f(ff)$ ff)$f(fYf($fYf\GD$ f( f(fff(fYf($fWffYf\f(Uf\f)$f(EfXf)$GD$f(f(fY$@fW$ffYf\f)$GD$f(f(fY$fW$ffYf\ߋ_$\f( f(fff(fYf($fWffYf\ՋGD$f(f(fff(fYf($fWffYf(f\f($f\f)$f(f\f)$f($fX$f)$f($fXf)D$pfXf)L$`fXf)D$Pwtf(f(fY$pfW$ff($`fYf\W Tf(f(fY$ fW$ff($fYf\GDD$ f(f($Pff($Pff(fYf($fWffYf\ՋO Lf( f($0ff($0ff(fYf($fWffYf\f(f\f(f\f(fXfXfXf(fXf)D$@f(f\$f($fYfX$f($fYf($f\f)T$0f\f($f\$f)D$ f($fYD$ f($fYfXf($fWff($fYD$ f($fYf\fW$ff($fX̋$ f)f(\$0f\f(f\f) fXËT$ f)fXt$0f(f\‹$f)fXf)f(D$@f\D$Pf($fYf(D$@fXD$Pf)D$f($fYD$f($f\f(t$pf\t$`f\f($fYf($fYf\f($fWff($fYf($fYfXfW$f(ff($fXD$f)Ef(fXf(fXȋ$f)f\ŋ$f)f\f(fXf)f\f)$$8l$0zp<$49$z [^_]à D${pD$dvpD$$ ÐUWVS$ f( {pf)$f( 0{pf)$f(@{pf)$f(P{pf)$$$$$$$9$3$f( f)$pf(@f)D$f(ff)$ff(fYf(5@R{pfWff(fYf(fXf\f)$`f(h f)$Pf(ff)$ff)$f(fYf)$f(fWffYf) $f($f\f)$f(fY$f)$f(fYfXf($fX $f)$f(ff)$pff(fY$pf)$`f(fYf) $f($`f\ $f)$Pf(L$ff)$@f(L$ff)$0fY$@fYf(f(f\f)$@f($f\f)$0fXf)$ f($`fX$f)$f(H0f)$f($ff)$ f($ff)$f(fYf(fWff($fYf\f(fY$pfYf\f)$f(fY$@f($0fYf\f)$f(fY$fYf\f)$fY$f($fYf\f(eG]f(f(f(fff(fYf(%@R{pf(fWffYfXM f(f(O f(fff(fYf(fWffYfXf)\$ Uf(f(O0f(fff(fYf(fWffYfXEf(f(Of(fff(fYf(fWffYfXf(f\f)D$f(f\D$ f)$fXfXT$ f(fXf(fXf)f(D$PfY$f(L$@fYL$fXf(fWff(D$PfYD$f(L$@fY $f\fWff\f(T$`fYf(D$pfYf\f(fXf\f(fXf)f(f\f)f\f) fXf) D$<$4ƃ@zpl$9D$< Č[^_]à D$@{pD$,8wpD$$~ ÐUWVSl$f({pf)D$Pf( {pf)L$@$$D$<$ŋ$9T$<.f(?^ f(f(M f(fff(fYf(-@R{pf(fWffYfXf(f\f)D$ fXFljD$f(f(M0f(fff(fYf(fWffYfXVf(f(Mf(fff(fYf(fWffYfXf(f\f)$fXN f(f(Mf(fff(fYf(fWffYfXFf(f(M@f(fff(fYf(fWffYfXf(f\fXf(f\$f(L$@fYf(fWffX$f(D$PfYf(L$ f\f(fXf)f(D$ fXf)f\f)f(f\f(L$@fYfWffXf(D$PfYf(f\f(f\f)fXf)?fXD$f)(D$<$<׃Pzp4$9D$<l[^_]à D${pD$:wpD$$Lj ÐUWVS$f({pf)$f( {pf)$f( {pf)$f( 0{pf)L$pf(@{pf)D$`f( P{pf)L$P$$D$L@$Nj$9T$Lf(}^\f(f(Of(fff(fYf(%@R{pf(fWffYf(fXNLf(f(O@f(fff(fYf(fWffYfXf(f\f)D$0fXf)l$ FDD$f(f(f(fff(fYf(fWffYfXVTT$f(f(OPf(fff(fYf(fWffYfXf(f\f)$fXV Tf(f(O f(fff(fYf(fWffYfXFDf(f(O0f(fff(fYf(fWffYfXf(f\fXf(D$ fXf(fXf(f(fXf)Mf(D$PfY$f(L$pfYL$0f\f(L$`fYf\f(fWff($fYf(f\f(f($fYL$ f\f($fYfXf(fXf) f\f)f(D$PfYf(L$`fYL$0f\f(L$pfY $fXf(fWff($fYf(f\f(f($fYf\f($fYL$ fXf(fXf) f\f)f(D$pfYf(L$PfYL$0fXf(L$`fY $fXfWff($fYD$ f\f($fYf\f($fYfXf(fXNjD$f)f\T$f):D$L$l`zp4$9T$L}ļ[^_]à D${pD$=wpD$$s ÐUWVS$f({pf)D$p$$D$l+D$l$Nj$9L$lf(}FDD$hf(f(O0f(fff(fYf(%@R{pf(fWffYfXf(f\f)D$PfXFDD$Lf(f(Of(fff(fYf(fWffYf(fXNLf(f(OPf(fff(fYf(fWffYfXf(f\f)D$0fXf)l$ FDD$f(f(f(fff(fYf(fWffYfX^\f(f(O@f(fff(fYf(fWffYfXf(f\f)$fXVTf(f(O`f(fff(fYf(fWffYfXًF Df(0f(O f(fff(fYf(fWffYfXf(f\fXf(f\T$ f(f\fWff(f\f) fXЋL$Lf)fX|$ fXf(f\ŋL$hf)fXf)}f($f\f(L$pfYf(f\D$0f(fWff(D$0fXfWff($fXf(L$pfYf(f(L$Pf\f(l$PfXf(fXf)f(f\f)f\f) fXD$f) D$l$lpzp4$9D$lČ[^_]à D$@{pD$AwpD$$ ÐUWVS$f({pf)$f( {pf)$f({pf)$f( {pf)$f({pf)$pf( н{pf)$`f({pf)$Pf( {pf)$@f({pf)$0f( {pf)$ f( {pf)$f( 0{pf)$f(@{pf)$f( P{pf)$$$$$Nj$9$f(Ef)$F D$f(f(O f(fff(fYf(5@R{pf(fWffYfXً^\f(#f(OPf(fff(fYf(fWffYfXf(fXf)$f\f($fYf)$FD$f(f(f(fff(fYf(fWffYfXFD$f(f(O`f(fff(fYf(fWffYfXFD$f(f(O0f(fff(fYf(fWffYfXf(f\f)D$pfXf($fYf(f\f)L$`fXVTf(f(Of(fff(fYf(fWffYfXF DD$ f(f(Opf(fff(fYf(fWffYfXNLf(f(O@f(fff(fYf(fWffYfXf(f\f)D$PfXf($fYf(f\f)L$@fXf(f\f($fYf(fWff($fX$fXf($fYf(f\f(fX$f)fXf)Uf\f) f($ fYD$@f($0fYL$pf\f($fYL$PfXf($fYL$`fXf\$f(fWff($PfY|$`f($@fYD$pfXf($fYl$@f($0fYD$PfXf(fXf)D$0f($`fY\$`f($pfYD$pf\f($fYd$@f($fYD$Pf\f(fXf)L$ f($fY$f($f\f)L$f($fYD$@f\f(f($fYL$PfXf($fYL$`fXf($fYL$pfXf(f\ʋ$f)fXf)f(T$fXT$ f($fXD$0fWff(f\ȋD$ f)fXЋ$f)f\f($fYf($fYL$0f\f($fXfWff($fYD$ f(T$f\f\f($fYfXf(fX‹$f)f(f\f)$$lzp4$9$w[^_]à D${pD$`EwpD$$y ÐUWVS\$|f({pf)$@f(%{pf)$0f({pf)$ f(%{pf)$$t$$ $xNj$9$ [f(eFD$f(f(O@f(fff(fYf(5@R{pf(fWffYfXf(f\f)$fXf)$FD$f(f(O0f(fff(fYf(fWffYf(fXFD$f(f(f(fff(fYf(fWffYfXV$T$f(f(f(fff(fYf(fWffYfXًFD$f(f(OPf(fff(fYf(fWffYf(fXf(f\f)$f(f\f)$f($fX$f)$fXf)$fXf)$f(fXf)d$p^\f(f(Of(fff(fYf(fWffYfXf)\$`V Tf(f(O f(fff(fYf(fWffYfXFDD$ f(f(O`f(fff(fYf(fWffYfXًN Lf(f(Opf(fff(fYf(fWffYfXf(T$`f\f(f\f(fXf(D$`fXf)D$PfXfXf)D$@f(f\$f($fYfX$f($ fYf($f\f)d$0f\f($f\$f)D$ f($@fYD$ f($0fYfXf(fWff($@fYf($0fYL$ f\fWff($fX͋$f)f(T$0f\f(f\f) fX‹T$ f)fX\$0f(fXË$f)f\܋$f)f(D$@f\D$pf($fYf(D$@fXD$pf)D$f($ fYD$f($f\f(D$Pf\f(f($f\$f($@fYf($0fYf\f(fWff($@fYf($0fYfXfWff($fXD$f)Ef(fXf(f\Ƌ$f)fX$f)2f\f(fXf)f\f)$ $lǐzp4$9$ \[^_]à D$`{pD$LLwpD$$s ÐUWVSt$ |$(l$,T$L$$\$9}hf(Ff( f( f(fff(fYf(@R{pfWffYfXf(f\f)fXf)zp49|[^_]à D${pD$dRwpD$$)s ÐUWVSt$]f(f(f(fff(fYf(%@R{pf(fWffYfXM f(f(O f(fff(fYf(fWffYfXf)\$ Uf(f(O0f(fff(fYf(fWffYfXEf(f(Of(fff(fYf(fWffYfXf(f\f)D$f(f\D$ f)$fXfXT$ f(fXf(fXf)f(D$PfY$f(L$@fYL$fXf(fWff(D$PfYD$f(L$@fY $f\fWff\f(T$`fYf(D$pfYf\f(fXf\f(fXf)f(f\f)f\f) fXf) D$<$4ƃ@zpl$9D$< Č[^_]à D$@{pD$UwpD$$m ÐUWVSl$f({pf)D$Pf( {pf)L$@$$D$<$ŋ$9T$<.f(?^ f(f(M f(fff(fYf(-@R{pf(fWffYfXf(f\f)D$ fXFljD$f(f(M0f(fff(fYf(fWffYfXVf(f(Mf(fff(fYf(fWffYfXf(f\f)$fXN f(f(Mf(fff(fYf(fWffYfXFf(f(M@f(fff(fYf(fWffYfXf(f\fXf(f\$f(L$@fYf(fWffX$f(D$PfYf(L$ f\f(fXf)f(D$ fXf)f\f)f(f\f(L$@fYfWffXf(D$PfYf(f\f(f\f)fXf)?fXD$f)(D$<$<׃Pzp4$9D$<l[^_]à D${pD$pXwpD$$k ÐUWVS$f({pf)$f( {pf)$f( {pf)$f( 0{pf)L$pf(@{pf)D$`f( P{pf)L$P$$D$L@$Nj$9T$Lf(}^\f(f(Of(fff(fYf(%@R{pf(fWffYf(fXNLf(f(O@f(fff(fYf(fWffYfXf(f\f)D$0fXf)l$ FDD$f(f(f(fff(fYf(fWffYfXVTT$f(f(OPf(fff(fYf(fWffYfXf(f\f)$fXV Tf(f(O f(fff(fYf(fWffYfXFDf(f(O0f(fff(fYf(fWffYfXf(f\fXf(D$ fXf(fXf(f(fXf)Mf(D$PfY$f(L$pfYL$0f\f(L$`fYf\f(fWff($fYf(f\f(f($fYL$ f\f($fYfXf(fXf) f\f)f(D$PfYf(L$`fYL$0f\f(L$pfY $fXf(fWff($fYf(f\f(f($fYf\f($fYL$ fXf(fXf) f\f)f(D$pfYf(L$PfYL$0fXf(L$`fY $fXfWff($fYD$ f\f($fYf\f($fYfXf(fXNjD$f)f\T$f):D$L$l`zp4$9T$L}ļ[^_]à D${pD$([wpD$$f ÐUWVS$f({pf)D$p$$D$l+D$l$Nj$9L$lf(}FDD$hf(f(O0f(fff(fYf(%@R{pf(fWffYfXf(f\f)D$PfXFDD$Lf(f(Of(fff(fYf(fWffYf(fXNLf(f(OPf(fff(fYf(fWffYfXf(f\f)D$0fXf)l$ FDD$f(f(f(fff(fYf(fWffYfX^\f(f(O@f(fff(fYf(fWffYfXf(f\f)$fXVTf(f(O`f(fff(fYf(fWffYfXًF Df(0f(O f(fff(fYf(fWffYfXf(f\fXf(f\T$ f(f\fWff(f\f) fXЋL$Lf)fX|$ fXf(f\ŋL$hf)fXf)}f($f\f(L$pfYf(f\D$0f(fWff(D$0fXfWff($fXf(L$pfYf(f(L$Pf\f(l$PfXf(fXf)f(f\f)f\f) fXD$f) D$l$lpzp4$9D$lČ[^_]à D$@{pD$|_wpD$$=c ÐUWVS$f({pf)$f( {pf)$f({pf)$f( {pf)$f({pf)$pf( {pf)$`f({pf)$Pf( {pf)$@f({pf)$0f( {pf)$ f( {pf)$f( 0{pf)$f(@{pf)$f( P{pf)$$$$$Nj$9$f(Ef)$F D$f(f(O f(fff(fYf(5@R{pf(fWffYfXً^\f(#f(OPf(fff(fYf(fWffYfXf(fXf)$f\f($fYf)$FD$f(f(f(fff(fYf(fWffYfXFD$f(f(O`f(fff(fYf(fWffYfXFD$f(f(O0f(fff(fYf(fWffYfXf(f\f)D$pfXf($fYf(f\f)L$`fXVTf(f(Of(fff(fYf(fWffYfXF DD$ f(f(Opf(fff(fYf(fWffYfXNLf(f(O@f(fff(fYf(fWffYfXf(f\f)D$PfXf($fYf(f\f)L$@fXf(f\f($fYf(fWff($fX$fXf($fYf(f\f(fX$f)fXf)Uf\f) f($ fYD$@f($0fYL$pf\f($fYL$PfXf($fYL$`fXf\$f(fWff($PfY|$`f($@fYD$pfXf($fYl$@f($0fYD$PfXf(fXf)D$0f($`fY\$`f($pfYD$pf\f($fYd$@f($fYD$Pf\f(fXf)L$ f($fY$f($f\f)L$f($fYD$@f\f(f($fYL$PfXf($fYL$`fXf($fYL$pfXf(f\ʋ$f)fXf)f(T$fXT$ f($fXD$0fWff(f\ȋD$ f)fXЋ$f)f\f($fYf($fYL$0f\f($fXfWff($fYD$ f(T$f\f\f($fYfXf(fX‹$f)f(f\f)$$lzp4$9$w[^_]à D${pD$cwpD$$Q\ ÐUWVS\$|f({pf)$@f(%{pf)$0f({pf)$ f(%{pf)$$t$$ $xNj$9$ [f(eFD$f(f(O@f(fff(fYf(5@R{pf(fWffYfXf(f\f)$fXf)$FD$f(f(O0f(fff(fYf(fWffYf(fXFD$f(f(f(fff(fYf(fWffYfXV$T$f(f(f(fff(fYf(fWffYfXًFD$f(f(OPf(fff(fYf(fWffYf(fXf(f\f)$f(f\f)$f($fX$f)$fXf)$fXf)$f(fXf)d$p^\f(f(Of(fff(fYf(fWffYfXf)\$`V Tf(f(O f(fff(fYf(fWffYfXFDD$ f(f(O`f(fff(fYf(fWffYfXًN Lf(f(Opf(fff(fYf(fWffYfXf(T$`f\f(f\f(fXf(D$`fXf)D$PfXfXf)D$@f(f\$f($fYfX$f($ fYf($f\f)d$0f\f($f\$f)D$ f($@fYD$ f($0fYfXf(fWff($@fYf($0fYL$ f\fWff($fX͋$f)f(T$0f\f(f\f) fX‹T$ f)fX\$0f(fXË$f)f\܋$f)f(D$@f\D$pf($fYf(D$@fXD$pf)D$f($ fYD$f($f\f(D$Pf\f(f($f\$f($@fYf($0fYf\f(fWff($@fYf($0fYfXfWff($fXD$f)Ef(fXf(f\Ƌ$f)fX$f)2f\f(fXf)f\f)$ $lǐzp4$9$ \[^_]à D$`{pD$iwpD$$:V ÐUWVSl$f({pf)$Pf( {pf)$@$$$<@+$<$Nj$9$<f(Ef)$ F D$f(f(Opf(fff(fYf(=@R{pf(fWffYfXًFD$f(f(O0f(fff(fYf(fWffYf(fXf(f\f)$fXf)$f($@fYf($ f\f)$FD$f(f(f(fff(fYf(fWffYf(fXF$D$f(f(f(fff(fYf(fWffYfXf)$^\f(f(O@f(fff(fYf(fWffYfXf(f\f)$fXf)$f($@fYf($f\f)$FD$f(f(OPf(fff(fYf(fWffYfXf)\$pFDD$lf(f(Of(fff(fYf(fWffYfXًV(TT$hf(f(f(fff(fYf(fWffYf(fXf(f\f)D$PfXf)T$@f($@fYf(L$pf\f)L$0VTf(f(O`f(fff(fYf(fWffYf(fXN Lf(f(O f(fff(fYf(fWffYfXF,Df(f(f(fff(fYf(fWffYfXf(f\f)D$ fXf)d$f($@fYf(f\f) $f($f\\$0f(D$ f\$f($PfYf(f\fXf($f\D$Pf($PfYf(f\$f(fXf(fWff\f(fWff(f\f)f(fXf)fX⋄$f) f\f)f($ fX$f(D$pfXD$@f(f\f(fXfXt$f($fX$f(f\f(fWffXf(f\f)f(fXf)EfXы$f)f(f\Ƌ$f)f(\$ fX$f($fXL$Pf(f\f($PfYf(f(fWff(fXf($PfYfWff($fX\$0f($fX$f(f\fXf(fXD$lf)f(f\Nj$f)f\ʋD$hf)fX$f):$<$lǰzp4$9$<l[^_]à D${pD$ pwpD$$O UWVS$f(@{pf)$f( P{pf)$f(%`{pf)$pf(p{pf)$`f( {pf)$Pf(%{pf)$@f({pf)$0f( {pf)$ f(%{pf)$f({pf)$$$$+$$Ƌ$9$5 f(/E(f(f(f(fff(fYf(5@R{pf(fWffYfXEf(f(N@f(fff(fYf(fWffYfXf(f\f)$fXf($fYf(f\f)$fXf)$E lj$f(f(N f(fff(fYf(fWffYfXf)$]f(f(NPf(fff(fYf(fWffYfXf)$pM$ f(f(f(fff(fYf(fWffYfXf)$`U0f(f(f(fff(fYf(fWffYfXf)$PE f(f(Npf(fff(fYf(fWffYf(fXE4f(f(f(fff(fYf(fWffYfXf(f\f)$@fXf)$0E,f(f(f(fff(fYf(fWffYfXEf(f(f(fff(fYf(fWffYfXf(f\f)$ fXE8f(f(f(fff(fYf(fWffYfXEf(f(N0f(fff(fYf(fWffYfXf(f\f)$fXEf(f(Nf(fff(fYf(fWffYfXًEf($f(N`f(fff(fYf(fWffYfXf(f\fXf($@f\f)$f($ f\$f)$f($@fXf)$f($ fX$f)$fXf)$f($pfXf($`fXf)$f(fXf($fYf($pf\f)$f($fYf($`f\f)$f($fXf)$f($fY$0f($f\f)$f($fYf($Pf\f)d$pf($fXf)$f($fX$0f)d$`f($PfXf(fXf(f\f($fYfXf($ fYf($f\f(L$`f\f)L$Pf\$f($0fYf($@fYf\f(fWff($0fYf($@fYL$PfXf(fWff($fXf)f(fXf(fXf) f\f)f\f(f\Ë$f)fXf)f($`fY$f($PfY$fXf($`fY$f($PfY$f\f($fX$f($pfYfWff($f\\$pf($f\$f($0fYf($@fYfXf)L$@f($0fYf($@fYf\f)T$0f($f\$f($fYf($pfY$f($fY$f\f(fXf)L$ f\f($f\$f($fYf($fX$f($ fYf($f\f(fXf)D$f($fXf(f\f)$Ef\f)NjE(fXf)4f(D$ fXD$@f(@R{pf(fWff(T$f\׋Ef(fXf)NjE8f\f)f(D$0f\f(fWff($f\ՋEf(fXf)NjE f\f)fXd$0f(fWffX,$Ef(fXf)NjE4f\f),f(D$ f\D$@fWffX|$Ef(fXf)NjE,f\f)<ǃ$$<ǁzpl$9$Ĭ[^_]à D$@{pD$vwpD$$'E ÐUWVS|$f({pf)$`f( {pf)$Pf({pf)$@$$$<+$<$Ƌ$9$<f(eG f(\f(Npf(fff(fYf(5@R{pf(fWffYfXf(f\f)$ fXf)$GD$f(f(N0f(fff(fYf(fWffYf(fXG0D$f(f(f(fff(fYf(fWffYfXf(f\f)$fXf)$GD$f(f(Nf(fff(fYf(fWffYfXً_\f(f(NPf(fff(fYf(fWffYfXO(Lf(f(f(fff(fYf(fWffYfXW8Tf("f(f(fff(fYf(fWffYfXf(fXf)D$pf(fXf)L$`f\f\f(f\f($@fYf)$fXf($@fYf)$Gf(Tf(f(fff(fYf(fWffYfXG4f(Tf(f(fff(fYf(fWffYfXG$f(Tf(f(fff(fYf(fWffYfXGf(\f(N@f(fff(fYf(fWffYfXf(fXf)D$Pf(fXf)L$@f\f)D$0f\f\f($PfYf($`fYf\f)$f($PfYf($`fYfXf)$GfX$@f($fX$fX$f(fXf\f($fYf(f($fYf(f\f(fXf)f(f\ʋG(f(fXf)ƋGf(/C f($0f(8f(f(f(fYf(fYfXf(fYfYf\f(fXf)$f(f\f)$f\f)$fXf)$Cf(0f(8f(m`f(Mpf(fYf(fYf(fXf(fYfYf(f\C0f(,0f($8f(`f(pf(fYf(fYfXfYfYf\f(fXf)$f\f)$f(f\f)$fXf)$Cf($0f(8f(] f(M0f(fYf(fYf(fXfYfYf\ًC(f(40f(,8f( f(0f(fYf(fYfXfYfYf\f(fXf)$pf(fXf)$`f\f(f\f(f\f)$PfXf)$@C8f($0f(8f(f(f(fYf(fYf(fXfYfYf\ًCf(40f(,8f(f(f(fYf(fYfXfYfYf\f(fXf)$0f(fXf)$ f(f\f\f(fXf)$f\f)$C<$$f($$f(f(f(f(fYf(fYfXf)$f(fYfYf\f)$C,$$f($$f(f(@f(Pf(fYf(fYfXf)$fYfYf\K1$f(f(f(f(f(fYf(fYfXfYfYf\S 2$f(f)D$f(2f(M@f(UPf(fYf(fYD$fXfYfYT$f\f($fXf)$f(fX$f)$f\f)$pf($fXf)$`f(fXf)$Pf\f)$@f($f\f\f(f\f)$0fXf)$0f($f\f\$f(fXf)$ f\f)$ Cf(0f(8f(mf(Mf(fYf(fYfXf)$f(fYfYf\f)$C4f(0f(8f(f(f(fYf(fYfXf)$fYfYf\C$f(0f(8f(f(f(fYf(fYfXf)$fYfYf\Cf(<0f(48f(f(f(fYf(fYfXfYfYf\f($fX$f)$f(fX$f)$f\f)$f($fXf)$f(fXf)$f(f\f($f\f\$f(fXf)$f\f)$f($f\$f\f(f\fXf)$f($f\$f($Pf\$f($PfYf(fXf\f($f\$@f($PfYf(f($fX$fXf)L$pf\f($pfYf($`fY$fXf($pfY$0f($`fY$ f\f(fXf)D$`f\f($pfY$f($`fYf\f($`fY$0f($pfY$ fXf(f\fXf(f\D$`$f)f(D$pf\$f)fXt$`$f)0fXL$pf) f(f\‹$f)f(f\Ë$f)fX⋄$f) fXf)f($f\$f($`f\$ f(fXf\f($0f\$pf($f\$f(fXf)L$Pf\f($fXf($pf\$@f(fXf($PfYf\f($PfYf\$f($pfX$@f(f\f)$f($PfY$f)D$@fXf($PfYϋC(f(f\f)0f(D$Pf\f)8CfXf)$0fXL$Pf) 8C8f(f\D$@f)0f(f\f)8CfX\$@f)0fXf)8f($fX$f($@fX$f($PfYf(fXf\f)L$0f($PfX$f($PfYf(f($f\$f(fXf(f\f($`fY$f($pfY$fXf($`fY$0f($pfY$ f\f(fXf\f($`fY$f($pfY$f\f($pfY$0f($`fY$ fXf(f\fXЋC$f(f\f)0f(f\f)8CfXf)$0fXf)8C4f(D$0f\f)0f(f\f)8Cf(D$0fXf)0fXf)8f($fX$f($pfX$0f(fXf\f)\$ f($`fX$ f($fX$f(fXf\f(f($fX$f($fX$f(fXf(f\f($fX$f($`fX$Pf(f\fXf(C f(f\f)0f(f\f)8fXf)f(fXf)C0f(D$ f\f)0f(f\f)8Cf(D$ fXf)0f(fXf)8$L$ǁzp$9$LČ[^_]à D${pD$xpD$$# ÐUWVS, $@ $D $L f({pf)$ f( {pf)$ f( {pf)$f(%0{pf)$f(-@{pf)$f(5P{pf)$f(`{pf)$$P )$H ;$T !G@f(f(f(f(f(fYf(fYfXf(fYfYf\f)$G f($f(f(f(f(fYf(fYfXf)$fYfYf\ًG`f(4f(,f(f(f(fYf(fYfXfYfYf\f( fXf($fXf(fXf)$f\f)$f(f\$f($f\f(f\f)$fXf)$pf( f\f(f\f(f\f)$`fXf)$PfXf($fXf(fXf)$@f\f)$0Gf(f(f(.f(Nf(fYf(fYfXf)$f(fYfYf\f)$Gdf(f(f(f(f(fYf(fYfXf)$fYfYf\GDf(f(f(f(f(fYf(fYfXf)$fYfYf\G$f(<f(4f(f(f(fYf(fYfXfYfYf\f($fX$f(fX$f(fXf)$ f\f)$f($fXf(fXf(f\f)$fXf)$f($f\f\$f(fXf)$f\f)$f($f\$f\f(f\f)$fXf)$G|f(f(f(f(f(fYf(fYfXf)$f(fYfYf\f)$G\f(f(f(f(f(fYf(fYfXf)$fYfYf\G<f(f(f(f(f(fYf(fYfXfYfYf\Gf(4f)$f(4f(f(f(fYf(fY$fXfYfY$f\f($fXf(fX$f(fXf)$f\f)$f($fXf(fXf(f\f)$fXf)$pf($f\f\f(f\f)$`fXf)$Pf($f\f\$f(fXf)$@f\f)$0Gf(f(f(f`f(Npf(fYf(fYfXf)$pfYfYf\G0f(f(f(`f(pf(fYf(fYfXf)$`fYfYf\GPf(4f(f(`f(pf(fYf(fYfXf)$PfYfYf\ًGpf(<f(4f(`f(pf(fYf)$@f(fYf)D$f($@fXD$f)$0fYfYf\f($pfX$Pf($0fX$`f(fXf)$ f\f)$f(fXf(fXf(f\f)$fXf)$f\f($pf\$Pf(f\f)$fXf)$f($0f\$`f\f(fXf)$f\f)$Gf(f(f(n f(N0f(fYf(fYfXf)$ f(fYfYf\f)$Ghf(f(f( f(0f(fYf(fYfXf)$fYfYf\GHf(f(f( f(0f(fYf(fYfXf)$fYfYf\G(f(<f(4f( f(0f(fYf(fYfXfYfYf\f($ fX$f(fX$f(fXf)$f\f)$f($fXf(fXf(f\f)$fXf)$f($f\f\$f(fXf)$pf\f)$`f($ f\$f\f(f\f)$PfXf)$@Gxf(f(f(f(f(fYf(fYfXf)$f(fYfYf\f)$GXf(f(f(f(f(fYf(fYfXf)$fYfYf\G8f(f(f(f(f(fYf(fYfXf)$fYfYf\Gf(<f(4f(f(f(fYf(fYfXfYfYf\f($fX$f(fX$f(fXf)$f\f)$0f($fXf(fXf(f\f)$ fXf)$f($f\f\$f(fXf)$f\f)$f($f\$f\f(f\f)$fXf)$Gf(f(f(f(f(fYf(fYfXf)$pf(fYfYf\f)$`GTf(f(f(f(f(fYf(fYfXf)$PfYfYf\f($pf\f)$@f($`f\Gtf($f(f(f(f(fYf(fYfXf)$0fYfYf\ًG4f(f)$ f(4f(f(f(fYf(fY$ fXfYfY$ f\f($0f\f(f\f)$f($pfX$Pf($0fXf(fXf)$f\f)$f($`fXfXf(f\f)$fXf)$f(f\$f($@fXf(f\f($fYf)$fXf($fYf)$f\$@fX$f(f\f($fYf)$fXf($fYf)$G f(f(f(f@f(NPf(fYf(fYfXf)$f(fYfYf\f)$GLf(f(f(@f(Pf(fYf(fYfXf)$fYfYf\f($f\f)$f\Glf($f(f(@f(Pf(fYf(fYfXf)$fYfYf\ًG,f( f)$f(4f(@f(Pf(fYf(fY$fXfYfY$f\f($f\f(f\f)$f($fX$f($fXf(fXf)$pf\f)$pf($fXfXf(f\f)$`fXf)$`f($f\f(fX$f(f\f($fYf)$PfXf($fYf)$@f\$fX$f(f\f($fYf)$0fXf($fYf)$ f($fX$ f($fX$f(fXf\f($fX$f($fX$@f(fXf\f($ fX$f($fX$pf(fXf\f($fX$f)$f($pfX$`f( $f\f)$Pf( $fXȋG@f(f\f)f(f\f)fXf)#fXf) G`f(f\$Pf)f(f\f)G fX$Pf)fXf)f($f\$ f($f\$f(fXf\f)$@f($f\$f($@f\$f(fXf\f)$0f($ f\$f($f\$f(fXf(f\f($f\$pf($pf\$`f(f\f(fXf(fXf($fYЋWPf(f\f)GfXf) f(fXf($fYf(fXf)f\f) f(f\f($fYȋWpf($@f\f)G0f($@fXf)f\f($fYf(fX$0f)f($0f\f) f($f\$f($fX$0f)$ f($0f\$f)$f($fX$f)$f($f\$f($0fX$ f(f\f($fYf)$fXf($fYf)$f($fX$`f($fX$pf($fYf($fYf\f)$f($fYf(f($fYfXf)$f($fX$f($0f\$ f(fXf($fYf)$f(f\f($fYf)$f($f\$f($f\$f($fYf($fYfXf)$f($fYf($fYf\f($fX$f($fX$f($fYf($fYfXf)$f($fYf($fYf\f($f\$`f($f\$pf($fYf($fYf\f($fYf($fYfXf(fX$f($fXӋWXf(f\f)GfXf) f(fXf($fX$f(fXf) f\f) f\$f\Wxf(f\f)G8fXf)<f\$f($f\$f(fXf)f(f\f) f($fX$f($fX$WHf(f\f)GfXf) f(fX$f($fX$ f(fXf) f\f) f($f\$f\$Whf(f\f)G(f(fXf)f($f\$f($ f\$f(fXf)f(f\f) f($f\$f($fYf($`f\f)$pf($`fXf)$`f($f\$f($fYf(fX$pf)$Pf($pf\f)$@f($fY$pf($fY$Pf(f\f($fY$f($fY$fXf(f\f)$0fXf)$ f($`fX$Pf($@fX$0f($fYf($fYf\f)$f($fYf(f($fYfXf)$f($f\$f($f\$f($ fYf($ fYfXf)$f($ fYf($ fYf\f($fY$Pf($fY$pfXf($fY$f($fY$f\f(fXf)$f\f($fX$f($fX$f($fYf($fYfXf)$f($fYf($fYf\f($`f\$Pf($@f\$0f($ fYf($ fYf\f($ fYf($ fYfXf($pfX$0f($fXӋW\f(f\f)GfXf) f(fXf(fX$@f(fXf) f\f) f($pf\$0f\W|f(f\f)G<f(fXf)f\$f($@f\f(fXf)f(f\f) f($`fX$f($fX$WLf(f\f)G fXf) f(fX$f($ fX$Pf(fXf) f\f) f($`f\$f\$Wlf(f\f)G,f(fXf)f($f\$f($Pf\$ f(fXf)f(f\f) f($fX$f($fYf($Pf\f)$f($PfXf)$f($fX$f($fYf(fX$f)$f($f\f)$f($fY$`f($fY$@f(f\f($fY$f($fY$fXf(f\f)$fXf)T$pf($PfX$ f($0fX$@f($ fYf($ fYf\f)\$`f($ fYf(f($ fYfXf)L$Pf($f\$f($f\$f($fYf($fYfXf)\$@f($fYf($fYf\f($fY$@f($fY$`fXf($fY$f($fY$f\f(fXf)D$0f\f($fX$f($fX$f($ fYf($ fYfXf)T$ f($ fYf($ fYf\f($Pf\$ f($0f\$@f($fYf($fYf\f($fYf($fYfXf($fX$f(T$@fXӋWTf(f\f)GfXf) f(fXf(fX$f(fXf) f\f) f($f\$f\Wtf(f\f)G4f(fXf)f\\$@f($f\f(fXf)f(f\f) f($fXL$0f(T$ fXT$`WDf(f\f)GfXf) f(fXT$Pf(D$pfX$f(fXf) f\f) f($f\L$0f\|$PWdf(f\f)G$f(fXf)f(T$`f\T$ f($f\L$pf(fXf)f(f\f) $X zp<;$T , [^_]à D${pD$$xpD$$J ÐUWVS$$$$$$$9$4$f(!f(Af)D$ f(i f(A0f)D$f(t$ fYf(fYfXf(fYL$f(D$ fYf\f(?f(Ef)$$H49f(f(f(fYf)D$pf(fYf)$f(D$pfX$f)D$`fYfYf\P:D$\f(f( f(\$ fYf(fYfXfYf(D$ fYf\$C 8f(f(f(D$fYf)D$@f(fYf)$f(D$@fX$f)D$0fYf(D$fYf\f(fXD$`f(fXT$0f(f\f)fXf)f(fXf(fX$f(fXf)Mf\f)f\|$`f\f(f\f)fXL$\f)9f($f\f\\$0f(f\f)fXf)$$Ń$@zp$$$9$Ĭ[^_]à D${pD$ypD$$蛴 ÐUWVS<$Tf(@{pf)$$`$ @$X$,$d9$ $,f(f)D$`f(Hf)L$Pf(` f(P0f)T$@f(fYfYf(D$PfYf(|$`fYf(f\f(fXf)$fXf\f)$f(@@f)D$0f(XPf(L$PfYf(D$`fYD$0fXf)$f(fYf(fYD$0f\f)$f(L$`fYf(D$PfYD$0f\f)$f(fYf(fYD$0fXf)$$Pf(f)D$ $\p$P$f(:f(f($fYf(fYfXfYf($fYf\f(D$ fXf)$f(Uf\f)$pf(D$ f\f)$`fXu@$P‰$\f(艄$Xf(f(fYf(D$0fYfXf)$@f(D$0fYfYf(f\$\x $P$<f(f(f(L$@fYf(fYfXfYf(D$@fYf\f($@fXf)$ f(fXf)$f($@f\f)$f\f)$X$P؉$f(f( f($fYf(fYfXfYf($fYf\苄$\P$PЉ$f(f(f($fYf($fYfXf($fYf(f($fYf\f(f(fXf)$f\f(f\f)$fX苄$\H$Pȉ$f(f( f(d$PfYf(D$`fYfXf(\$`fYf(D$PfYf\f)$$\@D$ D$$PD$$f(D$D$f(f($fYf($fYfXf($fYf(f($fYf\f(f(fXf)$f($fXf\f($f\f)L$pf($fX$fX$ f(f\ʋ$f)fX‹$Pf)f(fX$f(fXf(fXf)Mf\f)f($f\$f\$f(f\Ë$f)f(fXË$f)f($ f\$f\f(fXf)f\f)2f($`f\$f($pf\f(D$pf\f($fX$f(f\f($fYfXf($fYf(f\ŋ$\f)f(f\D$f)fX݋$<f)fXf) f($`fX$fX$pfXd$pf($f\$f(fXf($fYf(f\f($fYf(f\‹$f)f(f\$Xf)f(fX‹$f)fXf)$ $h$PŃ$,`zp$\$\$d9$ <[^_]à D${pD$ypD$$# ÐUWVS $ $$$,f({pf)$f( {pf)$f({pf)$$0$$($$49$j$f(f)$f(Hf)L$pf(P f)T$`f(X0f)\$Pf(fYf(fYfYL$Pf($fYT$Pf(f\f)$f(fXf)$f\f)$fXf(@Pf)D$@f(d$pfYf(L$`fYf)$pf($fYf(T$PfYf(p@f)t$0f($fYf)$`f(L$PfYf(D$pfYf(|$`fYf($`fXf)$Pf($pf\f)$@f(fXf)$0f(f\fXf)$ f\f($pfXf)$f($`f\f)$f(P`f)T$ f(`pf)d$f(|$pfYf($fYfXf($fYf(D$pfYf\f)$f($fYL$@f($fYD$0f(f\f)$fXf)$f($fYL$0f($fYD$@f(fXf)$f\f)$f(fYL$@f($fYD$0f(f\f)$fXf)$f(fYL$0f($fYD$@f(fXf)$f\f)$pE f($8f(0f(fYf($PfYfXf($PfYfYf\f(fXf)$`f(&f\f)$pf(f\f)$`fXf)$PEf(8f( 0f($fYf($fYfXf)$Pf($fYf($fYf(f\E0f($8f(0f($fYf(fYfXfYf($fYf\f($PfXf)$@f($Pf\f)$@f(f\f)$0fXf)$0Ef(8f( 0f($fYf(fYf(fXfYf($fYf\؋E(f($8f(0f($0fYf($fYfXf($fYf(f($0fYf\f(f(fXf)$ f(fXf)$f\f\f(f(f\f)$ fXf)$E8f(8f( 0f($fYf(fYf(fXfYf($fYf\Ef(8f(0f($@fYf($ fYfXf($ fYf($@fYf\f(fXf)$f(fXf)$f(f\f\f(fXf)$f\f)$E<f(8f( 0f(\$fYf(D$ fYfXf)$f(d$ fYf(f(D$fYf\f)$U,:f(f( f($fYf($pfYfXf($pfYf($fYf(f\Ef(8f( 0f($fYf($fYfXf($fYf($fYf\E  8f(f(0f(L$PfYf(D$`fYfXf(D$`fYf(f(D$PfYf\f(f($fXf)$f(fXf)$f\f)$f($fXf)$f(fXf)$f\f)$f($f\f\f(f\f)$fXf)$f($f\f\f(fXf)$pf\f)$Ef(8f( 0f(t$pfYf($fYfXf)$`f($fYf(D$pfYf\f)$PE4f(8f( 0f($fYf($fYfXf($fYf(f($fYf\f)$@E$f(8f( 0f(d$@fYf(D$0fYfXf(\$0fYf(D$@fYf(f\Ef(8f(0f($fYf($fYfXf($fYf($fYf(f\f($`fXf)$0f(fXf)$ f\f)$f($PfXf)$f(fX$@f)$f\f($Pf\f\f(fXf\f)$f($`f\f(f\$@f(f\f)$fXf)$f($`f\$0f($ f\$f($fYf(fXf\f($f\$f($fYf(f($@fX$pfXf)$f\f($fY$f($fYfXf($fY$f($fY$pf\f(fXf)$f\f($fYf(f($fY$f\f($fY$f($fY$pfXf(f\fXf(f\$f)f($f\f)fX$f))E fX$f)ƋE<f(f\f)8f(f\f)0EfXf)$8fXf)0f($`f\$@f($f\$f(fXf\f($f\$ f($Pf\$0f(fXf)$f\f($fXf($f\$f(fXf($fYf\f($fYf\$f($fX$f(f\f)$f($fY$f)$fXf($fY΋E(f(f\f)8f($f\f)0EfXf)$8fX$f) 0E8f(f\$f)8f(f\f)0EfX$f)8fXf)0f($`fX$0f($fX$f($fYf(fXf\f)$f($ fX$f($fYf($pf\$@f(fXf\f($fY$f($fY$fXf($fY$f($fY$f\f(fXf\f($fY$f($fY$f\f($fY$f($fY$fXf(f\fXЋE$f(f\f)8f(f\f)0EfXf)$8fXf)0E4f($f\f)8f(f\f)0Ef($fXf)8fXf)0f($`fX$@f($ fX$f(fXf\f)$f($fX$f($0fX$Pf(fXf(f\f($0fX$ f($fX$f(fXf(f\f($fX$f($fX$f(f\fXf(E f(f\f)8f(f\f)0fXf)fXf)6E0f($f\f)8f(f\f)0Ef($fXf)8f(fXf)0$$8ƃ$zpl$49$ [^_]à D${pD$$ypD$$ ÐUWVSl $ $ $ f({pf)$P f( {pf)$@ f({pf)$0 f({pf)$ f(%{pf)$ f(-{pf)$ f( {pf)$ $ $ ;$ *f(O f)$ f(G0f)$ f(fYf(WfYf(OfYf(?fYf(fXf)$p f)$ f\f)$` f)$ f(fXf)$P f)$ f\f)$ f(w@f(fYf)$@ f(fYf)$0 f(_fYf)$ f(g fYf)$ f(ofYoPf)$ f(o fYoPf(fYOPf(fYWPf)$ f(g`f)$ f(_ fYf)$ f(WfYf)$ f(fYf)$ f(fYf)$ f(_pf)$p fYf)D$ f(fYf)$ f(W fYf)$ f(WfYf($ fXD$ f)$ f($ f\$ f)$p f($ fXf)$` f($ fX$ f)$P f($ fX$ f)$@ f($ f\$ f)$0 f($ f\f)$ f($ f\T$ f)$ f(WPfYf(fYfXf)$ f(fYf(GPfYf\f)$ f($p fYf)D$f(fYf(T$fXf)$` f(T$f\f)$ f($p fYf)D$f(fYf(T$f\f)$P f(T$fXf)$ f($` fYf)D$f($P fYf(T$f\f)$@ f(T$fXf)$0 f($` fYf)D$f($P fYf(T$fXf)$ f(T$f\f)$ f($@ fX$ f)$ f(f\$ f)$fYfYfXf)$ f($ fYf($fYf\f)$ f($@ f\$ f)$ fX$ f)$ f(fYf)$f(fYf)D$ f($fXD$ f)$f(fYfYf\f)$f($ f\$ f)$ f(fX$0 f)$p f(fYf)$f(fYf)D$ f($fXD$ f)$f(fYfYf\f)$f($ fX$ f)$` f\$0 f)$P f(fYf(fYfXf)$@ f(fYfYf\f)$0 f($p fYf(fYGPf(f\f)$ fXf)$f($p fYGPfYf(fXf)$ f\f)$pf(fYf(fYfXf)$`f($fYf($pfYf\f)$ fYfYf\f($pfYf($fYfXf($` fYf($P fYGPf(f\f)$Pf)$ fXf)$ f($` fYGPf)$@f($P fYf)T$ f(fXT$ f)$ f\D$ f)$0f)$ f(fYf)$ f($PfYf)D$ f($ fXD$ f)$ f(fYf)$f($0fYf)D$ f($f\D$ f)$ f($PfYfYf\f)$ f($0fYfYfXf)$ A@f(0f( f(fYf($`fYfXf($`fYfYf\f)$@A f(0f( f($fYf($ fYf(fXf($ fYf(f($fYf\f)$0A`f(0f(f($p fYf($ fYfXf($ fYf(f($p fYf(f\f(fXf)T$f(fXfXf)$f(T$f\f)$f(f\$@f\f(f(f\f)$fXf)$f(f\f($0f\f(f\f)$fXf)$f($0fXf($@fXf(fXf)$f\f)$Af(0f( f(_fYf(fYfXf)$ f('fYf(f(GfYf\f)$Adf(0f( f($P fYf($` fYfXf($` fYf(f($P fYf\f)$ADf(0f( f($fYf($fYfXf($fYf(f($fYf\f)$A$f(0f(f(OPfYf(fYfXfYf(GPfYf\f($ fXf(fXf(fXf)$f\f)$pf($fX$f(fX$f(f\f)$`fXf)$Pf($f\$f\f(fXf)$@f\f)$0f($ f\f\$f(f\f)$ fXf)$A|f(0f( f($ fYf($@ fYfXf)$f($@ fYf(f($ fYf\f)$A\f(0f( f($ fYf($0 fYfXf($0 fYf(f($ fYf\f)$A<f(0f( f($fYf($fYfXf($fYf(f($fYf(f\Af(0f(f($pfYf($fYfXf($fYf(f($pfYf(f\f($fXf)T$f(fXfXf)$f(T$f\f)$f($fXf)D$f(fX$f(T$f\f)$f(T$fXf)$f($f\f(f\$f(f\f)$fXf)$f($f\f\f(fXf)$f\f)$Af(0f( f($ fYf($ fYfXf)$f($ fYf(f($ fYf\f)$A0f(0f( f($p fYf($ fYfXf($ fYf(f($p fYf\f)$APf(0f( f($ fYf(fYfXfYf($ fYf\Apf(0f( f($@ fYf($ fYf(fXf($ fYf($@ fYf(f\f($fXf(fXf(fXf)$f\f)$pf($fXf(fX$f(f\f)$`fXf)$Pf($f\f($f\f(f\f)$@fXf)$0f(f\f(f\$f(fXf)$ f\f)$Af(0f( f($ fYf($ fYfXf)$f($ fYf(f($ fYf\f)$pAhf(0f( f($0 fYf($` fYfXf($` fYf(f($0 fYf(f\AHf(0f( f($ fYf($ fYfXf($ fYf($ fYf(f\A(f(0f(f($ fYf($ fYfXf($ fYf(f($ fYf(f\f($fXf)T$f(fXfXf)$f(T$f\f)$f($pfXf)D$f(fXf(T$f\f)$f(T$fXf)$f($pf\f\f(fXf)$f\f)$f($f\f(f\f(f\f)$fXf)$Axf(0f( f($P fYf($ fYfXf)$`f($ fYf(f($P fYf\f)$PAXf(0f( f($ fYf($ fYfXf($ fYf($ fYf(f\A8f(0f( f($ fYf($ fYfXf($ fYf(f($ fYf(f\Af(0f(f($P fYf($` fYfXf($` fYf(f($P fYf(f\f($`fXf)T$f(fXfXf)$f(T$f\f)$pf($PfXf)D$f(fXf(T$f\f)$`f(T$fXf)$Pf($Pf\f\f(fXf)$@f\f)$0f($`f\f(f\f(f\f)$ fXf)$Af(0f( f($ fYf($ fYfXf($ fYf(f($ fYf\f)$@ATf(0f( f($0 fYf($@ fYfXf($@ fYf(f($0 fYf\f)$0f(f\f)$ f($@f\Atf(0f( f($ fYf($ fYfXf)$f($ fYf($ fYf\f)$A4f(0f(f($ fYf($ fYfXf($ fYf(f($ fYf\f(f($f\f\fXf($fXf(f(fXf)$f\f)$f($@fX$0f($fXf(f\f)$fXf)$f(f\f($ fXf(f\f($ fYf)$fXf($ fYf)$f\$ fXf(f\f($ fYf)$fXf($ fYf)$A f(0f( f($ fYf($ fYfXf($ fYf(f($ fYf\f)$ALf(0f( f($ fYf($ fYfXf($ fYf(f($ fYf\f)$f($f\f)$f(f\Alf(0f( f($p fYf($ fYfXf)$f($ fYf($p fYf\f)$A,f(0f(f($ fYf($ fYfXf($ fYf(f($ fYf\f(f($f\f\fXf($fXf(f(fXf)$f\f)$pf($fX$f($fXf(f\f)$fXf)$f($f\f(fXf(f\f($ fYf)$fXf($ fYf)$`f\fX$f(f\f($ fYf)$pfXf($ fYf)$Pf($fX$f($fX$f(fXf\f($fX$Pf($PfX$f(fXf\f($fX$f($fX$f(fXf\f($PfX$f)$f($fX$f( $f\f)$`f( $fXȋA@f(f\f)0f(f\f)fXf)&fXf) A`f(f\$`f)0f(f\f)A fX$`f)0fXf)f($f\$f($f\$Pf(fXf\f)$Pf($f\$f($f\$Pf(fXf\f)$@f($f\$f($Pf\$f(fXf(f\f($f\$f($f\$f(f\f(fXf(fXf($ fYЋQPf(f\f)2AfXf) 0f(fXf($ fYf(fXf)f\f)f(f\f($ fYȋQpf($Pf\f)2A0f($PfXf)0f\f($ fYf(fX$@f)f($@f\f)f($f\$`f($pfX$f)$0f($f\$pf)$ f($fX$`f)$f($f\$f($pfX$`f(f\f($ fYf)$fXf($ fYf)$f($fX$f($fX$pf($ fYf($ fYf\f)$f($ fYf(f($ fYfXf)$f($fX$f($pf\$`f(fXf($ fYf)$f(f\f($ fYf)$f($`f\$f($pf\$f($ fYf($ fYfXf)$f($ fYf($ fYf\f($`fX$f($pfX$f($ fYf($ fYfXf)$f($ fYf($ fYf\f($f\$f($f\$pf($ fYf($ fYf\f($ fYf($ fYfXf(fX$f($fXӋQXf(f\f)2AfXf) 0f(fXf($fX$ f(fXf) f\f)f\$f\Qxf(f\f)2A8fXf)<0f\$f($ f\$f(fXf)f(f\f)f($fX$f($fX$QHf(f\f)2AfXf) 0f(fX$f($fX$0f(fXf) f\f)f($f\$f\$Qhf(f\f)2A(f(fXf)0f($f\$f($0f\$f(fXf)f(f\f)f($@f\$ f($ fYf($f\f)$f($fXf)$f($f\$0f($ fYf(fX$f)$pf($f\f)$f($ fY$f($ fY$f(f\f($ fY$ f($ fY$@fXf(f\f)$fXf)$`f($fX$f($fX$pf($ fYf($0 fYf\f)$Pf($0 fYf(f($ fYfXf)$@f($@f\$f($ f\$f($P fYf($@ fYfXf)$f($P fYf($@ fYf\f($ fY$f($ fY$fXf($ fY$ f($ fY$@f\f(fXf)$0f\f($@fX$f($ fX$f($ fYf($0 fYfXf)$ f($ fYf($0 fYf\f($f\$f($f\$pf($P fYf($@ fYf\f($@ fYf($P fYfXf($fX$f($fXӋQ\f(f\f)2AfXf) 0f(fXf(fX$f(fXf) f\f)f($f\$f\A|f(f\f)ƋAuO;L$>uf$t$|$ Ð $t$|$\$|$1tMD$0 u@D$ u9D$,u2 u-u( u uS;T$>uO;L$>uf$t$|$ ÐUWVSL$T$|$0l$4f(- |pt$,\$$Ã9f(f(@R{pf(fWf(fXf( f\f(fffYfWffYfXf(f\f(fYfWf)fXf(fYf))ƒ9z[^_]ÃD$ D$` |pD$(ypD$ $%UWVS,t$@\$Hl$Tf( |pf)D$|$XL$P0;|$\cf(f(-@R{pf(fWf(fXf( f\f(fffYfWffYfXE0f(fWf(If(fXf(fff(fYf(fWffYf\f(I f\f(fffYf(fWffYfXf(f\f(f\fWff)$f(f\f(D$fYf(fX$f(D$fYfWf) f)fXfXf(f\f(L$fYfWfXf(D$fYf)(f)D$`)Ã0zpl;|$\,[^_]ÃD$ D$ |pD$ypD$ $#UWVS$$$f( |pf)$f( 0 |pf)L$pf(@ |pf)D$`$D$\$ƃP$9T$\f(eC(T$Xf(f)$S *f(-@R{pf(fW f)L$@f(fW8f(fWf(fXf(N f(f\$f(fffYfWffYfXf(fXf)D$0f\f)t$ f(f\f(fffYf(fWffYfXf(N0f(\$@fXf(fff(fYf(fWffYf\f(fXf)L$f\f(NfX<$f(fff(fYf(fWffYf\f(N@f(\$@f\f(fffYf(fWffYfXf(fXf\f(D$f\f(L$pfYf(fWff(|$`fYfX\$f(D$0fXf(T$`fYf(L$`fYL$0f($fYf\f)Uf(fXfWf)f\f) f(f\f(L$pfYf(fWff(\$`fYfXf(D$ fXf(L$`fYf(fWf(D$`fYD$ f($fYf\f)f(fXˋD$Xf)f\fWf)/D$\$)ǃPzp$9T$\EĜ[^_]ÃD$ D$ |pD$ypD$ $I ÐUWVS$$f( |pf)$f( |pf)$f(% |pf)$$$+$$Ńp$9$$K1$f(f)D$f(5@R{pf(fW/f(fW9f(fXf(M0f(fXf(fff(fYf(fWffYf\f(fXf)L$pf\f($fYf)d$`f(Mf\.f(fffYf(fWff(fYfXf(M@f\|$f(fffYf(fWffYfXf(fXf)l$Pf\f)\$@S2D$f(f\fWf)f(fXf)9f\f(fWË$B $f)fXBf\d$pf(fWf)f(D$PfXË$f)f(D$@fXf)f\L$@f(fW$f)8f\\$PfWf)<9$ $$)ǁ0zp$$$9$ Ĭ[^_]ÃD$ D$|pD$ypD$ $ÐUWVSL$T$|$0l$4t$,\$$Ã9}rf(f(%@R{pf(fWf(fXf( f\f(fffYfWffYf\f(fXf)f\fWf)")ƒ9|[^_]ÃD$ D$|pD$ zpD$ $ UWVSt$0\$8l$D|$HL$@0;|$LCf(6Ef(%@R{pf(fWf(f\fXf(f(fW f(f\f(fWffXf)$f(fXf( f(fXf(fffYfWffYf\f(fXf)f\f(fWf)f(I f\f(fffYf(fWffYf\f(If\4$f(fff(fYf(fWffYfXf(fXf)f\fWf)"D$P)Ã0zpl;|$L[^_]ÃD$ D$`|pD$ zpD$ $fÐUWVS|$$$f(|pf)D$`f( |pf)L$P$D$L$ƃP$9T$Lof(mS:D$Hf(%@R{pf(fWf(f\f)L$0fXf(C (f(fW?f(fWf(f\f(f\ f(fXf)t$ f\f(L$PfYf(fWffXfXf(fXf\f(D$PfYf(fWff(fXf)D$f(N f(D$0fXD$ f(fffYfWffYf(f\f)$f(D$`fYf\f(Nf(f\f(fff(fYf(fWffYfXf(N0fXf(fff(fYf(fWffYfXf(D$`fYD$ f(T$0f\f(N@f(f\f(fffYfWffYf\f(fXf(fffYf(fWffYf\f($fXf)f\<$f(fWf)f(D$f\fWf)fXT$f)Uf(f\fWD$Hf) fXf)D$L$)ǃPzp$9T$L|[^_]ÃD$ D$|pD$8zpD$ $\UWVS$$f(@|pf)$$$+$$Ńp$ 9$f($H1$f(‹@ D$,f(%@R{pf(fWB:$f(fWf(f\f)$f(f\f)$fXf(fXf(f\f)$fXf)T$pf(:D$,f(0f(fW)f(fWf(f\f(f\f(fXf)L$f($fYL$f)L$`f\f($fYf)L$PfXfXf(f\fWff)D$@fXf(l$pfXf)l$0f(MPf($f\f(fff(fYf(fWffYfXf($fX\$`f($fXD$Pf(fWff(M`f(f\f(fffYfWffYf\f(MfXf(fffYf(fWffYf\f(fXf)f(D$0f\fWf)f\f(fWf)fX\$0f)f(Mf($fXT$@f(fff(fYf(fWffYfXf(M0f(T$pf\f(fff(fYf(fWffYfXf(D$Pf\$f(fWff($f\|$`f(M f(fXf(fffYfWffYf\f(M@f(f\f(fffYfWffYf\f(fXf)f(f\fWf)f\fW勄$f) fX֋$f)$$)ǃpzp$$$ 9$H[^_]ÃD$ D$|pD$@zpD$ $ ÐUWVS$$f(|pf)$f( |pf)$f(|pf)$f(|pf)$$$|$Ł$9$|:f($Q:$xf(=@R{pf(fWf(f\f)$`fXf)$PY3$Lf(f(fWf(f\fX؋AD$,$Hf(I L$ 9$Df(fW0f(f\f)$0fXf(D$,D$,f(fWf(f\f)$ fXf(f(fWf(f\fXf(f\$ f)$f(f\$0f)$f(f\f)$f(f\f)$fXfXf(fXf)$f\f($fYf)$fX$ fX$0f(fXf\f($fYf($PfXf)$f(M@f($`fXf(fffYfWffYf(f\f)$f($fY$f($fY$f\f(fWff($fY$f($fY$fXf(fWff($fYf($`f\f(f\fXf(M f(f\f(fffYfWffYf(f\f)$f(Mf(fXf(fffYfWffYf(f\f)$f(f\f(fffYf(fWffYf(f\f)D$pf(M`fXf(fffYf(fWffYf(f\f)D$`f($fY$f($fY$f\f(fWff($fY$f($fY$fXf(fWff($fY$f($Pf\f(f\$f($fXf)L$Pf(Mf(fXf(fff(fYf(fWffYfXf(MPf(fXT$Pf(ff)D$ff(fYD$f)D$@f(fWffYf(T$@fXf)T$0f(Mpf\f(fff(fYf(fWffYfXf(M0f(d$Pf\f(fff(fYf(fWffYfXf($fXƋ$Hf)f(D$pfXf)f($f\$fWf)f\$f(fWƋT$,f)f($fX$f)f(D$0f\D$`fWNj$Df)f(f\$fWf)f\T$pfW$xf):f(D$`fXD$0f)f($fXË$Lf)$|$)ǁŐzp$$$9$|[^_]ÃD$ D$`|pD$zpD$ $ÐUWVS$f(|pf)$f( |pf)$$($@+$$ Ł$,9$o$f(f)D$`$$BD$L$f(-@R{pf(fWf)D$0r$f( f)L$PZ ;$f(fW0f(fXƉыR$Љ$f( IL$ 9$f(fWf(fXf(|$`fXf(\$0fXf)$f($fYf(f(\$`f\f)$f($fYf(\$0f\f($f\f)$f($fXf)$pf(T$Pf\f\f(f\f($fYf)$`fXf)$P$f(f(fW2f)t$ f(f(f(f\fWf)$@fXf(fW$f( D$L$f(f(f\fXf($@f\f($fYf)$0f($@fXf)$ f($fYf(f\f($fYf(t$ f\f(f(f\f)$fXf)$fXf(t$ fXf(f\f(fWffXf(fX$f(fXf)$f(MPf\f(fff(fYf(fWffYfXf)$f\$f(M f(f\f(fffYfWffYf(f\f)$f(fXf(fffYf(fWff(fYf\f)$f($f\$0f($`fX$f(fWff(f(f\f(fffYfWffYf(f\f)$f(MfXf(fffYf(fWffYf\f($PfX$ f($fYf(fWff($pfX$f(M0f(fXf(fff(fYf(fWffYfXf)$f(Mpf\f(fff(fYf(fWffYfXf)$f($fX$0f($f\$`f(fWff(M@f(fXf(fffYfWffYf(f\f)$f(M`f(f\f(fffYfWffYf\f($pf\$f)D$pf($ f\$Pf($fYf(fWff(f(\$pf\f(fff(fYf(fWffYfXf(MfXT$pf(fff(fYf(fWffYfXf($fXf)f($f\fWf)f($f\fWŋ$f)f($fX$$f)fX$$f)8f\$f(fWƋ$f)f($f\$fWf)fX$f)#f($f\$fWf)f(fX$f)f($fX$$f)f\$fW닌$f))$$0$)ǁŰzp$$$$$,9$[^_]ÃD$ D$|pD$zpD$ $ÐUWVS$f(@|pf)$f( P|pf)$f(`|pf)$$$+$$-$$9$s $f(9${f(C$f(%@R{pf(fW(f)$s f(fW .f)$pK$f(f)D$PCD$f)$0Af(fW8f)$ Yf(+IL$ f(fW 9f(f\f)$fXf)$f( (f(fW:f(f\fXf)$$dPf(*@ D$f(fW 8f(f\f)$fXf)$f((f(fW :f(f\f)$fXf)$f( .f(fWf(f\fXf)$f()f(fW,;f(f\f)$fX苄$dPf( *@ f(fW8f(f\f)$fXf)$pf((f(fW:f(f\f)$`fXf)$Pf(f\$f($f\$f($fYf($fYf\f)$f($fYf(f($fYfXf)$f(f\$f($`f\$f($fYf($fYf\f)$f($fYf(f($fYfXf)$f(ufX$0f($@fX$ f(f\f)$@fXf($@f\$ f)$0fX$f($fX$f(fXf)$ f\f($fYf)$f($fY$ f\f)$pf(Uf\$0f)$fX$f($`fX$f(fXf)$f($fYf\f)$`f\f($fYf)$Pf($fX$f($fX$pf(fXf)$f($PfX$f(fX$f(fXf)$f($fX$f)$f\f\f($f\$f($f\$pf(fXf)$f($Pf\$f)D$f\$fXf)$f\f)$f($fXf)$f(T$f\f)$f(fX$f)$p$,f(f($@fX$f(fff(fYf(fWffYfXf)$`f($fX$f)$f($0fX$ f(fWff(f($f\f(fffYfWffYf(f\f)$Pf(H@f($fXf(fffYfWffYf(f\f)$@f($fYf($fYfXf(fWff($fYf($fYf\f(fWff($f\$f($fYf($fY$f\f(fXf\f(H0f(f\f(ff)D$ff(fYD$f)$f(fWffYf($fXf)$0f(f(fXf(ff)D$ff(fYD$f)$f(fWffYf($fXf)$ f(fXf(fff(fYf(fWffYfXf)$f(Hpf\f(fff(fYf(fWffYfXf)$f($fY$f($fY$f\f(fWff($fY$f($fY$fXf(fWff($fY$f($@f\f($f\$f($fYf(f\fXf(Hf(fXf(ff)D$ff(fYD$f)$f(fWffYf($fXf)$f(f(f\f(ff)D$ff(fYD$f)$f(fWffYf($fXf)$f(f\f(fff(fYf(fWffYfXf)$f(HPfXf(fff(fYf(%@R{pf(fWffYfXf)T$pf($`f\$Pf(f\$fX$f($f\$pf(f\$f(fWff($fXf(fWff(H f(fXf(fffYfWffYf(f\f)D$`f(f(f\f(fffYfWffYf(f\f)D$Pf(H`fXf(fffYf(fWffYf(f\f)D$@f(f\f(fffYf(fWffYf(f\f)D$0f($PfX$`f(f\$fX$f)D$ f($fX$pf($fXf(fWff(f\$f(fWff( f(f\f(fffYfWffYf\f(fXf(fffYf(fWffYf\f(f(D$ f\f(fffYfWffYf\f(f(D$ fXf(fffYfWffYf\f(D$`fX$f)*f($f\D$`fWf):f($f\fWċYf);f($pf\fWf)f(D$@fXD$pQ f)*f(D$PfX$ Af)(f($ f\D$PfWf)8fX$pf)Uf($f\fWf)>fX$f)4.f(D$pf\D$@fWf):f($PfX$ȋIf))f($@fX$0‹@f)(fX$f)+f($`f\fWĉӋRf):f($0f\$@fWf)8f(D$0fX$C f)(f($f\D$0fWf)8fX$`f)<*f($f\$PfWf)$9$$p)ǁ$,0zp$d$l9$<[^_]ÃD$ D$ |pD$ JzpD$ $RÐ D$$@"|p+ D$LYzp$+D$$@"|pj+tD$$D$b+1 fWT$$T$D+ S "|puP1ۜZсRZQ9t%Yȁ QYP9tS[u0"|p "|pY0"|p[.tسԐD$D$tËD$ D$à "|pt Ѓ t1҅u!|pLmzp!|pyzpM$"|p뽃 N"|pu +!|p!|p"|p S "|pt&M$ËD$D$[M6eMËD$$D$w[à D$$`|pD$ ÐS\$ &B$D$D$K $) D$$)Su"|pD$D$$) $E)1[D$D$$) "|pD$ D$D$$A)"|p"|p$D$C)"|p"|p$)1UWVS W %X %GƍF50#|p #|pF@#|pe[^_]ÉÁ9u Q=r -) ̋@S\$ t^ D$P7Qjj T$,RD$,P3jh@BRP2CD$ T$$*j!NbhRP 1[Ð%4Q|p% Q|p%(Q|p%Q|p%P|p%Q|p% Q|p%LQ|p%DQ|p%8Q|p%_ư>@@E-DT!@bwhpbwhp=whp@whpYwhpPwhpyhpyhphyhpkyhpyhppyhp{hpyhpzhp#zhpzhp>zhp?(dft-bluestein-%D/%D%(%p%))Lhp{}hp^hpNhphp(dft-buffered-%D%v/%D-%D%(%p%)%(%p%)%(%p%))LhphpwhpIhp׃hpfftw_dft_indirect_registerfftw_dft_indirect_transpose_registerfftw_dft_rank_geq2_registerfftw_dft_vrank_geq1_registerfftw_dft_buffered_registerfftw_dft_generic_registerfftw_dft_rader_registerfftw_dft_bluestein_registerfftw_dft_nop_registerfftw_ct_generic_registerfftw_ct_genericbuf_register޽hpzphpzphp!zphp=zpthpZzpHhpuzp0hpzp{hpzpDhpæzphp٦zpȫhpzpditdif(dft-ct-%s/%D%(%p%)%(%p%))Lhphphphp"hp(dftw-directbuf/%D-%D/%D%v "%s")(dftw-direct-%D/%D%v "%s")Yhphphp(dftw-directsq-%D/%D%v "%s")hpzhpWhpditdif(dftw-generic-%s-%D-%D%v%(%p%))^hpȣhphpA@(dftw-genericbuf/%D-%D-%D%(%p%))hphphpA@ @(dft-directbuf/%D-%D%v "%s")(dft-direct-%D%v "%s")Lhp(hphphplhp(dft-generic-%D)LhphpQhp'hpthpdft-indirect-after4hphpxzpdft-indirect-beforethp۹hpzp(%s%(%p%)%(%p%))Lhp'hpdhphpzpzphp(indirect-transpose%v%(%p%)%(%p%)%(%p%))Lhp4hphphphp(dft-nop)Lhp(hphp'hphphp.hphphpdft(dft %d %d %d %D %D %T %T)?(dft-rader-%D%ois=%oos=%(%p%)%(%p%)Lhphp hphphp(dft-rank>=2/%d%(%p%)%(%p%))Lhphp#hphpYhp(dft-vrank>=1-x%D/%d%(%p%))Lhphp7hp'hpn! @mhpDhphpn1_2zp@zp?LXz?n1_3zp$@@@zpn1_4`zp0@zp^Zu#?TDo?w??n1_5zp:@@@zpLXz??n1_6Pzp@@@@zpE{?q\˩??qM?Ku?iX2?n1_7ЭzpB@(@8@zp;f?n1_8(zpJ@@zp-RB? t??s ~:?&?LXz?M:??n1_13 8zp@a@>@C@zpE{?q\˩??qM?Ku?iX2?n1_14zpY@8@H@zp^Zu#?TDo?w??LXz??n1_150zp`@<@<@zpc}?F2k?;f?n1_16zpa@0@ @zp)f?h9;? iw?^Zu#?TDo?t1_5zpzpzp:@,@,@?LXz?t1_6XzpPzpzp@@,@,@E{?q\˩??qM?Ku?iX2?t1_7طzpзzpzpB@8@B@;f?t1_80zp(zpzpJ@2@,@-RB? t??s ~:?@>@LXz?? t1_12 zpzpzpV@>@>@^Zu#?TDo?w?LXz???t1_158zp0zpzp`@L@L@c}?F2k?;f?t1_16zpzpzpa@G@C@ i@2@,@^Zu#?TDo?w?? t2_10 pzp`zpzpS@E@C@^Zu#?TDo?w?? t2_20zpzpzpi@W@R@C?y ?%??W?ـTg?[] ?e?k[c ? U?S?Q\ ?YN ?.d?Q+<~%???^Zu#?TDo?w?? t2_25zpzpzpq@f@d@q1_2Hzp@zpzp @@@q1_4zpzpzpP@8@8@;f?q1_8zpzpzpz@b@\@LXz??q1_3tzplzpzp>@2@2@^Zu#?TDo?w??q1_5zpzpzp@`@Q@Q@?LXz?q1_6XzpPzpzph@U@U@fftw_codelet_n1_2fftw_codelet_n1_3fftw_codelet_n1_4fftw_codelet_n1_5fftw_codelet_n1_6fftw_codelet_n1_7fftw_codelet_n1_8fftw_codelet_n1_9fftw_codelet_n1_10fftw_codelet_n1_11fftw_codelet_n1_12fftw_codelet_n1_13fftw_codelet_n1_14fftw_codelet_n1_15fftw_codelet_n1_16fftw_codelet_n1_32fftw_codelet_n1_64fftw_codelet_n1_20fftw_codelet_n1_25fftw_codelet_t1_2fftw_codelet_t1_3fftw_codelet_t1_4fftw_codelet_t1_5fftw_codelet_t1_6fftw_codelet_t1_7fftw_codelet_t1_8fftw_codelet_t1_9fftw_codelet_t1_10fftw_codelet_t1_12fftw_codelet_t1_15fftw_codelet_t1_16fftw_codelet_t1_32fftw_codelet_t1_64fftw_codelet_t1_20fftw_codelet_t1_25fftw_codelet_t2_4fftw_codelet_t2_8fftw_codelet_t2_16fftw_codelet_t2_32fftw_codelet_t2_64fftw_codelet_t2_5fftw_codelet_t2_10fftw_codelet_t2_20fftw_codelet_t2_25fftw_codelet_q1_2fftw_codelet_q1_4fftw_codelet_q1_8fftw_codelet_q1_3fftw_codelet_q1_5fftw_codelet_q1_6HhpzpFhpzpahpzpohpzphpzp#hpzphp zphpzphp0zpZhpCzpipVzp ipizpip|zpipzp"ipzpq5ipzpeipzppipzpʆipzpwipzpipzpip%zp\ip7zpipIzpip[zpnipmzpipzpipzpipzpipzpipzphipzph jpzpjpzp[1jpzp2jp)zp6jp;zplAjpMzp&_jp`zpjpszpjpzpjpzpjpzpjpzpjpzpjpzpkpzpGkpzpkpzp&kp+zpditdif(rdft-ct-%s/%D%(%p%)%(%p%))ĐkpB'kp'kp'kp{(kp(dft-r2hc-%D%(%p%))Lhp-kp=-kp--kp?g-kp(dht-r2hc-%D%(%p%))Đkp0kp0kp0kp0kp(dht-rader-%D/%D%ois=%oos=%(%p%)%(%p%)Đkps5kp7kp7kp8kp(rdft-buffered-%D%v/%D-%D%(%p%)%(%p%)%(%p%))Đkpf>kp>kp>kp@?kpfftw_rdft_indirect_registerfftw_rdft_rank0_registerfftw_rdft_vrank3_transpose_registerfftw_rdft_vrank_geq1_registerfftw_rdft_nop_registerfftw_rdft_buffered_registerfftw_rdft_generic_registerfftw_rdft_rank_geq2_registerfftw_dft_r2hc_registerfftw_rdft_dht_registerfftw_dht_r2hc_registerfftw_dht_rader_registerfftw_rdft2_vrank_geq1_registerfftw_rdft2_nop_registerfftw_rdft2_rank0_registerfftw_rdft2_buffered_registerfftw_rdft2_rank_geq2_registerfftw_rdft2_rdft_registerfftw_hc2hc_generic_register3rkp@zpkp\zp@kpxzpTkpzpskpzpEkpzpUkpzpkpzp0kp%zpkp=2/%d%(%p%)%(%p%))ĐkpkpkpkpIkp?r2hchc2r(%s-dht-%D%(%p%))ĐkpIkpikpYkp@@kp(rdft-vrank>=1-x%D/%d%(%p%))Đkpckpkpskpn! @kprdft-transpose-toms513kpӧkpkpzprdft-transpose-cutkpUkpkpzprdft-transpose-gcdkpkpkp,zp(%s-%Dx%D%v)%(%p%)Đkp.kpzkp6kp@zpzpzpdkp(rdft2-buffered-%D%v/%D-%D%(%p%)%(%p%)%(%p%))0kpNkpȱkpkp(kp(rdft2-%s-direct-%D%v "%s")0kp(hpkpkpykp(rdft2-nop)0kp(hpukp'hpkp(rdft2-hc2r-rank0%(%p%))(rdft2-r2hc-rank0%v)0kpkpkpkp.kp(rdft2-rank>=2/%d%(%p%)%(%p%))0kpkpkpkpHkp?kp+kp-kpkprdft2(rdft2 %d %d %T %T)(rdft2-vrank>=1-x%D/%d%(%p%))0kpkpkp kpn! @Qkpr2hchc2r(rdft2-rdft-%s-%D%v/%D-%D%(%p%)%(%p%))0kp^kpkpkp"kpdif(rdft2-ct-%s/%D%(%p%)%(%p%))dit0kpkptkpQkpjkp(hc2c-directbuf/%D-%D/%D/%D%v "%s"%(%p%)%(%p%))(hc2c-direct-%D/%D/%D%v "%s"%(%p%)%(%p%))kp}kpDkphkphkpr2cf_2zp@zpLXz??r2cf_3,zp@??zpr2cf_4zp@zp>w?^Zu#?TDo?r2cf_5zp"@@@zp?LXz?r2cf_6pzp(@@@zpE{?q\˩??qM?Ku?iX2?r2cf_7zp(@@(@zp;f?r2cf_8Hzp4@@zp-RB?WsL? t?^o ??D /???9PϢo?LXz??r2cf_9 zp5@"@1@zp>w?TDo?^Zu#?r2cf_10 zp<@@@zpXw?Dd_7?WP͛*?(?d?B8?,?v? XL?(:/?r2cf_11 0zp4@$@D@zpLXz??r2cf_12 zpA@@@zpUUUUUU?dв`n?11?11?8 0%?M?>&?M:?M?nV?LXz?%7?E?`?G\f?յuv,J?g?LXz??r2cf_13 xzpL@.@3@zpq\˩?E{??qM?iX2?Ku?r2cf_14zpC@(@8@zpNO?LXz?TDo?^Zu#?w?A3J?,d@[?LXz???r2cf_15zpI@&@,@zpF2k?c}?;f?r2cf_16zpK@ @@zph9;?)f? inEr?u?!!?\ ]?sw?^Zu#?TDo?r2cf_20zpR@(@(@zpC?y ?C?y ?w?P/7? U?S?Q\ ?YN ??? U?S?Q\ ?YN ???ـTg?[] ?%??W?e?k[c ?.d?Q+<~%?[] ?ـTg?W?%??e?k[c ?Q+<~%?.d?^Zu#?TDo?w?^Zu#?TDo??r2cf_25zp@]@L@T@zphf_2zpzp`zp@@@LXz??hf_3tzplzp`zp$@@@hf_4zpzp`zp0@@@>w?^Zu#?TDo?hf_5Hzp@zp`zp:@,@,@?LXz?hf_6zpzp`zp@@,@,@E{?q\˩??qM?iX2?Ku?hf_78zp0zp`zpB@8@B@;f?hf_8zpzp`zpJ@2@,@@>@LXz?? hf_12 zpzp`zpV@>@>@^Zu#?TDo?w?LXz???hf_15zpzp`zp`@L@L@c}?F2k?;f?hf_16zpzp`zpa@G@C@h9;?)f?\ϗb? i@2@,@^Zu#?TDo?w?? hf2_20zpzp`zpi@W@R@C?y ? U?S?Q\ ?YN ???ـTg?[] ?%??W?e?k[c ?.d?Q+<~%?^Zu#?TDo?w?? hf2_25zpzp`zpq@f@d@r2cfII_2@zpxzp?LXzr2cfII_3zp@??xzp;f?r2cfII_4zp@@xzp>w?TDo?^Zu#?r2cfII_5zp"@@@xzpLXz??r2cfII_6zp&@@@xzpq\˩?E{??qM?iX2?Ku?r2cfII_7pzp(@@(@xzpc}?F2k?;f?r2cfII_8zp2@@@xzp c:??9PϢo?J?s ~:??D /??^o ? t?-RB?WsL?LXz??r2cfII_9 zp9@*@1@xzp^Zu#?TDo?w??r2cfII_10 zp:@@@xzp;f?;f?.! ??LXz?r2cfII_12 zpC@ @@xzpLXz?w?P/7?w?^Zu#?TDo???r2cfII_15@zpK@.@2@xzph9;?)f?\ϗb? inEr?"s?;8]+?8?\ ]?s;f?S[:XL?o?~E?;f?r2cfII_20zpU@2@0@xzpC?y ?y ?C? U?S?Q\ ?YN ???S? U?YN ?Q\ ???ـTg?[] ?W?%??k[c ?e?.d?Q+<~%?%??W?ـTg?[] ?e?k[c ?.d?Q+<~%?^Zu#?TDo?^Zu#?TDo?w??r2cfII_25pzp_@N@U@xzphc2cf_2zpzpzp@@@hc2cf_4(zp zpzp0@@@?LXz?hc2cf_6zpzpzp@@,@,@;f?hc2cf_8zpzpzpJ@2@,@^Zu#?TDo?w?? hc2cf_10 hzp`zpzpR@>@>@LXz?? hc2cf_12 zpzpzpV@>@>@c}?F2k?;f?hc2cf_16`zpXzpzpa@G@C@ i@,@^Zu#?TDo?w??? hc2cfdft_10 0{p({pzpW@C@>@>?LXz? hc2cfdft_12 {p{pzp\@G@>@F2k?c}?;f??hc2cfdft_16${p{pzpe@O@C@h9;?)f? imp {p[mp& {p!mp< {pmpR {pwmph {pmp~ {p*mp {pemp {pkmp {pmp {pmp {pmp {pfmp {pmp6 {p}mpK {p,mp` {pmpu {pmp {pmp {pnp {pnp {pQ,np {p-np {p,2np{p?LXz?LXz??r2cb_9 {p6@ @$@pzpTDo?^Zu#?w??r2cb_10 @{p:@@ @pzpWP͛*?Xw?Dd_7?(?d?v?(:/?B8?,? XL?r2cb_11 {p3@$@D@pzpLXz?r2cb_12 H{pA@@@pzp11?8 0%?M?>&?M?nV?dв`n?11?UUUUUU?M:??G\f?`?յuv,J?g?%7?E?LXz?r2cb_13 0{pL@.@4@pzpq\˩?E{??qM?iX2?Ku?r2cb_14{pB@(@:@pzpw?TDo?^Zu#?LXz?LXz??r2cb_150{pG@,@1@pzpF2k?c}?;f?r2cb_16{pK@,@@pzp)f?h9;?\ϗb? inEr?AG?5p?0~ ?_!{?:an?U?)f?h9;?\ ]?s@>@?LXz? hb_12 x"{pp"{pXzpV@>@>@w?TDo?^Zu#??LXz??hb_15"{p"{pXzp`@L@L@c}?F2k?;f?hb_16`#{pX#{pXzpa@G@C@h9;?)f?\ϗb? i^Zu#?TDo??hb_25p&{ph&{pXzp@p@a@a@hb2_4&{p&{pXzp0@ @ @;f?hb2_88'{p('{pXzpL@:@2@c}?F2k?;f? hb2_16'{p'{pXzpc@Q@D@h9;?)f?\ϗb? i@2@,@w?^Zu#?TDo?? hb2_20T){p@){pXzpi@W@R@C?y ?ـTg?[] ?%??W???k[c ?e?.d?Q+<~%? U?S?Q\ ?YN ?w?>^Zu#?TDo?? hb2_25\*{pH*{pXzpq@f@d@r2cbIII_2*{p@hzpLXz?r2cbIII_3(+{p@??hzp;f?;fr2cbIII_4+{p@@hzpw??^Zu#?TDo?r2cbIII_5,{p @@@hzpLXz?r2cbIII_6h,{p$@@@hzp?q\˩?E{?qM?iX2?Ku?r2cbIII_7,{p"@@.@hzp;f?c}?F2k?r2cbIII_8X-{p2@ @@hzp??s ~:?J?D /??LXz?LXz??r2cbIII_9 .{p6@ @$@hzpTDo?^Zu#?w??r2cbIII_10 .{p:@$@@hzp;f?LXz??r2cbIII_12 /{pC@0@@hzpLXz?LXz?NO?^Zu#?TDo?>,d@[?A3J?w??w?^Zu#?TDo?r2cbIII_15/{pH@&@.@hzp\ϗb? inEr?"s?U?:an?_!{?0~ ?h9;?)f? %L?Ak?8?;8]+?&%ѣ?,)?.?-VA?)f?h9;? i@>@?LXz? hc2cb_12 6{p6{pzpV@>@>@c}?F2k?;f?hc2cb_16`7{pX7{pzpa@G@C@h9;?)f?\ϗb? i@>@?LXz? hc2cbdft_12 ={p={pzp\@>@>@F2k?c}?;f?hc2cbdft_16 >{p>{pzpe@G@C@)f?h9;? i{p>{pzp@y@\@W@TDo?^Zu#?w??hc2cbdft_20H?{p@?{pzpl@O@O@hc2cbdft2_4?{p?{pzp8@@@;f?hc2cbdft2_8@{p@{pzpQ@2@,@F2k?c}?;f?hc2cbdft2_16@{px@{pzpe@G@C@)f?h9;? i?p>?9PϢo?9PϢo???D /??D /??J?J?s ~:?s ~:???LXz?LXz?n1fv_9 `W{p>@$@0@R{p??w?w?^Zu#?^Zu#?TDo?TDo?n1fv_10 X{pB@@@R{pXw?Xw?Dd_7?Dd_7?WP͛*?WP͛*?(?(?d?d?B8?B8?,?,?v?v? XL? XL?(:/?(:/?n1fv_11 Y{p>@$@D@R{p??LXz?LXz?n1fv_12 Y{pF@@@R{p@@UUUUUU?UUUUUU?dв`n?dв`n?11?11?M?M?nV?nV?LXz?LXz?%7?%7?E?E?`?`?G\f?G\f?յuv,J?յuv,J?g?g?11?11?8 0%?8 0%?M?M?>&?>&?M:?M:?LXz?LXz???n1fv_13 [{p@Q@.@3@R{pE{?E{?q\˩?q\˩???qM?qM?Ku?Ku?iX2?iX2?n1fv_14[{pI@(@8@R{pLXz?LXz?A3J?A3J?,d@[?,d@[?^Zu#?^Zu#?TDo?TDo???w?w?LXz?LXz?NO?NO???n1fv_15\{pP@&@,@R{pF2k?F2k?c}?c}?;f?;f?n1fv_16p]{pQ@ @@R{p inEr?>nEr?"s?"s?4i}?4i}?j"ߵ?j"ߵ? e? e?~my!?~my!?5p?5p?AG?AG?:an?:an?U?U?-VA?-VA?.?.?8?8?;8]+?;8]+? %L? %L?Ak?Ak?,)?,)?&%ѣ?&%ѣ?h9;?h9;?)f?)f? i?p>?9PϢo?9PϢo???D /??D /??J?J?s ~:?s ~:?LXz?LXz???n1bv_9 i{p>@$@0@R{p??w?w?^Zu#?^Zu#?TDo?TDo?n1bv_10 j{pB@@@R{pWP͛*?WP͛*?Xw?Xw?Dd_7?Dd_7?(?(?d?d? XL? XL?,?,?B8?B8?(:/?(:/?v?v?n1bv_11 k{p>@$@D@R{pLXz?LXz???n1bv_12 l{pF@@@R{p@@UUUUUU?UUUUUU?dв`n?dв`n?11?11?M?M?nV?nV?LXz?LXz?%7?%7?E?E?G\f?G\f?`?`?յuv,J?յuv,J?g?g?11?11?8 0%?8 0%?M?M?>&?>&?M:?M:?LXz?LXz???n1bv_13 m{p@Q@.@3@R{pq\˩?q\˩?E{?E{???Ku?Ku?iX2?iX2?qM?qM?n1bv_14`n{pI@(@8@R{pLXz?LXz?A3J?A3J?,d@[?,d@[?TDo?TDo?^Zu#?^Zu#???w?w?LXz?LXz?NO?NO???n1bv_15`o{pP@&@,@R{pc}?c}?F2k?F2k?;f?;f?n1bv_16o{pQ@ @@R{ph9;?h9;?)f?)f? inEr?>nEr?_!{?_!{?0~ ?0~ ?\ ]?\ ]?s?p>?9PϢo?9PϢo??p>?9PϢo?9PϢo??t1fv_64@{p{pR{p0}@h@J@^Zu#?^Zu#?TDo?TDo???w?w?     t1fv_20{p@{pR{p[@I@(@C?C?y ?y ?C?C?y ?y ?w?w?P/7?P/7? U? U?S?S?Q\ ?Q\ ?YN ?YN ????? U? U?S?S?Q\ ?Q\ ?YN ?YN ?????ـTg?ـTg?[] ?[] ?%??%??W?W?e?e?k[c ?k[c ?.d?.d?Q+<~%?Q+<~%?[] ?[] ?ـTg?ـTg?W?W?%??%??e?e?k[c ?k[c ?Q+<~%?Q+<~%?.d?.d?^Zu#?^Zu#?TDo?TDo?^Zu#?^Zu#?TDo?TDo???w?w?     t1fv_25Ğ{p`{pR{p@e@[@S@t2fv_24{p {pR{p@@t2fv_4{p{pR{p&@@;f?;f?t2fv_8{p {pR{p@@0@F2k?F2k?c}?c}?;f?;f?      t2fv_16{p {pR{pT@C@@h9;?h9;?)f?)f? i>>???t2fv_64@{p {pR{p0}@h@J@??w?w?^Zu#?^Zu#?TDo?TDo?t2fv_5{p{pR{p1@&@@^Zu#?^Zu#?TDo?TDo???w?w?  t2fv_10 {p{pR{pF@8@@^Zu#?^Zu#?TDo?TDo???w?w?      t2fv_20ԭ{p{pR{p[@I@(@C?C?y ?y ?C?C?y ?y ?w?w?P/7?P/7? U? U?S?S?Q\ ?Q\ ?YN ?YN ????? U? U?S?S?Q\ ?Q\ ?YN ?YN ?????ـTg?ـTg?[] ?[] ?%??%??W?W?e?e?k[c ?k[c ?.d?.d?Q+<~%?Q+<~%?[] ?[] ?ـTg?ـTg?W?W?%??%??e?e?k[c ?k[c ?Q+<~%?Q+<~%?.d?.d?^Zu#?^Zu#?TDo?TDo?^Zu#?^Zu#?TDo?TDo???w?w?      t2fv_25${p{pR{p@e@[@S@t3fv_4{p{pR{p(@ @;f?;f?t3fv_8{p{pR{pB@8@F2k?F2k?c}?c}?;f?;f? t3fv_16{p{pR{pW@N@@h9;?h9;?)f?)f? i?p>?9PϢo?9PϢo??p>?9PϢo?9PϢo??t1bv_64@{p{pR{p0}@h@J@^Zu#?^Zu#?TDo?TDo???w?w?     t1bv_20{p`{pR{p[@I@(@????????w?w?P/7?P/7?.d?.d?Q+<~%?Q+<~%?%??%??W?W?Q\ ?Q\ ?YN ?YN ?.d?.d?Q+<~%?Q+<~%?Q\ ?Q\ ?YN ?YN ?%??%??W?W?[] ?[] ?ـTg?ـTg?S?S? U? U?e?e?k[c ?k[c ?y ?y ?C?C?k[c ?k[c ?e?e?y ?y ?C?C?ـTg?ـTg?[] ?[] ?S?S? U? U?^Zu#?^Zu#?TDo?TDo?TDo?TDo???^Zu#?^Zu#?w?w?     t1bv_25{p{pR{p`e@[@@S@t2bv_2T{p@{pR{p@@t2bv_4{p{pR{p&@@;f?;f?t2bv_8{p@{pR{p@@0@c}?c}?F2k?F2k?;f?;f?      t2bv_164{p@{pR{pT@C@@ i>>???t2bv_64@4{p@{pR{p0}@h@J@??w?w?^Zu#?^Zu#?TDo?TDo?t2bv_5{p{pR{p1@&@@^Zu#?^Zu#?TDo?TDo???w?w?  t2bv_10 4{p{pR{pF@8@@^Zu#?^Zu#?TDo?TDo???w?w?      t2bv_20{p{pR{p[@I@(@????????w?w?P/7?P/7?.d?.d?Q+<~%?Q+<~%?%??%??W?W?Q\ ?Q\ ?YN ?YN ?.d?.d?Q+<~%?Q+<~%?Q\ ?Q\ ?YN ?YN ?%??%??W?W?[] ?[] ?ـTg?ـTg?S?S? U? U?e?e?k[c ?k[c ?y ?y ?C?C?k[c ?k[c ?e?e?y ?y ?C?C?ـTg?ـTg?[] ?[] ?S?S? U? U?^Zu#?^Zu#?TDo?TDo?TDo?TDo???^Zu#?^Zu#?w?w?      t2bv_25D{p{pR{p`e@[@@S@t3bv_4{p{pR{p(@ @;f?;f?t3bv_8 {p{pR{pB@8@c}?c}?F2k?F2k?;f?;f? t3bv_16{p{pR{pW@N@@ irp{p}rp{prp{p\rp{pXsp{pj(sp({pq}sp={pBspS{pǞsph{pRsp}{pCsp{p+sp{psp{psp{psp{psp{psp {psp{psp2{pͼspG{psp\{pspq{pUsp{psp{psp{p tp{p?_tp{p.htp{ptp{ptp{pցtp.{p^tpB{pXtpV{ptpj{ptp{ptp{ptp{ptp{p-tp{ptp{p_tp{p6tp{ptp%{ptp9{potpM{ptpb{p0tpw{pUtp{pDtp{pup{p!up{p:#up{pi'up{pI2up{pvNup{pup2{pDupG{pup\{pupq{pup{p[up{pȣup{phup{pZup{pup{p@up{pup{pup-{pupA{pWupU{pupi{pdup}{pVup{pup{pup{pmup{pup{pFvp{p'0vp{p|p(LwpS|p?Rwph|pRwp~|pETwp|pUwp|pKXwp|p[wp|pV_wp|pbwp|piwp |powp|pvwp3|pwpH|pwp]|p%wpr|p@wp|pwp|p;wp|pwp|p wp|pwp|pxp|pLxp|pAxp,|pCxpA|p=IxpU|pUxpj|poxp|ppxp|puxp|pxp|pxp|pxp|pxp|pxp|paxp$|pBxp9|pqxpM|pxpa|pxpu|pyp|pyp|pyp|p*yp|pUyp|pWyp|p]yp|pTjyp|p҈yp-|pypA|pnypU|p!ypi|pyp}|p(ypyp??hc2cfdftv_28 |p0 |p |p@@??hc2cfdftv_4 |p |p |p.@$@??LXz?LXz???hc2cfdftv_6h |pP |p |p;@2@@;f?;f?;f?;f???hc2cfdftv_8 |p |p |pD@7@??w?w?^Zu#?^Zu#?TDo?TDo??? hc2cfdftv_10 |p |p |pK@@@@LXz?LXz?LXz?LXz?????   hc2cfdftv_12 |p|p |pP@B@@;f?;f?;f?;f???c}?c}?F2k?F2k?     hc2cfdftv_16|p|p |pX@J@@h9;?h9;?)f?)f? i=1-x%d/%d%(%p%)Lhp`zp`zp`zpazpditdif(dft-thr-ct-%s-x%d/%D%(%p%)%(%p%))LhpfzpfzpJfzp1gzp(rdft-thr-vrank>=1-x%d/%d%(%p%)Đkp nzpnzpXnzpozpditdif(rdft-thr-ct-%s-x%d/%D%(%p%)%(%p%))ĐkpLszpszpszpztzp(rdft2-thr-vrank>=1-x%d/%d)%(%p%)0kpvzzpzzpzzpr{zp-LIBGCCW32-EH-3-SJLJ-GTHR-MINGW32/home/ron/devel/debian/mingw32/mingw32-3.4.5.20060117.1.dfsg/build_dir/src/gcc-3.4.5-20060117-1-dfsg/gcc/config/i386/w32-shared-ptr.cw32_sharedptr->size == sizeof(W32_EH_SHARED)GetAtomNameA (atom, s, sizeof(s)) != 0aJ\8(0p369u o"u u z   #{  Cu u >u u pu [ v v v w T ΀  F Y{ { | K| x ʂ } ˆ y ~ rw |  O  ^ Du mZ ? ?^Z ? >Z |? wa F bn S g /M t Z a G n S ;h yM wZ ? [ H@ rZ ? Z @ Z ? -[ [ A \ CA N\ A W@ {h i UN Li N i N M b b G b H c XH HG t^ C k P !e _J s PX _ +E l (R yf K \ A i O cc H p V n o U !p _U tp U *T ~Z #@ Q Z@QL; = L< ; < < P= < = > = = < $ ` @ 5 XZ Ȑ 'ԕ Ԓ 8 t h ؔ  @  d Ԙ H 4 X 4 $ Z Qݨ Qk8{88888889/9N9m9999999::-:B:X:q::::::;;6;Q;h;;;;;;<+<=<R<g<|<<<<<<< =!=0=@=S=g=~======>><>Z>w>>>>>>>?"???T?j?~???????@@)@=@T@l@@@@@@@ A"A9AQAhAAAAAAA B&B;BQBlBBBBBCC1CJCdC}CCCCCCC D D3DGDXDrDDDDDDDDEE*E7EHE]ErEEEEEEEF&F9FJFTF_FyFFFFFFF GG*G;GLG]GoGGGGGGGGH-HFH[HvHHHHHHI!I>I[InIIIIIIIIJJ-J@JQJ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~libfftw3-3.dllDFFTW_CLEANUP@0DFFTW_CLEANUP_THREADS@0DFFTW_DESTROY_PLAN@4DFFTW_EXECUTE@4DFFTW_EXECUTE_DFT@12DFFTW_EXECUTE_DFT_C2R@12DFFTW_EXECUTE_DFT_R2C@12DFFTW_EXECUTE_R2R@12DFFTW_EXECUTE_SPLIT_DFT@20DFFTW_EXECUTE_SPLIT_DFT_C2R@16DFFTW_EXECUTE_SPLIT_DFT_R2C@16DFFTW_EXPORT_WISDOM@8DFFTW_FLOPS@16DFFTW_FORGET_WISDOM@0DFFTW_IMPORT_SYSTEM_WISDOM@4DFFTW_IMPORT_WISDOM@12DFFTW_INIT_THREADS@4DFFTW_PLAN_DFT@28DFFTW_PLAN_DFT_1D@24DFFTW_PLAN_DFT_2D@28DFFTW_PLAN_DFT_3D@32DFFTW_PLAN_DFT_C2R@24DFFTW_PLAN_DFT_C2R_1D@20DFFTW_PLAN_DFT_C2R_2D@24DFFTW_PLAN_DFT_C2R_3D@28DFFTW_PLAN_DFT_R2C@24DFFTW_PLAN_DFT_R2C_1D@20DFFTW_PLAN_DFT_R2C_2D@24DFFTW_PLAN_DFT_R2C_3D@28DFFTW_PLAN_GURU_DFT@52DFFTW_PLAN_GURU_DFT_C2R@48DFFTW_PLAN_GURU_DFT_R2C@48DFFTW_PLAN_GURU_R2R@52DFFTW_PLAN_GURU_SPLIT_DFT@56DFFTW_PLAN_GURU_SPLIT_DFT_C2R@52DFFTW_PLAN_GURU_SPLIT_DFT_R2C@52DFFTW_PLAN_MANY_DFT@56DFFTW_PLAN_MANY_DFT_C2R@52DFFTW_PLAN_MANY_DFT_R2C@52DFFTW_PLAN_MANY_R2R@56DFFTW_PLAN_R2R@28DFFTW_PLAN_R2R_1D@24DFFTW_PLAN_R2R_2D@32DFFTW_PLAN_R2R_3D@40DFFTW_PLAN_WITH_NTHREADS@4DFFTW_PRINT_PLAN@4dfftw_cleanup_dfftw_cleanup__dfftw_cleanup_threads_dfftw_cleanup_threads__dfftw_destroy_plan_dfftw_destroy_plan__dfftw_execute_dfftw_execute__dfftw_execute_dft_dfftw_execute_dft__dfftw_execute_dft_c2r_dfftw_execute_dft_c2r__dfftw_execute_dft_r2c_dfftw_execute_dft_r2c__dfftw_execute_r2r_dfftw_execute_r2r__dfftw_execute_split_dft_dfftw_execute_split_dft__dfftw_execute_split_dft_c2r_dfftw_execute_split_dft_c2r__dfftw_execute_split_dft_r2c_dfftw_execute_split_dft_r2c__dfftw_export_wisdom_dfftw_export_wisdom__dfftw_flops_dfftw_flops__dfftw_forget_wisdom_dfftw_forget_wisdom__dfftw_import_system_wisdom_dfftw_import_system_wisdom__dfftw_import_wisdom_dfftw_import_wisdom__dfftw_init_threads_dfftw_init_threads__dfftw_plan_dft_dfftw_plan_dft_1d_dfftw_plan_dft_1d__dfftw_plan_dft_2d_dfftw_plan_dft_2d__dfftw_plan_dft_3d_dfftw_plan_dft_3d__dfftw_plan_dft__dfftw_plan_dft_c2r_dfftw_plan_dft_c2r_1d_dfftw_plan_dft_c2r_1d__dfftw_plan_dft_c2r_2d_dfftw_plan_dft_c2r_2d__dfftw_plan_dft_c2r_3d_dfftw_plan_dft_c2r_3d__dfftw_plan_dft_c2r__dfftw_plan_dft_r2c_dfftw_plan_dft_r2c_1d_dfftw_plan_dft_r2c_1d__dfftw_plan_dft_r2c_2d_dfftw_plan_dft_r2c_2d__dfftw_plan_dft_r2c_3d_dfftw_plan_dft_r2c_3d__dfftw_plan_dft_r2c__dfftw_plan_guru_dft_dfftw_plan_guru_dft__dfftw_plan_guru_dft_c2r_dfftw_plan_guru_dft_c2r__dfftw_plan_guru_dft_r2c_dfftw_plan_guru_dft_r2c__dfftw_plan_guru_r2r_dfftw_plan_guru_r2r__dfftw_plan_guru_split_dft_dfftw_plan_guru_split_dft__dfftw_plan_guru_split_dft_c2r_dfftw_plan_guru_split_dft_c2r__dfftw_plan_guru_split_dft_r2c_dfftw_plan_guru_split_dft_r2c__dfftw_plan_many_dft_dfftw_plan_many_dft__dfftw_plan_many_dft_c2r_dfftw_plan_many_dft_c2r__dfftw_plan_many_dft_r2c_dfftw_plan_many_dft_r2c__dfftw_plan_many_r2r_dfftw_plan_many_r2r__dfftw_plan_r2r_dfftw_plan_r2r_1d_dfftw_plan_r2r_1d__dfftw_plan_r2r_2d_dfftw_plan_r2r_2d__dfftw_plan_r2r_3d_dfftw_plan_r2r_3d__dfftw_plan_r2r__dfftw_plan_with_nthreads_dfftw_plan_with_nthreads__dfftw_print_plan_dfftw_print_plan__fftw_assertion_failedfftw_ccfftw_cleanupfftw_cleanup_threadsfftw_codelet_optimfftw_destroy_planfftw_estimate_costfftw_executefftw_execute_dftfftw_execute_dft_c2rfftw_execute_dft_r2cfftw_execute_r2rfftw_execute_split_dftfftw_execute_split_dft_c2rfftw_execute_split_dft_r2cfftw_export_wisdomfftw_export_wisdom_to_filefftw_export_wisdom_to_stringfftw_flopsfftw_forget_wisdomfftw_fprint_planfftw_freefftw_ifreefftw_import_system_wisdomfftw_import_wisdomfftw_import_wisdom_from_filefftw_import_wisdom_from_stringfftw_init_threadsfftw_mallocfftw_malloc_plainfftw_mkprinter_filefftw_plan_awakefftw_plan_dftfftw_plan_dft_1dfftw_plan_dft_2dfftw_plan_dft_3dfftw_plan_dft_c2rfftw_plan_dft_c2r_1dfftw_plan_dft_c2r_2dfftw_plan_dft_c2r_3dfftw_plan_dft_r2cfftw_plan_dft_r2c_1dfftw_plan_dft_r2c_2dfftw_plan_dft_r2c_3dfftw_plan_guru64_dftfftw_plan_guru64_dft_c2rfftw_plan_guru64_dft_r2cfftw_plan_guru64_r2rfftw_plan_guru64_split_dftfftw_plan_guru64_split_dft_c2rfftw_plan_guru64_split_dft_r2cfftw_plan_guru_dftfftw_plan_guru_dft_c2rfftw_plan_guru_dft_r2cfftw_plan_guru_r2rfftw_plan_guru_split_dftfftw_plan_guru_split_dft_c2rfftw_plan_guru_split_dft_r2cfftw_plan_many_dftfftw_plan_many_dft_c2rfftw_plan_many_dft_r2cfftw_plan_many_r2rfftw_plan_r2rfftw_plan_r2r_1dfftw_plan_r2r_2dfftw_plan_r2r_3dfftw_plan_with_nthreadsfftw_print_planfftw_printer_destroyfftw_set_timelimitfftw_the_plannerfftw_version@P(SPpPSPTQ`QpQQQQQQQQRR$R8RHRTR\RhRpR|RRRRRRRRRRRRTQ`QpQQQQQQQQRR$R8RHRTR\RhRpR|RRRRRRRRRRRRAddAtomA&CloseHandlePCreateMutexAXCreateSemaphoreAFindAtomAGetAtomNameAGetSystemTimeAsFileTimeuReleaseMutexvReleaseSemaphore*WaitForSingleObject$__dllonexito_assertu_beginthreadex_endthreadex_errno_iob_setjmpabort0fflush9fprintf>fread?freeGfwriteqlongjmprmallocxmemcpyymemmovezmemsetqsortsignalstrcmpPPPPPPPPPPKERNEL32.dllPPPPPPPPPPPPPPPPPPPPPmsvcrt.dll, 00*0/0Y0c0|0001 111112>K? {22[:j:V8??0,0115G;}; <3<^>>.?P(0 000r11166A9q9x9999`459;;;-<8<p41222~35666669777"8d99;;>~?00001345d8l8J99999?;F;M;Y;M?U?000(6q6F9O9[9[;;;;<=<<=>>???<333444555%6R6j66669::;;;;;V>H??850T0t0 1174J5L7T788(8^9&;.;q;<<4<-?O?W???&0M0U0A1h1p11A2_2e2s22222M3v3~34445"505L5^555566777(7F7P7\7f7r7|777777777888"8<8F8R8\8j8t88888889*929:r;;;+<8%>1>9>K>U>_>i>s>>>>>>>? ?(?2?T?o????022222233#303>3H333333344!4.4:4M444466666666 7767@7L7T7b7n77777777777888&8I8S8_8i8w888888888899 9*989B9`9j9v99999999999 ::#:4:>:J:W:u:::::::::::; ;;%;/;@;J;X;e;;;;;;;;;;;1*>4>@>J>Y>f>>>>>>>>>> ??"???I?U?a?r?????????00"010;0^0h0t00000000001$101<1K1X1u1111111111 22T222313'7?7`7h7r7z778&8.888@8888888c9y99999 : :K:S:]:e:::; ;*;2;;;;? |00222|4444g5}5555555666677,747F9\999;;; <9>>>>0000011 1(12 222C2K2U2]2/373A3I3u3}333a4i4s4{44444H5x55778 8p::::::::;;;';C;T;j;r;V====??@0i0X2222445z5X7n7777778 88>8K8U8]8888888::; ;/;7;U;b;q;~;;;;;; <#<0<:&>J>>> ???$?U?f????????P040<0F0N0111222W2_2i2q22222222393J3^3f333334+5Q5^5m5z555555666-6:6I6V666666667888888889 9/9<9m9~99999997:?:I:Q:;;;;#<4B>P>>>>>U?m????p0B0P0000111111'282W2_2t2|29333N444444M5Z5i5q5{555555C6P6_6l6{6g77%8u888999v9999999: ::l:y:::::;<;D;N;V;;;;< <>$>1>@>>>>>> ??'?4?K?X?g?t??????0000=0R00000011!1.1=11111112 2%2/2C2R2m222222(303:3N3d333333D4Q4`4m44444444455+5>5K5n5555556"616;6E6666g7~77(848Q8u888999Y;_;m;;;;;;<X>>>>>000000 11#1-191C1_1i1u1111111111 22 2,282B2]2g2s2}2222225H6u6}697L7f7~7-8=8W8_89949<9R9i99999: ::$:.:::D:P:k:::::::: ;%;E;a;;;;>>??(?0???????000U0]0g0o0000011e111X2k222F3Y3s33@4S4g4|45"545H5777888 9;1;[;d;;;;;r======>>?>U>{>>>>>>&?.?8?@???????hP0X0b0j00011 1(1b1j11111!2)2222y77777777 8888 999999999 ::':;;;h5555d7u777@9^9}993:D:o:~::::;';Q;b;;;<)=]=u======>>!>0>Q>>>>>>>>>lV00000111<1J1X1`1x111111 222&2B3o3w3L6]66677778 88#8w99999999<<=,=`t00004404A47777::::;;+;3;Y;c;r;z;;;;;g>q>>>>>>>>???r?|???1112r2|222223(393A3i3z333333344n555555 66&636]66666666666,7D7U7p7x777779%929A9N9x999999 :::B:J:[:q:y:::::::;;; ;(;7;<===>=F=P=X=====>>,>>>>>>>t00000000a1i1z111111222)2?2G2Q2Y2444445)55577I8S8a8i8s8{888888 99!9)959I:o:w:T2e22222 323@3333384N4y4444 5.5555566N6y6666#717777[999999 ::/:9:H:P:< <<"<0<8<<<<<<<>>>>>>?&?5?B?P?]? 61>1H1U1c1k11111113333 44a4n4}444445 55N5V555556666667 77(7W7q777777778=8X8s8888888929M9e9r9999$:,:6:C:R::::::';/;9;F;U;;;;;;n<{<<<<<<<<=+=:=G=r=======!>.>^>x>>>>>>>[?a?m???0Pb0051b1j12225666L=j=========>>>>P?p?????????@F1s1{1Pg1x11133=3N345"5H55566(606X6i66666667 777?7I7Q7888999V9`999999999s:{:::;> ??p$00{6666x::::U>k>>>2)2N2f25555566 6A6K6\6d666669999::(:0:V:`:o:w:::::<=N=r=====M>^>>>>>>>??.?6?c?k?u?}?00 11&1P1x111111 222,2B2J2T2\2y22222223 33~444444!5.5=5J5t5555555555 6M6g6o6y666666y88888888O9W9f9w99999: ::#:9:A:K:S:<9>a>i>s>{>>>>? ??n???p<:M:s:{:::::;;$;,;~;;;;;;&<<F>q>y>>>>>?%?/?7????h5555 66(606Q6[6l6t68"8,848@8H8888888::::; ;T;a;p;x;;;======>>$>,>B>O>F0N0X0`0n0v000000 1h1p1z11112&20282r2z23"3:3G3^3k3z333333344*424T4u444444445*5W5k555555B6J6T6a6w66666 7]7e7o7|777777788888888&9I9V9e9r99999::):<:K:c:p::::: ;%;2;;;;e<>?455 n9D333J4a47N7V7 88#8X888t99N:f::0;;;<<<7===~>>4447> (X6667777::>R?0,001125467)8H8h8::J>??+?P0h1s111p4444g5n5z5555 6<<>??`8011M1`11>2M69D:K:R:^:< <<<<<<=C=h=y=p00o00I1K2S2222335565675=Q>?@0x345$6D6a6N7$868<8E8:96;>;;;>>>h?x??? 0;0001J3R33l4t44999::):`>,2H3&47'7E:::c<==$=R>}>>>?, 111111294666777P8W9 ?$B2D4L44O5W5p59:::&=.=A?$055555588::;;43W4~999<<%==== >;>h>>>/?S?[???? 00H0s0{001j111%2-252O2W2n2z2222222222(3O3W34444^5555555566"6*646>6i6u66666666666.7W7_778?8W8_8v8888889\999X:`:j:r:~::::::::::: ;;;&;2;B;J;T;\;h;x;;;;;;;;;;;< <<">6?R????0011112 20282B2J2\2f2n2x2222 3!3+3:3D3[3e3t3304845555555556&6,6T6d6v6666666667 727B7T7d7v7778 889999:.:=:^:j:::1;D;;;;a<<<====>P>l>r?? t0O0W011 22$2,22222<3\3 4-45 5h555555555 666$838t999::;;<<==> >>%>> ?U?f?|??0l0000000000k1s1{11111202A222220383G3O333M4Y4444444 55(5F526:6D6L6r6z666z77777777888899D9Q9`9m999<,<;6Z6k6666666770888T8\88888`99=;Y;;;< >,?=?c?k?????PL0012H2Y22223*39333556F666666667L7b7v777777777868@8Q8Y888c99999:O:c:r::::::;&;5;V;`;q;y;;;;;;;< <0>F>X>?D?o??????`00-050D0e0000000012222 333%343A3P3]333333333c4k4u4}466@6O6W66666666677,747J7W7f7s777779999:!:0:=::::::c;;c=p======>m>s>>>>.?k?p|.1;1J1W1111182>2J2`2~2243455 5s5555666)6G666888;;;;;<<<<&=>==>>>>>>>1?@?e????0>0F00001z111122/272f2w2222223 3;3_3s3333333 44'4/4I4V4^4y4444445%52555566:6N6_6r666666666 7 7/7D7m7777777818I8^8d888888888 99&9N9f9t999999X:l:x::::::::;;1;=;N;X;l;t;;;;;<<<">.>B>[>>>>>>>>>>?&?@?a???????|00&0>0f00003344%4-4{4444445+5S5[5e5m555556 6k666b7u777P8c8}8889H9\9n99 ::1:<<<====00E0M0y0000Q2q2222223*3@3f3l3z33344444415?5}5555/6=66666D7q7y7A<_<<<<<<<<d>>>>>>>>>????Tj000::::%<6<[9>C>K>o>>>>>>>>??)?1?^?f?p?x?e1111V2g22222223#373?3c3m3|33333305Z5555555556&626:6I6V6e6r66666666748a8i8F;W;|;;<<<<<===d>u>>>>>>>(12"2525555%969T9e9<<<=000'0H0Y0o0w0000011*1213334&474M4U4v44444445797n77B8J8T8\888889 9/999J9R9Z9b99999999:;;;;<$>> ??@?h?u??????0 0020:0D0L0i000000000 122222333@3O3\3333333344464c4}4444444466666667~777777778"8*8;8Q8Y8a8i8A:K:; ;";3;Q;;;==>>>>>>>>'?/?7?G?W?_?g?s?\0008888 9c9{999::G:U:::::K;c;;;; <8.>6>?? 00E0V0j0r00000[2c2m2u222222233445 55#5m5z55555|7777778 8/8<8O8W8":*:4:<:J:R:::::::?;G;Q;Y;;;-<:%>9>H>c>>>>>>??G?Q?^?t?????00U0b0l0y0000000`1h1r1z111`2m2|22222223$333@3S3`33333333C4a4u444445^5d5556p66B7o7w7888;<<<@@g3333333334y555555566!667-777777PP777 8m9999::;#;2;?;y;;;;;;;<<>?7????`p0 00:0K0v0000000011'1/1222233C3K3U3]3333334)4555q7y777777777 88[888ph3333354M4s44445'5~5555!696d6v66677u7777 888c8q889 9>=>a>~>>>>>>>>?00001 1U1]1g1t111333333 444*4@4M4!626H6P6f6n6666666889 9"9*9t9|99999::!:):^:f::;;!;4;A;P;];;;;;;;;;<)1>;>H>^>>>>>>*?7?A?N?]??????70?0I0Q00071D1S1`1o1~111111 22*272j2v22222222,3O3\3o3333>4J4x44@55 696A66677;7V7^778%8-8888889E9M999:5:b:j:::;;";,;<;D;S;f;n;v;;;;;;(<0<<<<===L>j>>>>>>>>>???0?8?F?W?_?i?q????????0$0U0~00 1D1|1111111112^222333333341595555 66x66667#797C7M7_77777 88R8|8888839l9t9::;u;;P<\<9=r=z=>>u>}>>>>>>>j?t?????E0]001$1,161>1]1e1o1w1-2>2T2\2f2n22222{3344J6Y677899999999:":8:@:::::::;;";*;};;;;= =>>??11+252{2222222233>3F3U3]3}333333@4J4g4o4w4444445 55"5B5J5Y5a5555=6L6h66666/7=7H9N9o99999 :;:S:::<<<='=C=g=x===>>!0'0?0y0000 1!1k1u111n333 4L444446"636S6n66666i7s7789: :::::::3;B;\;q;{;;<<"<<<<>A>]>>>>>>>> ? ?-????d3+3R3Z3b3n3334 444m4444445#5I5Q5[5c556 6667.7777888 999999a<<<@111111122#22233333333444,4~555(090^0o011 223334444444 515\5f5w5555555666777778?8G8Q8Y8}888888889&979D9v9~999:;1;>;M;Z;;;;;;;;;<<*<7>> 8667$777<8T88899#:;:::o;;+<`>??P0001111111 212\2m22222222333x44444435;5E5M5q5555555566+636`6h6r6z677#808?8L88888888889S9c999:;;`h55556]6s66677H7V77778Q8i8888 959C99999A:Y::::1;9;;<<====????pl 0/0K0o000113 4556:4:<:X:`:j:r::::: ;;;';:;;;;;;;;;5> 0E0M0e?q???????0"0E0T0s000000#1-1>1F1j1t111111122E2O2~2222224 4/4<4f4z4444445#5h5p5x55555/676O6Y6a6y677778"8C8P8_8l8888 999)9=9E9S9999999N;;;3344B4J4R4`444445 55#5{55555555A6I6S6[66666777!7Y7a7o7{77777#8+898E88888889 9_9g9q9y99999%:Z:b:;<8<@< !0Q02H2P2:;<<> ??#4/4N4^4v44444455-5A5_5n5555556$6.6?6G6v6666666 787B7q7y7778888(9<9]9j9y99999*:2:::N:h:p::::;;#;;;z<<<<=======>c>k>}>>>>?l 00;;;;;;;;M5>C>O>>>>>>> ??n?v???????80@0J0R000000111R1Z1b1p1111\2s2{22323:33 44f4p4444&5.556;6C666677"77788H9s9{99:8:N:r:::::::::B;i;q;1>>7>K>[>s>>>>>>>> ?M?W?g?u?}?????????? 00%0;0E0S0]0H1v1~11333<4`4|444455b555555561666667(808a9k9w999999999:):3:?:I:W:_::::::::::;;;=;G;S;];i;s;;;;H<U>r>z>>>>>??$?,???? ^0t0t1z111 202Q222333677[888889+9T9\9f9n9999: :M:Z::::::;&;s;;;;;;W>u>>>>>>>>00000223,344677(70777N8p8x8888!9U9b9999999(:0:i:v:::;";G;T;f;n;;;;;)<6<<<<<(=5=\=d=====">,>=>E>>>>>??7???????@h0$0P0]0}00001'1119111112282E22224+4 535Q5b5x5555557788:$;;;)>Q>>?Pt11111122&2K2|2245"5*5=5|555555K688888888$959d9u999999999U ?????`00?0G0t00001&171?1v111111 22O2p22222233B3J3w333333R4Z4d4l44444 55?5L5555556)6D6L6y6666667*777777788E8R8s8888!9)939;9t9|99999::M:Z::::::::;';4;l;{;U7>j>t>>>>>>>> ?K?X?g?t?????p90F0s0{000001&1S1`11111 22K2\2r2z222222283E3T3a33333-4:4g4o44444 55G5T555555 6D6N6_6g66666667-78%8R8X888889;9E9:4:<:<===)=A=======8>E>T>a>p>>>>>>>?|???&0.0?0G0o00031L1T1`1h1w111111f2222222+333=3E3Q3333333?4E4V4`4p4x4444445.5C5P5Z5b5l5t5555566.6:6J6R6\6d6667 787@7J7R7r77778L8T8889[9g999:&:Q;v;~;;;<<(?;???0B0J011151C1S1e1q1111111a2q22222222233444,7F8s8{89999[99999::0:6:::::;;L;;;;>>??`00:1R1`1t111111122233.3:3R3g33444T55e:::-;H;d;;2T2223333444'4A4W444555777788;;%>>xy0011222222 3333333333y55?6r67888::::;<6>.>;>W>d>s>>????|000+011111222333333 44a5n5}5555556!7)78999;;;;>??3?d?u?????C01222;2H2R2Z222222333A3N3X3`3V7c7m7u777777X8i888888 99N99:::&:=>>>=>J>T>\>>>?=?N?t??????h00000T2n2{22222223\4v445y6666f8n8x888888v:~:::::::<<<<<>>>>0+0:0G00000%1-171?1e1m1w111111222"2x44444 55'555555555"6*646<6b6j6t6|68888O9\9k9x99999::":*:s:{:::::::=&=5=B=====>>>">H>P>Z>b>>>>>>>>>p01$18888899'9A9I9~99:::::::;-;:;f;s;<<<<<<<==2=M=h=>>V>d>x>>>>>>>? ? 0G0O0011!171A1111111>2R2c2w22222 33383333333\4m44444445)5=5N5d5l555555 686E666666667U7f7|77777 8828:8M8888888;9O9`9t9|999999 :#:::: ;&;5;;;;;;;; />E>M>x>>>>??0l00,060G0O00000_2p22222223 3a3r34444 5*5;5C55555R7`7p7x77778999-;R;Z;>@(050=0:4K4h4y4$555K8r89+9;;;PL4/444%6;6O6^6666647>7O7W7v77779X99:|;;1L>r>|>??`t000*0F0S0]0j011112202=2L2Y23333344 45555556 6o7~7-9<9:;;;;;\>m>>>>>[?j?~????0-0A0W0k0s0000011)111D1L11111 2&2N2d222222233s444444445#5u557)7?7G7k7u777778+89999: ::%:f:w:::^>>4?c?k??? 0000000D1N1v11122i2233n3x333334'4444555556@6k6s66!7O7e777777778 8Q8z889C9|9999999:::t:::%;1;S;_;;;;;<.(>p>v>>>>>???$?*?00022223G3O3h3p333333333!4?4_4g4444446666779:-:K:S:n:v:::::;%;;;;;< ">*>D>L>>>>>>>>>#?U?]?11"2324!424:4`4q4444444'585N5V5L7o778:):Z::0;;;O<[<<<<>>8>E>T>a>>>>>>>>>??$?,?P?V?l?????0 0)060E0R000000000 11F1N1^1f111^2h22222/39333333333Q4Y4g4o444444444 55&55555555 676?6K6S6|6666666777Y7h78&8a8k88888;9m9u9: :(:7:?:Y::::::;d;x;;;;;;;<< <,<<>???????0001!1-151D111111F222222293A3K3S3_3333333E4K4^4k4u4}4444444415>5M5Z5d5l5v5~5555555"6(696H6[6c6m6u6666 7737@7J7R7\7d777778Q8Y89 9::k:s:<;;;<<<<<<<<>K>S> t55566"616E6b6j6667777788(8E8R8{8899999999 :*:E:`:2;J;X;l;x;;;;;;;< =A=I=>>>0 8Z23338*8G8X8899=9P99 :%:3:<><<<~???@ @7 8889 : :/:R:h:|::;; ;(;I;S;d;l;<===.?m??P h012&202c33333334 44D5q555555556Z7g7v777777E9R9a9n99999;!;<<>>>` (99G:O:::E&>A>^>??p ` 0&0I1~11B2J2333446668:::<;<\<<<<<<<< ====>%>E>M>W>_>y>>>> $1#2+22P3v999*<@<<<== X2B2~334;5C5!7Z777999: : :_:p:::::<=%=;=C=V======E>???? 80%0-050Z0g0q0~000000 1<1M1S2b288 9d999 D0O0W05x7~77788*888889#9 J>?? t1C1K1)3b333555 66(6g6x6666789-9C9K9^999999M:;;;<%<-<5<=j> 44(5l555>>>>>>? ?>?H?q????  99::;; << $55I6Z7a7m7"8*88X:;<[<{> (0c00t1v2}22T356679N;V;><0 (`2222C5J5V5F6>7+8>r>>??@ 50P :::p a555 ;D<<.==>->>I>Q>|>>>?:?B?? x0"0*0`0n0|0071111'2522n3333333 444t66667888899&979H9Y9j9{999999;===>>%>6>? `Y1~11111122%262G2X23778;8L8:;;;;; < ,12 2G2X2i24>7c7k7777777 8> 0T2:5_5g555555566'686I6Z6k6|66 ,7< P[7L8q8y888888 99.9?9P9a9r999999999 ::-:>:O:`:q:::::P 08` -3>p 0;S=x====== `1$6I6Q6666666677$757F7W7h7y7777777788#848E8V8g8x8888888899"9 C26>>>>?Y?a???? |+0J0R00121:1p1~111:2222'3533r4444445555t777789999 ::.:?:P:a:r:::::::<>>>>?!?2? `0s222222 33,3=3N3_3p34899W9h9(;<<<=$=5=F=W=h=y========>>#>4>E>V> <3z5555566#64608;;;<07O7`7q777777777 8W> P89::K:\:m:~::::::::;;(;9;J;[;l;};;;;;;;;<<'<8 87848<8s8888k< \000O1f1n11"2=2E2s22033334455556!6267U9v9~999;<= =W=h=y====? ,373?3w3336;8\8d88888889? 0L33*6K6S6666666677$757F7W7h7y7 &8? 7888+9<9M9^9*= $1113A3I33H7p7x77770 (2P2X22222223@ ,U>}>>>>>??&?7?H?Y?j?{????? Tl666747K7S7{777z88899: :5:C:Q:_::s<<<<a>i>>>>>A? T`444405G5O5w555v666777818?8M8[88o:::::?;)=^=f=======P> H1111q2A5k5s555555566%666G6X6i6z660<]>*>;>L>]>n>>>>>>>>>??)?:?K?\?m?~???@ Q6P00888M9d9l9-:t::::001111z25$6,6U6f6w66Q<<$ 020:0s0000000]1A6=,J7E:f:n:::::$;=F=N=y===='>a4444444{5 ;dS444444455%565G5X5i5z5555555566$656F6W6h6y6666666677#747E7V77e=  50X2}444 5@5W5_55556667788A8O8]8k88:::::O;:=a=i=======M>@H1111Z25C5K5u5555555556606A6R66,>4>k>|>>>>>>>>??&?7?H?Y?? 6_= !4<6&>G>O>>>>>?d)6:::%;6;G;X;i;z;;;;;;;;<<$<5 4v?,7B7J77778899E9;;"<*,26S6[66666666 77,7=7N7_7p77  >0 u3i?@8x11111113333 44/4@4U79D9L9u9999Pd0 445'5_5p555555555 66+6<6M6^6o66666666677*7;7L7]7n777777777?`4b>>?!??p00000^1455I5Z5k55;;z?????00#040E005*=,699:):7:E:S::<<<<<= ==333%464G4X44c:d334;4L4]4n44444444455)5:5K5\5m5~5555555566(696J6[6l6}666666M7< 5,<2G4h4p4+5I5Q5C7x777===>(>9>;< >>R111189 9G9X9i9 9%:-:g:x::::::P(555s66!7)7L8R=======>`5:[:c::+?p2l9>5888[99 ::4;$:0u0}0000018<(=0=R=J25<$208; <<@=f==>+>Z>???@ 00*00373?3p333377788"838D88>?#?M?^?o???77788)8:8K88?$Y222222233'383I33:$2M<<<<<<<=='=8=I==$5b;;;;t<|<<=>">X>f>>00$1,1\1135v5~55555F68<{<<<<;=  R444444h5d=????000%060G0X00;@2999(:9:J:[::PdX48.969Z9j999::':\:|::::::::::R;; <5<=)>2>;>>>?8?G?????`8o0 1W133444Z55666667::C=W==>>pL=1E12!2:2233344C4d447<7~99W:;?;==>>>?????????0/0F0V0e00000111&1.161>1F1N1W111111122!2)222:2L2R22222222224393A3&464F4V4f4v44444444455&565F5V5f5v5555555558D00 0$0(0,0004080<0@0D0H0L0P0T0X0\0`0d0h0l0p0t0x0|00000322333,3034383<3@3D3H3L3P3T3X3\3`3d3h3l3p3t3x3|333333333333333333333333333333333444 44444 4$4(4,4044484<4@4D4H4L4P4T4X4\4`4d4h4l4t4x4|44444444555 55555 5$5(5,5T5X5\5`5x555555 7$7(7,7074787<7@7D7H7L7P7T7X7\7`7d7h7l7p7t777777888084888p8t8x8888$9(9,90989\9`9d9h9p99999999999999: :$:(:0:D:H:L:P:X:d:h:l:p::::::; ;;;(;L;P;T;X;t;;;;;$D>h>>?d??0(0d00D1h111D2h222$3H334d44d55555$6(6,666677 7d7h7l7777D8H8L8888d9h9l9999D:H:L::::d;h;l;D(>,>>>>?? ????00011 111122 233 3d3h3l3333$4(4,444455 5d5h5l5@9D9H9L9P9T9X9\9`9d9h9l9p9t9x9|999999999999999999999999999999999::: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:X:\:`:d:h:l:p:t:x:|:::::::::::::::::::::;; ;;;4;8;<;@;T;t;x;|;;;;;;;;< <$<(<0<`>d>h>l>p>t>x>|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ?$?(?,?4???????????4H0L0P00000000001111 1$1,1@1D1H1L1T1d1h1l1p1,20242822 3$3(3,3@3h3l3p3t333333333444 4$4(4@4D4H4L4h4l4p4t4x4|44444444555 55(5,50545<5t5x5|555555555555(6,60646L66666666666L7P7T77778D8h888$9H999:(:d::$;H;;;D(>>>?(???D0h011$2H233$4(4,4444444d5h5l5555D6H6L6666D7H7L7777$8(8,8888$9(9,9999:::$;(;,;$<(<,<<<<<<> >>>>?? ?00 0d0000$1H1112(2223(333D4h444d556(667D8h89(9:::::D;H;L;;;;<< <<<<== ====$>(>,>>>>?? ????00 0000$1(1,1111111d2h2l2222D3H3L3333D4H4L455 5555555d6h6l6666777D8H8L8????????000 00000 0$0(0,0004080<0@0D0H0L0P0T0X0\0`0d0h0l0p0t0x0|000000000000000000000000000000000111 11111 1$1(1,1014181<1@1D1H1L1P1T1X1\1`1d1h1l1p1t1x1|111111111111111111111111111111111222 22222 2$2(2,2024282<2@2D2H2L2P2T2X2\2`2d2h2l2p2t2x2|222222222$3H3334(4d4445D5h556d667(7d77D8h888D9h999D:h:$;H;<<$=H=$>H>>>>>>>D?H?L???? $0(0,000011 1111$2(2,222233 3333$4(4,455 5555666666D7H7L7777d8h8l8888d9h9l9::::;D;h;;;$h>>>D?h?00(000113(33344444D5H5L555566 666677 7777$8(8,888899 9999:: ::::$;(;,;;;;;;;dH>L>>>>d?h?l????@$0(0,0000D1H1L1111`9d9h9l9p9t9x9|999999999999999999999999999999999::: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:X:\:`:d:h:l:p:t:x:|:::::::::::::::::::::::::::::::::;;; ;;;;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<< <<<<<$=H=====>>>>>>>>>>>>>>>>>8?h>??`L11d22D5h555$6H666$7H777d8888:(:::;;$>??pX0(0002(2D4h44577$8H8889(9d99:(:::D;h;;;<<==d>>>>$?H???0(000$1H112d22$3H3d445(5d5555D6h67(7D8h8888$9(9,9999$:(:,::::;;;$<(<,<===D>H>L>>>>$?(?,????d$0(0,0000111$2(2,2333D4H4L4444$6(6,677 7d8h8l8:::;;;>>>D?H?L????4000$2(2,2444$:(:,:;; ;$<(<,<===|D2H2L2222$3(3,3333444D5H5L5555666d9h9l9999D:H:L::::D;H;L;;;;<<>>d?h?l????\D0H0L0000D1H1L1111222D3H3L3444d5h5l566 6D7H7L7$8(8,8999;;;<<<D00 0d0h0l0000111D3H3L366 6D;H;L;$<(<,(>,>>>>???d1h1l122233 3d3h3l344 4444d5h5l566 6666D8H8L8$9(9,9@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;;;;;;;;;;;;;;;;;;;;;` : ;I I' I : ;  : ; I8 : ; I $ >  ' .? : ; ' I@ : ; I .: ; ' @ 4: ; I.? : ; @' I@: ; I4: ; I I!4: ; I? <  /home/ron/devel/debian/mingw32-runtime/mingw32-runtime-3.13/build_dir/src/mingw-runtime-3.13-20070825-1/home/ron/devel/debian/mingw32-runtime/mingw32-runtime-3.13/build_dir/src/mingw-runtime-3.13-20070825-1/include/home/ron/devel/debian/mingw32-runtime/mingw32-runtime-3.13/build_dir/src/mingw-runtime-3.13-20070825-1/../w32api/includedllcrt1.cstdio.hstdlib.hwindef.hwinnt.hhpk/jtk0Tugzx t sadt.0/A A .text8V (.data.bss.rdata.data.bss.rdata0| .filegnop.c_applyb _printb padt.1@1_mkplanb sadt.0P1c .textb .data.bss.rdata41(.filegplan.c4c .text4c".data.bss.file3gproblem.c_padt`1_destroyXc _hashc _recur6d d kstr.01e _printe _zeroCf >g Qj ,j Cj \:k .textXc@ .data.bss.rdata`1.fileWgrank0.c_copyk uGl l m m n po -p qp .q Iq oq 4r 0s H,s Us gBt zt ru _printv padt.2,2_mkplanpv tab.0 sadt.12x .textk %.data l.bss.rdata 2.filekgrank-geq2.c_applylx _awakex _destroyx _printy padt.2 3_mkplanIy T03sadt.1<3{ .textlx .data.bss.rdata3H.filegrdft-dht.ct8| | } _awakeI~ _destroyY~ _printi~ padt.1h3_mkplan~ sadt.03 .text8|.data.bss.rdataH3D.filegsolve.c Ā .textĀ).data.bss.filegvrank-geq1.c_apply _awakec _destroys _print padt.23_mkplan T3sadt.13T .text.data.bss.rdata3L.filegvrank3-transpose.c93_adt_cut4_adt_gcd@4F Q a n yU   ӗ  _awake. _printz _destroy6 padt.2h4_mkpland adts.0x4sadt.14@ .textZ.data.bss.rdata3.filegbuffered2.cR 4t  _awakeN _destroy _printȡ padt.14_mkplan( sadt.04Ϫ .texts H.data.bss.rdata4T.filegdirect2.c_apply  t` _destroy _print padt.15_mkplany sadt.05 K .text h.data.bss.rdata48.filegnop2.c_applyt _printu padt.1(5_mkplan sadt.085) .textt .data.bss.rdata5(.file grank0-rdft2.ct, B  _awakeŰ _destroyڰ _print padt.1t5_mkplan. sadt.05V .text,.data.bss.rdataD5L.file grank-geq2-rdft2.ctԲ ; _awake _destroy _print padt.25_mkplanH T5sadt.15q .textԲ #.data.bss.rdata5H.file* gplan2.c .text".data.bss.file@ gproblem2.c_padt5_destroy _hash? _print- _recurn _vrecurl  _zero+  #  .text '.data.bss.rdata5..fileJ gsolve2.c 0 .text0=.data.bss.file^ gvrank-geq1-rdft2.c_applyp _awake _destroy  _print padt.2(6_mkplanQ T@6sadt.1H67 .textp,.data.bss.rdata6L.filer grdft2-rdft.ct  _awake^ _destroy _print padt.16_mkplan" sadt.06; .text> >.data.bss.rdataX6P.file| grU .text.data.bss.file g .text.data.bss.file grdft2-strides.ch .texth-.data.bss.file gkhc2c.c .text.data.bss.file gct-hc2c.c    F  _awake _destroyQ _printt  padt.16_mkplanj sadt.06 0 .text*.data.bss.rdata6D.file gct-hc2c-direct.c_apply8  z _dobatch#  B _awake _destroyD _print} padt.0H7_mkcldwv B .text805.data.bss.rdata6l.file ghfb.c.texth.data.bss.rdataX7.file gr2c.c.texth.data.bss.rdatah7 .file gr2r.c.texth.data.bss.rdata7.file ghc2c.c_okph .texth.data.bss.rdata7.file gr2cf_2.c_r2cf_2p _desc7^ .textpw.data.bss.rdata7P.file gr2cf_3.c_r2cf_3 _desc@8s .text.data.bss.rdata 8P.file gr2cf_4.c_r2cf_4 _desc8L .text.data.bss.rdata8P.file) gr2cf_5.c_r2cf_5p _desc 9l .textp .data.bss.rdata8p.file7 gr2cf_6.c_r2cf_6 _desc9 .text.data.bss.rdata`9P.fileE gr2cf_7.c_r2cf_7 _desc:H .text.data.bss.rdata9p.fileS gr2cf_8.c_r2cf_8l _desc`: .textlk.data.bss.rdata@:P.filea gr2cf_9.c_r2cf_9 _desc ;P .text.data.bss.rdata:.fileo gr2cf_10.c_r2cf_10t _desc; .textt/.data.bss.rdata`;p.file} gr2cf_11.c_r2cf_11 _desc@< .text6.data.bss.rdata;.file gr2cf_12.c_r2cf_12< _desc<2 .text< .data.bss.rdata<P.file gr2cf_13.c_r2cf_13 _desc=H) .textt.data.bss.rdata<.file gr2cf_14.c_r2cf_14L _desc>^ .textL#.data.bss.rdata=p.file gr2cf_15.c_r2cf_15$ _desc>t  .text$.data.bss.rdata@>.file gr2cf_16.c_r2cf_16  _desc?H .text  .data.bss.rdata>P.file gr2cf_32.c_r2cf_32l _desc? .textl[ ".data.bss.rdata@?p.file gr2cf_64.c_r2cf_64 _desc@@/ .texth.data.bss.rdata?.file gr2cf_128.c/ _descAh .text/I9#.data.bss.rdata@P.file gr2cf_20.c_r2cf_20i _desc Bm .texti.data.bss.rdataAp.file gr2cf_25.c_r2cf_25n _descC{ .textn .data.bss.rdata`B.file ghf_2.c_hf_2| _twinstrD_desc D| .text|.data.bss.rdataDP.file' ghf_3.c_hf_3| _twinstrlD_descD,} .text|%.data.bss.rdata`DP.file6 ghf_4.c_hf_4} _twinstrD_descD? .text}L.data.bss.rdataDP.fileE ghf_5.c_hf_5@ _twinstr@E_desc`ER .text@o .data.bss.rdata Ep.fileT ghf_6.c_hf_6 _twinstrE_descEe .texta .data.bss.rdataEP.filec ghf_7.c_hf_7 _twinstr0F_desc@Fx  .text(.data.bss.rdataFp.filer ghf_8.c_hf_8, _twinstrF_descFp .text,g.data.bss.rdataFP.file ghf_9.c_hf_9 _twinstr G_desc@G .textM*.data.bss.rdataF.file ghf_10.c_hf_10 _twinstrG_descG .text.data.bss.rdataGp.file ghf_12.c_hf_12 _twinstrH_desc HȜ .text7.data.bss.rdataHP.file ghf_15.c_hf_15 _twinstrH_descHj .text 1.data.bss.rdata`Hp.file ghf_16.c_hf_16 _twinstrH_desc I .text# .data.bss.rdataHp.file ghf_32.c_hf_32 _twinstrI_descIZ .textX.data.bss.rdata`I.file ghf_64.c_hf_64 _twinstrxJ_descJ .textz8.data.bss.rdataJ.file ghf_20.c_hf_20 _twinstrK_desc K)' .textN %.data.bss.rdataJp.file ghf_25.c_hf_25L _twinstrL_desc L=h' .textL?.data.bss.rdata`K.file ghf2_4.c_hf2_4' _twinstr`L_descLQ( .text'r.data.bss.rdata`LP.file ghf2_8.c_hf2_8) _twinstrL_descLe, .text).data.bss.rdataLP.file& ghf2_16.c_hf2_16- _twinstr8M_desc`My7 .text- .data.bss.rdata Mp.file5 ghf2_32.c_hf2_327 _twinstrM_descNU .text7I.data.bss.rdataM.fileD ghf2_5.c_hf2_5U _twinstr`N_descN{X .textU.data.bss.rdata@Np.fileS ghf2_20.c_hf2_20X _twinstrN_descOh .textX}%.data.bss.rdataNp.fileb ghf2_25.c_hf2_25 i _twinstrO_descP2 .text i5.data.bss.rdata@O.filep gr2cfII_2.cX _desc`P .textXq.data.bss.rdata@PP.file~ gr2cfII_3.c̆ _descP O .text̆.data.bss.rdataPP.file gr2cfII_4.c#t _desc Q- .textt.data.bss.rdataQP.file gr2cfII_5.cDD _descQN> .textD .data.bss.rdata`Qp.file gr2cfII_6.ced _descRo[ .textd.data.bss.rdataQP.file gr2cfII_7.c _descR! .text.data.bss.rdata@Rp.file gr2cfII_8.cD _descS .textD.data.bss.rdataRp.file gr2cfII_9.c _descSw .text!.data.bss.rdata@S.file gr2cfII_10.c _desc@T .text .data.bss.rdataTp.file gr2cfII_12.c  _descT* .text .data.bss.rdataTp.file gr2cfII_15.c/P _desc`U:e .textP8.data.bss.rdataU.file gr2cfII_16.cR _descV]k .text .data.bss.rdataU.file gr2cfII_32.cu _descV .text 2.data.bss.rdata@V.file& gr2cfII_64.c _desc@X .text}.data.bss.rdata WP.file4 gr2cfII_20.c _descY .textd.data.bss.rdataX.fileB gr2cfII_25.c  _descZf .text i .data.bss.rdata@Yp.fileQ ghc2cf_2.c_hc2cf_2 _twinstrZ_descZ  .text.data.bss.rdataZP.file` ghc2cf_4.c_hc2cf_4< _twinstr [_desc@[ } .text<l.data.bss.rdata [P.fileo ghc2cf_6.c_hc2cf_6 _twinstr[_desc[- , .text .data.bss.rdata[P.file~ ghc2cf_8.c_hc2cf_8X _twinstr[_desc\C  .textX.data.bss.rdata[P.file ghc2cf_10.cY  _twinstr`\_desc\c  .text8.data.bss.rdata@\p.file ghc2cf_12.cz  _twinstr\_desc]  .text .data.bss.rdata\p.file ghc2cf_16.c  _twinstrX]_desc]  .text .data.bss.rdata@]p.file ghc2cf_32.c  _twinstr]_desc ^  .textX.data.bss.rdata].file ghc2cf_20.c  _twinstr^_desc^ Q .text .data.bss.rdata`^p.file ghc2cf2_4.c | _twinstr^_desc_! .text|.data.bss.rdata^P.file ghc2cf2_8.c! _twinstrH__desc_)!," .textW.data.bss.rdata@_p.file ghc2cf2_16.c@!X" _twinstr__desc`K!, .textX" .data.bss.rdata_p.fileghc2cf2_32.cc!- _twinstrx`_desc`n!K .text-,R.data.bss.rdata@`.fileghc2cf2_20.c!0K _twinstra_desc a!"[ .text0K%.data.bss.rdata`p.file#ghc2cfdft_2.c!P[ _twinstrda_desca![ .textP[.data.bss.rdata`aP.file2ghc2cfdft_4.c!$\ _twinstra_desca!] .text$\.data.bss.rdataaP.fileAghc2cfdft_6.c!] _twinstr8b_desc`b!a .text]P .data.bss.rdata bp.filePghc2cfdft_8.c",a _twinstrb_descb$"e .text,a.data.bss.rdatabP.file_ghc2cfdft_10.c="f _twinstr(c_desc@cJ"3m .textfJ$.data.bss.rdatacp.filenghc2cfdft_12.cd"`m _twinstrc_desccq"pu .text`m;.data.bss.rdatacp.file}ghc2cfdft_16.c"u _twinstrd_desc@d"6 .textu .data.bss.rdatadp.fileghc2cfdft_32.c"d _twinstrd_desce"{ .textdB`.data.bss.rdatad.fileghc2cfdft_20.c" _twinstrhe_desce"K .textD.data.bss.rdata@ep.fileghc2cfdft2_4.c#x _twinstre_desce #) .textx.data.bss.rdataeP.fileghc2cfdft2_8.c'#T _twinstr,f_desc`f4#9 .textT.data.bss.rdata fp.fileghc2cfdft2_16.cN#d _twinstrf_descf\# .textd .data.bss.rdatafp.fileghc2cfdft2_32.cw#( _twinstrpg_descg# .text( X.data.bss.rdata g.fileghc2cfdft2_20.c#( _twinstrh_desc@h# .text(D.data.bss.rdatag.filegcodlist.c.text.data.bss.rdatah .filegr2cb_2.c_r2cb_2 _descr#l .text{.data.bss.rdatarP.file gr2cb_3.c_r2cb_3 _desc s#+ .text.data.bss.rdatasP.filegr2cb_4.c_r2cb_4P _descs# .textP.data.bss.rdata`sP.file(gr2cb_5.c_r2cb_5( _desct$ .text(.data.bss.rdatasp.file6gr2cb_6.c_r2cb_6D _desc`t$4 .textD.data.bss.rdata@tP.fileDgr2cb_7.c_r2cb_7X _desct2$ .textX .data.bss.rdatatp.fileRgr2cb_8.c_r2cb_8 _desc@uG$l .texts.data.bss.rdata uP.file`gr2cb_9.c_r2cb_9 _descu\$b .text.data.bss.rdatau.filengr2cb_10.c_r2cb_10 _desc`vq$p .text .data.bss.rdata vp.file|gr2cb_11.c_r2cb_11 _descw$o .text*.data.bss.rdatav.filegr2cb_12.c_r2cb_12 _desc`w$ .text>.data.bss.rdata@wP.filegr2cb_13.c_r2cb_13 _desc@x$! .textp.data.bss.rdataw.filegr2cb_14.c_r2cb_14D _descx$  .textD(.data.bss.rdataxp.filegr2cb_15.c_r2cb_15  _desc@y$ .text .data.bss.rdatayp.filegr2cb_16.c_r2cb_16 _descy$ .text+ .data.bss.rdatayP.filegr2cb_32.c_r2cb_32 _desc@z %O .textZ (.data.bss.rdatay.filegr2cb_64.c_r2cb_64t _desc {!%2 .texttcr.data.bss.rdataz.filegr2cb_128.c7%2 _desc|A%-j .text2x78.data.bss.rdata`{p.filegr2cb_20.c_r2cb_20Pj _desc }X%o .textPjz.data.bss.rdata|p.filegr2cb_25.c_r2cb_25o _desc ~n%Ex .textoS.data.bss.rdata`}.fileghb_2.c_hb_2hx _twinstr`~_desc~%x .texthx.data.bss.rdata`~P.file&ghb_3.c_hb_3y _twinstr~_desc~%z .texty".data.bss.rdata~P.file5ghb_4.c_hb_4.data.bss.fileg0/-  .text- >.data.bss.filegG0/0P-  .textP- 2.data.bss.filegexecute.c[0-  .text- .data.bss.fileg0i0-  .text- 0.data.bss.fileg00-  0-  0-  .text- .data.bss.file(gexport-wisdom.c0.  0.  .text. }.data.bss.filegf77api.c10/  1S/  (1|/  91/  O1/  `1/  w1/  1/  10  1#0  1H0  1W0  11   2C1  "21  721  N23  e2+5  26  27  2H7  27  28  2X8  38  .3_:  I3;  j3/=  3y=  3=  3U>  3>  3>  4?  4@  94(B  Z4C  s4C  4*D  4 E  4_E  4E  4F  4PH  5J  &5>J  65^J  K5mJ  [5rJ  q5wJ  5J  5J  5J  5 K  5K  5K  6L  6NL  (6L  >6tN  T6O  p6wQ  6Q  6 R  6R  6R  6S  6cS  7!U  /7yV  O7W  g7;X  7{X  7Y  7LY  7Y  7Y  7[  8\  68b^  N8^  l8^  }8_  8!`  8t`  8`  8c  8d  8e   9"e   99e  19>e  H9Ce  _9pe  w9e  9e  9e  9 f  9f  9f  9g  :rg  &:h  >:i  \:j  r:#k  :Yk  :k  : l  :Kl  :l  ;m  +;n  M;o  g;p  ;Tp  ;p  ;q  ;Fq  ;q  <r  $<s  F<t  `< u  <Ou  <v  <^v  <v  <w  <x  =z  .text0/  K;.data.bss.filegflops.c=|  >|  .text| h.data.bss.filegmalloc.c2>|  ?>|  .text|  .data.bss.file gmap-r2r-kind.cJ>|  .text| .data.bss.rdataȰ, .filegmapflags.c]>}  .text} # .data.bss.rdata.file#gmkprinter-file.cl>  v>~  >Ȁ  .text .data0.bss.file.gmktensor-iodims.c>  >t  .text .data0.bss.file9g>>ԁ  >_  .textԁ .data0.bss.fileCgplan-dft-1d.c>  .text ;.data0.bss.fileMgplan-dft-2d.c?Ԃ  .textԂ K.data0.bss.fileWgplan-dft-3d.c"?  .text S.data0.bss.fileagplan-dft-c2r-1d.c4?t  .textt 3.data0.bss.filekgplan-dft-c2r-2d.cJ?  .text C.data0.bss.fileugplan-dft-c2r-3d.c`?  .text K.data0.bss.filegplan-dft-c2r.cv?8  .text8 k.data0.bss.filegplan-dft-r2c-1d.c?  .text 3.data0.bss.filegplan-dft-r2c-2d.c?؄  .text؄ C.data0.bss.filegplan-dft-r2c-3d.c?  .text K.data0.bss.filegplan-dft-r2c.c?h  .texth k.data0.bss.filegplan-dft.c?ԅ  .textԅ s.data0.bss.fileg@?H  .textH K .data0.bss.fileg1@@  .text > .data0.bss.filegplan-guru-dft.cE@Ԉ  .textԈ ^ .data0.bss.filegplan-guru-r2r.cY@4  .text4 " .data0.bss.fileg@m@X  .textX _.data0.bss.fileg@@  .text T.data0.bss.fileg@@  .text  .data0.bss.fileg%A A  .text  .data0.bss.file gQA9A  .text  .data0.bss.filegplan-many-dft.ceA4  .text4 z .data0.bss.filegplan-many-r2r.cyA  .text 7 .data0.bss.file)gplan-r2r-1d.cA  .text ;.data0.bss.file3gplan-r2r-2d.cA$  .text$ [.data0.bss.file=gplan-r2r-3d.cA  .text k.data0.bss.fileGgplan-r2r.cA  .text s.data0.bss.fileRgprint-plan.cA`  A  .text` _.data0.bss.file\grdft2-pad.cA  .text .data0.bss.fileigthe-planner.c_plnrB  B  %Bݘ  .text g.data0.bss.filesgversion.c.text .data0.bss .rdata .file}gSB9B  .text K .data0.bss .filegBiB@  .text@ > .data0.bss .filegplan-guru64-dft.cB  .text ^ .data0.bss .filegplan-guru64-r2r.cB  .text " .data0.bss .filegBB  .text _.data0.bss .fileg!CCd  .textd T.data0.bss .filegYC=C  .text  .data0.bss .filegCqCd  Cܢ  .textd .data0.bss .filegsse.c.text< .data0.bss .filegsse2.cC<  .text< :.data0.bss .rdata@F.filegn1b.c_okpx  .textx .data0.bss .rdata.filegn1f.c_okp\  .text\ .data0.bss .rdata.filegn2b.c_okp@  .text@ .data0.bss .rdata.filegn2f.c_okp  .text .data0.bss .rdata.filegn2s.c_okp  .text ).data0.bss .rdata.file gq1b.c_okp  .text .data0.bss .rdata.file,gq1f.c_okp  .text .data0.bss .rdata.file=gt.c_okp_t1f\  C  _okp_t1b  C/  _okp_t2fЫ  _okp_t2bu  .text\ .data0.bss .rdataȲ0.fileIgts.c_okp  .text .data0.bss .rdata.fileWgn1fv_2.c_n1fv_2ܭ  _desc CB  .textܭ .data0.bss .rdata`.fileggn1fv_3.c_var.0`_var.1p_n1fv_3h  _descC3  .texth .data0.bss .rdata`.fileugn1fv_4.c_n1fv_4X  _descD  .textX .data0.bss .rdata`.filegn1fv_5.c_var.0@_var.1P_var.2`_var.3p_n1fv_5@  _desc&D  .text@  .data0.bss .rdata@.filegn1fv_6.c_var.0_var.1_n1fv_6  _desc ;D  .text .data0.bss .rdata.filegn1fv_7.c_var.0`_var.1p_var.2_var.3_var.4_var.5_n1fv_7  _descPD  .text   .data0.bss .rdata`.filegn1fv_8.c_var.0 _n1fv_8  _desc@eD  .text .data0.bss .rdata `.filegn1fv_9.c_var.0_var.1_var.2_var.3_var.4_var.5ж_var.6_var.7_var.8_var.9_var.10 _var.110_var.12@_var.13P_n1fv_9и  _desczD  .textи .data0.bss .rdata@.filegn1fv_10.c_var.0_var.1з_var.2_var.3_n1fv_10  _desc Dw  .text  .data0.bss .rdata.filegn1fv_11.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_var.7и_var.8_var.9_n1fv_11  _desc D  .text y.data0.bss .rdata`.filegn1fv_12.c_var.0`_var.1p_n1fv_12  _descD  .text .data0.bss .rdata`.file2gn1fv_13.c_var.0_var.1_var.2_var.3_var.4 _var.50_var.6@_var.7P_var.8`_var.9p_var.10_var.11_var.12_var.13_var.14_var.15к_var.16_var.17_var.18_var.19_n1fv_13  _desc@D>  .text .data0.bss .rdata.fileFgn1fv_14.c_var.0_var.1_var.2_var.3_var.4_var.5л_n1fv_14d  _descD}  .textd < .data0.bss .rdata.file^gn1fv_15.c_var.0@_var.1P_var.2`_var.3p_var.4_var.5_var.6_var.7_var.8_var.9м_n1fv_15  _descD  .text .data0.bss .rdata@.fileogn1fv_16.c_var.0@_var.1P_var.2`_n1fv_16$  _descE\  .text$ [.data0.bss .rdata@.filegn1fv_32.c_var.0_var.1н_var.2_var.3_var.4_var.5_var.6 _n1fv_32  _desc@)EX  .text  .data0.bss .rdata.filegn1fv_64.c_var.0_var.1_var.2_var.3_var.4_var.5о_var.6_var.7_var.8_var.9_var.10 _var.110_var.12@_var.13P_var.14`_n1fv_64|  _desc?Ej  .text| #.data0.bss .rdata@.filegn1fv_128.c_var.0_var.1п_var.2_var.3_var.4_var.5_var.6 _var.70_var.8@_var.9P_var.10`_var.11p_var.12_var.13_var.14_var.15_var.16_var.17_var.18_var.19_var.20_var.21_var.22 _var.230_var.24@_var.25P_var.26`_var.27p_var.28_var.29_var.30UE  _desc_Eqm  .text U).data0.bss .rdata@.filegn1fv_20.c_var.0_var.1_var.2 _var.30_n1fv_20m  _desc`vEBv  .textm  .data0.bss .rdata.filegn1fv_25.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6_var.7_var.8 _var.90_var.10@_var.11P_var.12`_var.13p_var.14_var.15_var.16_var.17_var.18_var.19_var.20_var.21_var.22_var.23_var.24 _var.250_var.26@_var.27P_var.28`_var.29p_var.30_var.31_var.32_var.33_var.34_var.35_var.36_var.37_var.38_var.39_n1fv_25hv  _desc@Eǎ  .texthv ..data0.bss .rdata.file$gn1bv_2.c_n1bv_2  _descER  .text .data0.bss .rdata`.file4gn1bv_3.c_var.0_var.1_n1bv_3x  _desc EC  .textx .data0.bss .rdata.fileBgn1bv_4.c_n1bv_4h  _descE+  .texth .data0.bss .rdata``.fileTgn1bv_5.c_var.0_var.1_var.2_var.3_n1bv_5P  _desc E  .textP  .data0.bss .rdata.filedgn1bv_6.c_var.0`_var.1p_n1bv_6  _descE  .text .data0.bss .rdata`.filexgn1bv_7.c_var.0_var.1_var.2_var.3_var.4 _var.50_n1bv_7  _desc` F  .text  .data0.bss .rdata.filegn1bv_8.c_var.0_n1bv_8  _desc F  .text .data0.bss .rdata`.filegn1bv_9.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_var.6`_var.7p_var.8_var.9_var.10_var.11_var.12_var.13_n1bv_9ؙ  _desc5F  .textؙ .data0.bss .rdata@.filegn1bv_10.c_var.0@_var.1P_var.2`_var.3p_n1bv_10ܞ  _descJF  .textܞ  .data0.bss .rdata@.filegn1bv_11.c_var.0_var.1_var.2_var.3_var.4 _var.50_var.6@_var.7P_var.8`_var.9p_n1bv_11  _desc`F  .text .data0.bss .rdata.filegn1bv_12.c_var.0_var.1_n1bv_124  _desc vFͬ  .text4 .data0.bss .rdata.filegn1bv_13.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12 _var.130_var.14@_var.15P_var.16`_var.17p_var.18_var.19_n1bv_13  _descF  .text .data0.bss .rdata`.filegn1bv_14.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_n1bv_14  _descFػ  .text ? .data0.bss .rdata.file+gn1bv_15.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6 _var.70_var.8@_var.9P_n1bv_15  _descFU  .text |.data0.bss .rdata.file<gn1bv_16.c_var.0_var.1_var.2_n1bv_16x  _descF  .textx D.data0.bss .rdata.fileQgn1bv_32.c_var.0@_var.1P_var.2`_var.3p_var.4_var.5_var.6_n1bv_32  _descF  .text ) .data0.bss .rdata@.filengn1bv_64.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_var.6`_var.7p_var.8_var.9_var.10_var.11_var.12_var.13_var.14_n1bv_64  _descF  .text <#.data0.bss .rdata@.filegn1bv_128.c_var.0@_var.1P_var.2`_var.3p_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12_var.13_var.14 _var.150_var.16@_var.17P_var.18`_var.19p_var.20_var.21_var.22_var.23_var.24_var.25_var.26_var.27_var.28_var.29_var.30 G$  _desc@G?O  .text$ >U).data0.bss .rdata@@.filegn1bv_20.c_var.0_var.1_var.2_var.3_n1bv_20dO  _desc1G.X  .textdO  .data0.bss .rdata.filegn1bv_25.c_var.0 _var.10_var.2@_var.3P_var.4`_var.5p_var.6_var.7_var.8_var.9_var.10_var.11_var.12_var.13_var.14_var.15_var.16 _var.170_var.18@_var.19P_var.20`_var.21p_var.22_var.23_var.24_var.25_var.26_var.27_var.28_var.29_var.30_var.31_var.32 _var.330_var.34@_var.35P_var.36`_var.37p_var.38_var.39_n1bv_25TX  _descGGp  .textTX P..data0.bss .rdata .filegn2fv_2.c_n2fv_2p  _desc ]Gp  .textp ~.data0.bss .rdata`.filegn2fv_4.c_n2fv_4$q  _descrGq  .text$q .data0.bss .rdata``.filegn2fv_6.c_var.0_var.1_n2fv_6q  _descG^s  .textq .data0.bss .rdata.filegn2fv_8.c_var.0@_n2fv_8s  _desc`GXu  .texts .data0.bss .rdata@`.file0gn2fv_10.c_var.0_var.1_var.2_var.3_n2fv_10|u  _descGx  .text|u  .data0.bss .rdata.file@gn2fv_12.c_var.0@_var.1P_n2fv_12y  _descG|  .texty .data0.bss .rdata@.fileTgn2fv_14.c_var.0_var.1_var.2_var.3_var.4_var.5_n2fv_14|  _desc@G  .text|  .data0.bss .rdata.fileegn2fv_16.c_var.0_var.1_var.2_n2fv_16Ȃ  _descG  .textȂ .data0.bss .rdata.filezgn2fv_32.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_var.6`_n2fv_32  _desc H  .text  .data0.bss .rdata.filegn2fv_64.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6 _var.70_var.8@_var.9P_var.10`_var.11p_var.12_var.13_var.14_n2fv_64̕  _descH-  .text̕ ".data0.bss .rdata@.filegn2fv_20.c_var.0_var.1_var.2 _var.30_n2fv_20P  _desc`5H  .textP  .data0.bss .rdata.filegn2bv_2.c_n2bv_2  _descKH_  .text ~.data0.bss .rdata`.filegn2bv_4.c_n2bv_4  _desc `H6  .text .data0.bss .rdata`.filegn2bv_6.c_var.0`_var.1p_n2bv_6\  _descuH  .text\ .data0.bss .rdata`.filegn2bv_8.c_var.0_n2bv_8  _descH  .text .data0.bss .rdata`.filegn2bv_10.c_var.0@_var.1P_var.2`_var.3p_n2bv_10  _descHo  .text  .data0.bss .rdata@.filegn2bv_12.c_var.0_var.1_n2bv_12  _desc H  .text .data0.bss .rdata.filegn2bv_14.c_var.0`_var.1p_var.2_var.3_var.4_var.5_n2bv_144  _descH0  .text4  .data0.bss .rdata`.file+gn2bv_16.c_var.0 _var.10_var.2@_n2bv_16T  _desc`HU  .textT $.data0.bss .rdata .file@gn2bv_32.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6_n2bv_32x  _desc HD  .textx  .data0.bss .rdata.file]gn2bv_64.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12 _var.130_var.14@_n2bv_64h  _desc` I  .texth ".data0.bss .rdata`@.fileogn2bv_20.c_var.0_var.1_var.2_var.3_n2bv_20  _desc#I  .text  .data0.bss .rdata.file}gn2sv_4.c_n2sv_4  _desc`9I:  .text .data0.bss .rdata@`.filegn2sv_8.c_var.0_n2sv_8`  _descNIi  .text` ,.data0.bss .rdata`.filegn2sv_16.c_var.0_var.1_var.2 _n2sv_16  _desc@cII"  .text  .data0.bss .rdata.filegn2sv_32.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6_n2sv_32l"  _descyIv>  .textl" - .data0.bss .rdata.filegn2sv_64.c_var.0@_var.1P_var.2`_var.3p_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12_var.13_var.14 _n2sv_64>  _desc@I  .text> H.data0.bss .rdata@@.filegt1fuv_2.c_t1fuv_2  _twinstr_descID  .text .data0.bss .rdata`.filegt1fuv_3.c_var.0_var.1_t1fuv_3h  _twinstr_desc I  .texth L.data0.bss .rdata.filegt1fuv_4.c_t1fuv_4  _twinstr`_descI  .text j.data0.bss .rdata``.filegt1fuv_5.c_var.0_var.1_var.2_var.3_t1fuv_5  _twinstr_desc I  .text  .data0.bss .rdata.file"gt1fuv_6.c_var.0`_var.1p_t1fuv_6  _twinstr_descI[  .text .data0.bss .rdata`.file7gt1fuv_7.c_var.0_var.1_var.2_var.3_var.4 _var.50_t1fuv_7  _twinstr@_descJȓ  .text k .data0.bss .rdata.fileGgt1fuv_8.c_var.0_t1fuv_8  _twinstr_desc )Jh  .text .data0.bss .rdata.filedgt1fuv_9.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12 _var.130_t1fuv_9  _twinstr@_desc?JZ  .text .data0.bss .rdata``.filewgt1fuv_10.c_var.0_var.1_var.2_var.3UJ  _twinstr_desc@_J  .text ) .data0.bss .rdata.filegt1fv_2.c_t1fv_2  _twinstr_descvJ@  .text .data0.bss .rdata`.filegt1fv_3.c_var.0_var.1_t1fv_3d  _twinstr_desc J  .textd L.data0.bss .rdata.filegt1fv_4.c_t1fv_4  _twinstr`_descJ  .text j.data0.bss .rdata``.filegt1fv_5.c_var.0_var.1_var.2_var.3_t1fv_5  _twinstr_desc J  .text  .data0.bss .rdata.filegt1fv_6.c_var.0`_var.1p_t1fv_6  _twinstr_descJW  .text .data0.bss .rdata`.filegt1fv_7.c_var.0_var.1_var.2_var.3_var.4 _var.50_t1fv_7|  _twinstr@_descJı  .text| k .data0.bss .rdata.filegt1fv_8.c_var.0_t1fv_8  _twinstr_desc Jd  .text .data0.bss .rdata.file gt1fv_9.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_var.7_var.8_var.9_var.10_var.11_var.12 _var.130_t1fv_9  _twinstr@_desc KV  .text .data0.bss .rdata``.filegt1fv_10.c_var.0_var.1_var.2_var.3_t1fv_10|  _twinstr_desc@K  .text| ) .data0.bss .rdata.file0gt1fv_12.c_var.0_var.1_t1fv_12  _twinstr_desc4K  .text .data0.bss .rdata.fileIgt1fv_15.c_var.0 _var.10_var.2@_var.3P_var.4`_var.5p_var.6_var.7_var.8_var.9_t1fv_158  _twinstr_desc JKm  .text8 X .data0.bss .rdata @.file[gt1fv_16.c_var.0`_var.1p_var.2_t1fv_16  _twinstr_desc`K  .text  .data0.bss .rdata`.fileqgt1fv_32.c_var.0@_var.1P_var.2`_var.3p_var.4_var.5_var.6_t1fv_32(  _twinstr_desc`vKF  .text( A.data0.bss .rdata@`.filegt1fv_64.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6_var.7_var.8 _var.90_var.10@_var.11P_var.12`_var.13p_var.14_t1fv_64l  _twinstr_descK'  .textl /.data0.bss .rdata`.filegt1fv_20.c_var.0_var.1_var.2 _var.30_t1fv_20L  _twinstr@_descK, .textL  .data0.bss .rdata.filegt1fv_25.c_var.0_var.1_var.2_var.3_var.4 _var.50_var.6@_var.7P_var.8`_var.9p_var.10_var.11_var.12_var.13_var.14_var.15_var.16_var.17_var.18_var.19_var.20 _var.210_var.22@_var.23P_var.24`_var.25p_var.26_var.27_var.28_var.29_var.30_var.31_var.32_var.33_var.34_var.35_var.36 _var.370_var.38@_var.39P_t1fv_25, _twinstr`_descKH .text,/.data0.bss .rdata@.filegt2fv_2.c_t2fv_2H _twinstr _desc@K]I .textH.data0.bss .rdata `.filegt2fv_4.c_t2fv_4I _twinstr_descKJ .textI-.data0.bss .rdata.file gt2fv_8.c_var.0_t2fv_8J _twinstr _descKM .textJ.data0.bss .rdata.file gt2fv_16.c_var.0_var.1_var.2_t2fv_16M _twinstr _desc  LU .textM.data0.bss .rdata.file/ gt2fv_32.c_var.0`_var.1p_var.2_var.3_var.4_var.5_var.6_t2fv_32U _twinstr_desc#Lg .textU' .data0.bss .rdata`.fileM gt2fv_64.c_var.0 _var.10_var.2@_var.3P_var.4`_var.5p_var.6_var.7_var.8_var.9_var.10_var.11_var.12_var.13_var.14_t2fv_64g _twinstr _desc 9Lޒ .textg+.data0.bss .rdata @.file` gt2fv_5.c_var.0` _var.1p _var.2 _var.3 _t2fv_5 _twinstr _desc OL .text> .data0.bss .rdata` .files gt2fv_10.c_var.0@ _var.1P _var.2` _var.3p _t2fv_10D _twinstr _desc dL .textDz .data0.bss .rdata@  .file gt2fv_20.c_var.0` _var.1p _var.2 _var.3 _t2fv_20 _twinstr _desc zLW .text .data0.bss .rdata` .file gt2fv_25.c_var.0 _var.10_var.2@_var.3P_var.4`_var.5p_var.6_var.7_var.8_var.9_var.10_var.11_var.12_var.13_var.14_var.15_var.16 _var.170_var.18@_var.19P_var.20`_var.21p_var.22_var.23_var.24_var.25_var.26_var.27_var.28_var.29_var.30_var.31_var.32 _var.330_var.34@_var.35P_var.36`_var.37p_var.38_var.39_t2fv_25| _twinstr_desc@L/ .text|/.data0.bss .rdata `.file gt3fv_4.c_t3fv_4T _twinstr_descL .textT.data0.bss .rdata`.file gt3fv_8.c_var.0_t3fv_8 _twinstr_desc L .text`.data0.bss .rdata.file gt3fv_16.c_var.0`_var.1p_var.2_t3fv_16@ _twinstr_descL+ .text@ .data0.bss .rdata`.file!gt3fv_32.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_var.6`_t3fv_32P _twinstrp_descL_ .textP2.data0.bss .rdata.file!gt3fv_5.c_var.0_var.1_var.2_var.3_t3fv_5 _twinstr _desc@L? .text .data0.bss .rdata.file*!gt3fv_10.c_var.0_var.1_var.2_var.3_t3fv_10d _twinstr_descM .textdF .data0.bss .rdata.file=!gt3fv_20.c_var.0 _var.10_var.2@_var.3P_t3fv_20 _twinstr`_desc'My .text .data0.bss .rdata .filet!gt3fv_25.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6 _var.70_var.8@_var.9P_var.10`_var.11p_var.12_var.13_var.14_var.15_var.16_var.17_var.18_var.19_var.20_var.21_var.22 _var.230_var.24@_var.25P_var.26`_var.27p_var.28_var.29_var.30_var.31_var.32_var.33_var.34_var.35_var.36_var.37_var.38 _var.390_t3fv_25 _twinstr@_desc`=M$ .text 0.data0.bss .rdata.file!gt1buv_2.c_t1buv_2$ _twinstr_descSMP% .text$.data0.bss .rdata`.file!gt1buv_3.c_var.0_var.1_t1buv_3t% _twinstr _desc@iM& .textt%L.data0.bss .rdata.file!gt1buv_4.c_t1buv_4& _twinstr_descM( .text&j.data0.bss .rdata`.file!gt1buv_5.c_var.0_var.1_var.2_var.3_t1buv_5,( _twinstr _desc@M* .text,( .data0.bss .rdata.file!gt1buv_6.c_var.0_var.1_t1buv_6* _twinstr_descMZ- .text*.data0.bss .rdata.file!gt1buv_7.c_var.0_var.1_var.2 _var.30_var.4@_var.5P_t1buv_7- _twinstr`_descM1 .text-Q .data0.bss .rdata.file!gt1buv_8.c_var.0_t1buv_81 _twinstr_desc@M<5 .text1.data0.bss .rdata.file "gt1buv_9.c_var.0_var.1_var.2_var.3_var.4_var.5_var.6_var.7_var.8_var.9_var.10 _var.110_var.12@_var.13P_t1buv_9`5 _twinstr`_descM(< .text`5.data0.bss .rdata`.file"gt1buv_10.c_var.0_var.1_var.2_var.3NL< _twinstr _desc` N?B .textL< .data0.bss .rdata.file+"gt1bv_2.c_t1bv_2dB _twinstr_desc$NB .textdB.data0.bss .rdata`.file<"gt1bv_3.c_var.0 _var.1 _t1bv_3C _twinstr _desc@ 9NED .textCL.data0.bss .rdata .fileK"gt1bv_4.c_t1bv_4hD _twinstr _desc NNE .texthDj.data0.bss .rdata `.file^"gt1bv_5.c_var.0 _var.1 _var.2!_var.3!_t1bv_5E _twinstr !_desc@!cNKH .textE .data0.bss .rdata .fileo"gt1bv_6.c_var.0!_var.1!_t1bv_6pH _twinstr!_desc!xNK .textpH.data0.bss .rdata!.file"gt1bv_7.c_var.0"_var.1"_var.2 "_var.30"_var.4@"_var.5P"_t1bv_7(K _twinstr`"_desc"NVO .text(KQ .data0.bss .rdata".file"gt1bv_8.c_var.0"_t1bv_8|O _twinstr#_desc@#NR .text|O.data0.bss .rdata".file"gt1bv_9.c_var.0#_var.1#_var.2#_var.3#_var.4#_var.5#_var.6#_var.7#_var.8$_var.9$_var.10 $_var.110$_var.12@$_var.13P$_t1bv_9S _twinstr`$_desc$NY .textS.data0.bss .rdata#`.file"gt1bv_10.c_var.0$_var.1$_var.2%_var.3%_t1bv_10Y _twinstr %_desc`%N_ .textY .data0.bss .rdata$.file"gt1bv_12.c_var.0%_var.1%_t1bv_12 ` _twinstr%_desc&Nf .text `.data0.bss .rdata%.file"gt1bv_15.c_var.0@&_var.1P&_var.2`&_var.3p&_var.4&_var.5&_var.6&_var.7&_var.8&_var.9&_t1bv_15f _twinstr&_desc@'Np .textf] .data0.bss .rdata@&@.file#gt1bv_16.c_var.0'_var.1'_var.2'_t1bv_16 q _twinstr'_desc (Oy .text q .data0.bss .rdata'.file#gt1bv_32.c_var.0`(_var.1p(_var.2(_var.3(_var.4(_var.5(_var.6(_t1bv_32y _twinstr(_desc)$O% .texty.data0.bss .rdata`(`.file4#gt1bv_64.c_var.0)_var.1)_var.2)_var.3)_var.4*_var.5*_var.6 *_var.70*_var.8@*_var.9P*_var.10`*_var.11p*_var.12*_var.13*_var.14*_t1bv_64H _twinstr*_desc+:O@ .textH0.data0.bss .rdata)`.fileG#gt1bv_20.c_var.0 ,_var.10,_var.2@,_var.3P,_t1bv_20d _twinstr`,_desc,PO .textd .data0.bss .rdata ,.file~#gt1bv_25.c_var.0-_var.1-_var.2 -_var.30-_var.4@-_var.5P-_var.6`-_var.7p-_var.8-_var.9-_var.10-_var.11-_var.12-_var.13-_var.14-_var.15-_var.16._var.17._var.18 ._var.190._var.20@._var.21P._var.22`._var.23p._var.24._var.25._var.26._var.27._var.28._var.29._var.30._var.31._var.32/_var.33/_var.34 /_var.350/_var.36@/_var.37P/_var.38`/_var.39p/_t1bv_25 _twinstr/_desc0fO; .textN/.data0.bss .rdata-@.file#gt2bv_2.c_t2bv_2` _twinstr@0_desc`0|O .text`.data0.bss .rdata@0`.file#gt2bv_4.c_t2bv_4 _twinstr0_desc0O  .text-.data0.bss .rdata0.file#gt2bv_8.c_var.0 1_t2bv_80 _twinstr@1_desc1O .text0.data0.bss .rdata 1.file#gt2bv_16.c_var.02_var.12_var.2 2_t2bv_16@ _twinstr@2_desc@3O .text@.data0.bss .rdata2.file#gt2bv_32.c_var.03_var.13_var.23_var.33_var.43_var.53_var.63_t2bv_328 _twinstr4_desc6OL .text87 .data0.bss .rdata3.file#gt2bv_64.c_var.0@6_var.1P6_var.2`6_var.3p6_var.46_var.56_var.66_var.76_var.86_var.96_var.106_var.116_var.127_var.137_var.14 7_t2bv_64p _twinstr@7_desc@;O1 .textpE+.data0.bss .rdata@6@.file$gt2bv_5.c_var.0;_var.1;_var.2;_var.3;_t2bv_51 _twinstr;_desc <O3 .text1> .data0.bss .rdata;.file$gt2bv_10.c_var.0`<_var.1p<_var.2<_var.3<_t2bv_103 _twinstr<_desc@=P=9 .text3h .data0.bss .rdata`< .file+$gt2bv_20.c_var.0=_var.1=_var.2=_var.3=_t2bv_20`9 _twinstr=_desc?(PE .text`9 .data0.bss .rdata=.fileb$gt2bv_25.c_var.0@?_var.1P?_var.2`?_var.3p?_var.4?_var.5?_var.6?_var.7?_var.8?_var.9?_var.10?_var.11?_var.12@_var.13@_var.14 @_var.150@_var.16@@_var.17P@_var.18`@_var.19p@_var.20@_var.21@_var.22@_var.23@_var.24@_var.25@_var.26@_var.27@_var.28A_var.29A_var.30 A_var.310A_var.32@A_var.33PA_var.34`A_var.35pA_var.36A_var.37A_var.38A_var.39A_t2bv_25P_ .text .data0.bss .rdatax.file'gcodlist.c.textLI.data0.bss .rdata`yx$.file'galtivec.c.textLI.data0.bss .file'gsse.c.textLI.data0.bss .file'gsse2.cVtL OVN .textdKb3.data0.bss0.file(gopenmp.c.textO.data0.bss.file*(gdft-vrank-geq1.ceVO _apply/P _awakeP _destroyP _printP padt.2|_mkplanQ T|sadt.1|rVyT .textO.data0.bss.rdata|D.file?(gct.ceVT  U  U _awakeV _destroyJV _printV padt.1|_mkplan1W sadt.0}VL] .textT'.data0.bss.rdata|L.fileT(grdft-vrank-geq1.ceV] _apply] _awake ^ _destroyX^ _print^ padt.24}_mkplan_ TD}sadt.1L}Vb .text].data0.bss.rdata}H.filei(ghc2hc.ceVhb  b  b _awakeLc _destroyc _printc padt.1}_mkplanzd sadt.0}Vi .texthbH'.data0.bss.rdataX}L.file~(gvrank-geq1-rdft2.ceVi _applyj _awakevj _destroyj _printj padt.2}_mkplanrk T}sadt.1}Vn .textiG.data0.bss.rdata}H.file*gf77api.cWn .Wo DWo ]Wo xW-o W?o WDo W[o Woo .textn| .data0.bssWto .textto .data0.bssWo .texto*.data0.bssXo _p.19520*Xo ___mainDp =X.texto .data0.bss.textdp.data@.bssJX}[Xdp Xtp XX@XXHXXXPYp .textdp3.data@.bss@.rdata}probezsdones.textts-.data`.bss .texts.data`.bss Ys .textsq.data`.bss .text$t.data`.bss .idata$7p.idata$54.idata$4.idata$6.text4t.data`.bss .idata$7H.idata$5 .idata$4.idata$6H.textDt.data`.bss .idata$7d.idata$5(.idata$4.idata$6.textTt.data`.bss .idata$7X.idata$5.idata$4.idata$6p.textdt.data`.bss .idata$78.idata$5.idata$4p.idata$6.texttt.data`.bss .idata$7L.idata$5.idata$4.idata$6T.texttt.data`.bss .idata$7T.idata$5.idata$4.idata$6h.textt.data`.bss .idata$7\.idata$5 .idata$4.idata$6|.textt.data`.bss .idata$7.idata$5L.idata$4.idata$6.textt.data`.bss .idata$7.idata$5D.idata$4.idata$6.textt.data`.bss .idata$7t.idata$58.idata$4.idata$6.textt.data`.bss .idata$7x.idata$5<.idata$4.idata$6.textt.data`.bss .idata$7`.idata$5$.idata$4.idata$6.textt.data`.bss .idata$7h.idata$5,.idata$4.idata$6.textt.data`.bss .idata$7P.idata$5.idata$4.idata$6\.textu.data`.bss .idata$7.idata$5H.idata$4.idata$6.textu.data`.bss .idata$7l.idata$50.idata$4.idata$6.text$u.data`.bss .idata$7D.idata$5.idata$4|.idata$68.text4u.data`.bss .idata$7@.idata$5.idata$4x.idata$6$.textDu.data`.bss .idata$7<.idata$5.idata$4t.idata$6.textTu.data`.bss .idata$7|.idata$5@.idata$4.idata$6hnamepfthunk.textdu.data`.bss .idata$2.idata$5.idata$4l.textdu.data`.bss .idata$4.idata$5P.idata$7 .textdu.data`.bss .idata$7 .idata$5.idata$4`.idata$6.texttu.data`.bss .idata$7 .idata$5.idata$4L.idata$6.textu.data`.bss .idata$7.idata$5.idata$4\.idata$6.textu.data`.bss .idata$7$.idata$5.idata$4d.idata$6.textu.data`.bss .idata$7.idata$5.idata$4D.idata$6`.textu.data`.bss .idata$7.idata$5.idata$4H.idata$6p.textu.data`.bss .idata$7.idata$5.idata$4T.idata$6.textu.data`.bss .idata$7.idata$5.idata$4@.idata$6T.textu.data`.bss .idata$7.idata$5.idata$4P.idata$6.textu.data`.bss .idata$7.idata$5.idata$4X.idata$6hname@fthunk.textv.data`.bss .idata$2.idata$5.idata$4<.textv.data`.bss .idata$4h.idata$5.idata$7( +Yv .textv.data`.bss 6Yw .textw.data`.bss AYx .textx .data`.bss .ctorsxSYزlY Yh7YYYxY _freeDt _strcmpt YZ@)Z73Z NZu _Z qZp7ZZk_longjmpu ZZ__errno4t ZZZ [1[C[u O[og[y[ts[7[[[[tu [[X7\7&\4\ W\o\\ \\\\e\4u __setjmpt  ]]H__dll__(]=]_fwritet T]g]hpv]]]<_memcpyt ]]@] _memsetTu ]^$u ^`5^DB^`O^0`^x_fflushTt n^pz^^^_fprintft __allocats^`7^^x_freadt ^_Ȳ&_$3_u J_]_8k_Ly__4__u _u _в__end____dt _signalu _malloc$t `x` `du 4`@B`\` j`` k```hp``_aborttt `a@+aCaPagaua(aa_fftw_cca7aa@abb7bNb@{_memmovet fbu sb__assertDu bu b bb(_qsortt bb0ccx77cOc_cwc,c.debug_aranges.debug_pubnames.debug_info.debug_abbrev.debug_line.debug_frame.debug_loc_next_atexit_first_atexit___dll_exit_DllMainCRTStartup@12.debug_abbrev.debug_info.debug_line.debug_frame.debug_loc.debug_pubnames.debug_aranges___do_sjlj_init_fftw_alignment_of_fftw_malloc_plain_fftw_ifree_fftw_ifree0_fftw_assertion_failed_fftw_null_awake_fftw_nbuf_fftw_bufdist_fftw_toobig_fftw_nbuf_redundant_fftw_cpy1d_fftw_cpy2d_pair_fftw_cpy2d_pair_ci_fftw_cpy2d_pair_co_fftw_cpy2d_fftw_cpy2d_ci_fftw_cpy2d_co_dotile_buf_fftw_cpy2d_tiled_fftw_cpy2d_tiledbuf_fftw_ct_uglyp_fftw_extract_reim_fftw_hash_fftw_iabs_fftw_kernel_malloc_fftw_kernel_free_fftw_md5putb_fftw_md5puts_fftw_md5int_fftw_md5INT_fftw_md5unsigned_roundtab_fftw_md5begin_fftw_md5putc_fftw_md5end_fftw_imax_fftw_imin_fftw_ops_zero_fftw_ops_cpy_fftw_ops_other_fftw_ops_madd_fftw_ops_add_fftw_ops_add2_fftw_ops_madd2_fftw_pickdim_fftw_mkplan_fftw_plan_destroy_internal_fftw_plan_null_destroy_fftw_plan_awake_stimeout_register_solver_htab_insert_fftw_iestimate_costrelax_tab.1_fftw_mkplanner_fftw_planner_destroy_fftw_mkplan_d_fftw_mkplan_f_d_fftw_safe_mulmod_fftw_power_mod_fftw_find_generator_fftw_first_divisor_fftw_is_prime_fftw_next_prime_fftw_factors_into_fftw_isqrt_fftw_choose_radix_fftw_modulo_fftw_mkprinter_fftw_printer_destroy_the_unsolvable_problem_fftw_mkproblem_fftw_problem_destroy_unsolvable_destroy_unsolvable_hash_unsolvable_print_unsolvable_zero_fftw_mkproblem_unsolvable_fftw_rader_tl_insert_fftw_rader_tl_find_fftw_rader_tl_delete_fftw_mkscanner_fftw_scanner_destroy_fftw_mksolver_fftw_solver_use_fftw_solver_destroy_fftw_solver_register_fftw_solvtab_exec_fftw_mkstride_fftw_stride_destroy_fftw_mktensor_fftw_tensor_destroy_fftw_tensor_sz_fftw_tensor_md5_fftw_tensor_tornk1_fftw_tensor_print_fftw_mktensor_0d_fftw_mktensor_1d_fftw_mktensor_2d_fftw_mktensor_3d_fftw_mktensor_4d_fftw_mktensor_5d_fftw_tensor_max_index_fftw_tensor_min_istride_fftw_tensor_min_ostride_fftw_tensor_min_stride_fftw_tensor_inplace_strides_fftw_tensor_inplace_strides2_fftw_tensor_strides_decrease_fftw_tensor_copy_fftw_tensor_copy_inplace_fftw_tensor_copy_except_fftw_tensor_copy_sub_fftw_tensor_append_fftw_dimcmp_fftw_tensor_compress_fftw_tensor_compress_contiguous_fftw_tensor_split_fftw_tensor_equal_fftw_tensor_inplace_locations_fftw_tensor_destroy2_fftw_tensor_destroy4_fftw_tensor_kosherp_fftw_tile2d_fftw_compute_tilesz_fftw_get_crude_time_fftw_elapsed_since_fftw_measure_execution_time_fftw_transpose_transpose_rec_fftw_transpose_tiled_fftw_transpose_tiledbuf_real_cexp_cexpl_sqrtn_table_rotate_sqrtn_table_cexpl_sincos_cexp_zero_cexpl_zero_cexp_generic_rotate_generic_fftw_mktriggen_fftw_triggen_destroy_fftw_twiddle_length_fftw_twiddle_awake_fftw_dft_bluestein_register_maxnbufs_fftw_dft_buffered_register_fftw_dft_conf_standard_apply_dit_apply_dif_fftw_ct_applicable_fftw_mksolver_ct_fftw_mkplan_dftw_apply_extra_iter_apply_buf_fftw_regsolver_ct_directw_fftw_regsolver_ct_directwsq_fftw_ct_generic_registerradices.0batchsizes.1_fftw_ct_genericbuf_register_fftw_mksolver_dft_direct_fftw_mksolver_dft_directbufhalf_tw.2_fftw_dft_generic_register_adt_after_adt_before_apply_before_mkcld_before_apply_after_mkcld_after_fftw_dft_indirect_register_apply_op_fftw_dft_indirect_transpose_registerindirect-transpose.c_fftw_kdft_dif_register_fftw_kdft_difsq_register_fftw_kdft_dit_register_fftw_kdft_register_fftw_dft_nop_register_fftw_mkplan_dft_fftw_mkproblem_dft_fftw_mkproblem_dft_d_fftw_dft_rader_registerbuddies.0_fftw_dft_rank_geq2_register_fftw_dft_solve_fftw_dft_vrank_geq1_register_fftw_dft_zerotens_fftw_codelet_n1_2_fftw_codelet_n1_3_fftw_codelet_n1_4_fftw_codelet_n1_5_fftw_codelet_n1_6_fftw_codelet_n1_7_fftw_codelet_n1_8_fftw_codelet_n1_9_fftw_codelet_n1_10_fftw_codelet_n1_11_fftw_codelet_n1_12_fftw_codelet_n1_13_fftw_codelet_n1_14_fftw_codelet_n1_15_fftw_codelet_n1_16_fftw_codelet_n1_32_fftw_codelet_n1_64_fftw_codelet_n1_20_fftw_codelet_n1_25_fftw_codelet_t1_2_fftw_codelet_t1_3_fftw_codelet_t1_4_fftw_codelet_t1_5_fftw_codelet_t1_6_fftw_codelet_t1_7_fftw_codelet_t1_8_fftw_codelet_t1_9_fftw_codelet_t1_10_fftw_codelet_t1_12_fftw_codelet_t1_15_fftw_codelet_t1_16_fftw_codelet_t1_32_fftw_codelet_t1_64_fftw_codelet_t1_20_fftw_codelet_t1_25_fftw_codelet_t2_4_fftw_codelet_t2_8_fftw_codelet_t2_16_fftw_codelet_t2_32_fftw_codelet_t2_64_fftw_codelet_t2_5_fftw_codelet_t2_10_fftw_codelet_t2_20_fftw_codelet_t2_25_fftw_codelet_q1_2_fftw_codelet_q1_4_fftw_codelet_q1_8_fftw_codelet_q1_3_fftw_codelet_q1_5_fftw_codelet_q1_6_fftw_hc2hc_applicable_fftw_mksolver_hc2hc_fftw_mkplan_hc2hc_fftw_dft_r2hc_register_fftw_dht_r2hc_register_fftw_dht_rader_register_apply_hc2r_fftw_rdft_buffered_register_fftw_rdft_conf_standard_fftw_mksolver_rdft_r2r_direct_apply_r2hc_dobatch_r2hc_dobatch_hc2r_apply_buf_r2hc_apply_buf_hc2r_fftw_mksolver_rdft_r2c_direct_fftw_mksolver_rdft_r2c_directbuf_fftw_rdft_generic_register_fftw_regsolver_hc2hc_direct_fftw_hc2hc_generic_register_fftw_khc2hc_register_fftw_kr2c_register_fftw_kr2r_register_fftw_rdft_indirect_register_fftw_rdft_nop_register_fftw_mkplan_rdft_fftw_rdft_zerotens_fftw_rdft_kind_str_fftw_mkproblem_rdft_fftw_mkproblem_rdft_d_fftw_mkproblem_rdft_1_fftw_mkproblem_rdft_1_d_fftw_mkproblem_rdft_0_d_transpose_apply_iter_applicable_iter_apply_cpy2dco_applicable_cpy2dco_apply_tiled_applicable_tiled_apply_tiledbuf_apply_memcpy_applicable_memcpy_memcpy_loop_apply_memcpy_loop_applicable_memcpy_loop_apply_ip_sq_applicable_ip_sq_apply_ip_sq_tiled_applicable_ip_sq_tiled_apply_ip_sq_tiledbuf_fftw_rdft_rank0_register_fftw_rdft_rank_geq2_register_apply_hc2r_save_fftw_rdft_dht_register_fftw_rdft_solve_fftw_rdft_vrank_geq1_register_adt_toms513_apply_gcd_applicable_gcd_mkcldrn_gcd_apply_cut_applicable_cut_mkcldrn_cut_apply_toms513_applicable_toms513_mkcldrn_toms513_fftw_rdft_vrank3_transpose_register_fftw_rdft2_buffered_register_fftw_mksolver_rdft2_direct_fftw_rdft2_nop_register_apply_r2hc_inplace_fftw_rdft2_rank0_register_fftw_rdft2_rank_geq2_register_fftw_mkplan_rdft2_fftw_rdft2_complex_n_fftw_mkproblem_rdft2_fftw_mkproblem_rdft2_d_fftw_mkproblem_rdft2_d_3pointers_fftw_rdft2_solve_fftw_rdft2_vrank_geq1_register_fftw_rdft2_rdft_register_fftw_rdft2_tensor_max_indexrdft2-tensor-max-index.c_fftw_rdft2_inplace_stridesrdft2-inplace-strides.c_fftw_rdft2_strides_fftw_khc2c_register_apply_dit_dft_apply_dif_dft_fftw_hc2c_applicable_fftw_mksolver_hc2c_fftw_mkplan_hc2c_fftw_regsolver_hc2c_direct_fftw_codelet_r2cf_2_fftw_codelet_r2cf_3_fftw_codelet_r2cf_4_fftw_codelet_r2cf_5_fftw_codelet_r2cf_6_fftw_codelet_r2cf_7_fftw_codelet_r2cf_8_fftw_codelet_r2cf_9_fftw_codelet_r2cf_10_fftw_codelet_r2cf_11_fftw_codelet_r2cf_12_fftw_codelet_r2cf_13_fftw_codelet_r2cf_14_fftw_codelet_r2cf_15_fftw_codelet_r2cf_16_fftw_codelet_r2cf_32_fftw_codelet_r2cf_64_r2cf_128_fftw_codelet_r2cf_128_fftw_codelet_r2cf_20_fftw_codelet_r2cf_25_fftw_codelet_hf_2_fftw_codelet_hf_3_fftw_codelet_hf_4_fftw_codelet_hf_5_fftw_codelet_hf_6_fftw_codelet_hf_7_fftw_codelet_hf_8_fftw_codelet_hf_9_fftw_codelet_hf_10_fftw_codelet_hf_12_fftw_codelet_hf_15_fftw_codelet_hf_16_fftw_codelet_hf_32_fftw_codelet_hf_64_fftw_codelet_hf_20_fftw_codelet_hf_25_fftw_codelet_hf2_4_fftw_codelet_hf2_8_fftw_codelet_hf2_16_fftw_codelet_hf2_32_fftw_codelet_hf2_5_fftw_codelet_hf2_20_fftw_codelet_hf2_25_r2cfII_2_fftw_codelet_r2cfII_2_r2cfII_3_fftw_codelet_r2cfII_3_r2cfII_4_fftw_codelet_r2cfII_4_r2cfII_5_fftw_codelet_r2cfII_5_r2cfII_6_fftw_codelet_r2cfII_6_r2cfII_7_fftw_codelet_r2cfII_7_r2cfII_8_fftw_codelet_r2cfII_8_r2cfII_9_fftw_codelet_r2cfII_9_r2cfII_10_fftw_codelet_r2cfII_10_r2cfII_12_fftw_codelet_r2cfII_12_r2cfII_15_fftw_codelet_r2cfII_15_r2cfII_16_fftw_codelet_r2cfII_16_r2cfII_32_fftw_codelet_r2cfII_32_r2cfII_64_fftw_codelet_r2cfII_64_r2cfII_20_fftw_codelet_r2cfII_20_r2cfII_25_fftw_codelet_r2cfII_25_fftw_codelet_hc2cf_2_fftw_codelet_hc2cf_4_fftw_codelet_hc2cf_6_fftw_codelet_hc2cf_8_hc2cf_10_fftw_codelet_hc2cf_10_hc2cf_12_fftw_codelet_hc2cf_12_hc2cf_16_fftw_codelet_hc2cf_16_hc2cf_32_fftw_codelet_hc2cf_32_hc2cf_20_fftw_codelet_hc2cf_20_hc2cf2_4_fftw_codelet_hc2cf2_4_hc2cf2_8_fftw_codelet_hc2cf2_8_hc2cf2_16_fftw_codelet_hc2cf2_16_hc2cf2_32_fftw_codelet_hc2cf2_32_hc2cf2_20_fftw_codelet_hc2cf2_20_hc2cfdft_2_fftw_codelet_hc2cfdft_2_hc2cfdft_4_fftw_codelet_hc2cfdft_4_hc2cfdft_6_fftw_codelet_hc2cfdft_6_hc2cfdft_8_fftw_codelet_hc2cfdft_8_hc2cfdft_10_fftw_codelet_hc2cfdft_10_hc2cfdft_12_fftw_codelet_hc2cfdft_12_hc2cfdft_16_fftw_codelet_hc2cfdft_16_hc2cfdft_32_fftw_codelet_hc2cfdft_32_hc2cfdft_20_fftw_codelet_hc2cfdft_20_hc2cfdft2_4_fftw_codelet_hc2cfdft2_4_hc2cfdft2_8_fftw_codelet_hc2cfdft2_8_hc2cfdft2_16_fftw_codelet_hc2cfdft2_16_hc2cfdft2_32_fftw_codelet_hc2cfdft2_32_hc2cfdft2_20_fftw_codelet_hc2cfdft2_20_fftw_codelet_r2cb_2_fftw_codelet_r2cb_3_fftw_codelet_r2cb_4_fftw_codelet_r2cb_5_fftw_codelet_r2cb_6_fftw_codelet_r2cb_7_fftw_codelet_r2cb_8_fftw_codelet_r2cb_9_fftw_codelet_r2cb_10_fftw_codelet_r2cb_11_fftw_codelet_r2cb_12_fftw_codelet_r2cb_13_fftw_codelet_r2cb_14_fftw_codelet_r2cb_15_fftw_codelet_r2cb_16_fftw_codelet_r2cb_32_fftw_codelet_r2cb_64_r2cb_128_fftw_codelet_r2cb_128_fftw_codelet_r2cb_20_fftw_codelet_r2cb_25_fftw_codelet_hb_2_fftw_codelet_hb_3_fftw_codelet_hb_4_fftw_codelet_hb_5_fftw_codelet_hb_6_fftw_codelet_hb_7_fftw_codelet_hb_8_fftw_codelet_hb_9_fftw_codelet_hb_10_fftw_codelet_hb_12_fftw_codelet_hb_15_fftw_codelet_hb_16_fftw_codelet_hb_32_fftw_codelet_hb_64_fftw_codelet_hb_20_fftw_codelet_hb_25_fftw_codelet_hb2_4_fftw_codelet_hb2_8_fftw_codelet_hb2_16_fftw_codelet_hb2_32_fftw_codelet_hb2_5_fftw_codelet_hb2_20_fftw_codelet_hb2_25_r2cbIII_2_fftw_codelet_r2cbIII_2_r2cbIII_3_fftw_codelet_r2cbIII_3_r2cbIII_4_fftw_codelet_r2cbIII_4_r2cbIII_5_fftw_codelet_r2cbIII_5_r2cbIII_6_fftw_codelet_r2cbIII_6_r2cbIII_7_fftw_codelet_r2cbIII_7_r2cbIII_8_fftw_codelet_r2cbIII_8_r2cbIII_9_fftw_codelet_r2cbIII_9_r2cbIII_10_fftw_codelet_r2cbIII_10_r2cbIII_12_fftw_codelet_r2cbIII_12_r2cbIII_15_fftw_codelet_r2cbIII_15_r2cbIII_16_fftw_codelet_r2cbIII_16_r2cbIII_32_fftw_codelet_r2cbIII_32_r2cbIII_64_fftw_codelet_r2cbIII_64_r2cbIII_20_fftw_codelet_r2cbIII_20_r2cbIII_25_fftw_codelet_r2cbIII_25_fftw_codelet_hc2cb_2_fftw_codelet_hc2cb_4_fftw_codelet_hc2cb_6_fftw_codelet_hc2cb_8_hc2cb_10_fftw_codelet_hc2cb_10_hc2cb_12_fftw_codelet_hc2cb_12_hc2cb_16_fftw_codelet_hc2cb_16_hc2cb_32_fftw_codelet_hc2cb_32_hc2cb_20_fftw_codelet_hc2cb_20_hc2cb2_4_fftw_codelet_hc2cb2_4_hc2cb2_8_fftw_codelet_hc2cb2_8_hc2cb2_16_fftw_codelet_hc2cb2_16_hc2cb2_32_fftw_codelet_hc2cb2_32_hc2cb2_20_fftw_codelet_hc2cb2_20_hc2cbdft_2_fftw_codelet_hc2cbdft_2_hc2cbdft_4_fftw_codelet_hc2cbdft_4_hc2cbdft_6_fftw_codelet_hc2cbdft_6_hc2cbdft_8_fftw_codelet_hc2cbdft_8_hc2cbdft_10_fftw_codelet_hc2cbdft_10_hc2cbdft_12_fftw_codelet_hc2cbdft_12_hc2cbdft_16_fftw_codelet_hc2cbdft_16_hc2cbdft_32_fftw_codelet_hc2cbdft_32_hc2cbdft_20_fftw_codelet_hc2cbdft_20_hc2cbdft2_4_fftw_codelet_hc2cbdft2_4_hc2cbdft2_8_fftw_codelet_hc2cbdft2_8_hc2cbdft2_16_fftw_codelet_hc2cbdft2_16_hc2cbdft2_32_fftw_codelet_hc2cbdft2_32_hc2cbdft2_20_fftw_codelet_hc2cbdft2_20_fftw_codelet_e01_8_fftw_codelet_e10_8_fftw_reodft_conf_standard_apply_re01_apply_ro01_apply_re10_apply_ro10reodft010e_tw.2_fftw_reodft010e_r2hc_register_apply_re11_apply_ro11reodft11e_tw.3_fftw_reodft11e_radix2_r2hc_register_fftw_reodft11e_r2hc_odd_registerreodft11e-r2hc-odd.c_fftw_redft00e_r2hc_pad_registerredft00e-r2hc-pad.c_fftw_rodft00e_r2hc_pad_registerrodft00e-r2hc-pad.creodft00e_tw.2_fftw_reodft00e_splitradix_registerreodft00e-splitradix.c_aligned_awake_fftw_mkapiplan_fftw_destroy_plan_fftw_configure_planner_fftw_execute_dft_c2r_fftw_execute_dft_r2c_fftw_execute_dft_fftw_execute_r2r_fftw_execute_split_dft_c2rexecute-split-dft-c2r.c_fftw_execute_split_dft_r2cexecute-split-dft-r2c.c_fftw_execute_split_dftexecute-split-dft.c_fftw_execute_fftw_export_wisdom_to_fileexport-wisdom-to-file.c_putchr_cnt_putchr_str_fftw_export_wisdom_to_stringexport-wisdom-to-string.c_putchr_generic_fftw_export_wisdom_write_char_read_char_dfftw_execute___dfftw_destroy_plan___dfftw_cleanup___dfftw_forget_wisdom___dfftw_export_wisdom___dfftw_import_wisdom___dfftw_import_system_wisdom___dfftw_print_plan___dfftw_flops___dfftw_plan_dft___dfftw_plan_dft_1d___dfftw_plan_dft_2d___dfftw_plan_dft_3d___dfftw_plan_many_dft___dfftw_plan_guru_dft___dfftw_plan_guru_split_dft___dfftw_execute_dft___dfftw_execute_split_dft___dfftw_plan_dft_r2c___dfftw_plan_dft_r2c_1d___dfftw_plan_dft_r2c_2d___dfftw_plan_dft_r2c_3d___dfftw_plan_many_dft_r2c___dfftw_plan_guru_dft_r2c___dfftw_plan_guru_split_dft_r2c___dfftw_execute_dft_r2c___dfftw_execute_split_dft_r2c___dfftw_plan_dft_c2r___dfftw_plan_dft_c2r_1d___dfftw_plan_dft_c2r_2d___dfftw_plan_dft_c2r_3d___dfftw_plan_many_dft_c2r___dfftw_plan_guru_dft_c2r___dfftw_plan_guru_split_dft_c2r___dfftw_execute_dft_c2r___dfftw_execute_split_dft_c2r___dfftw_plan_r2r___dfftw_plan_r2r_1d___dfftw_plan_r2r_2d___dfftw_plan_r2r_3d___dfftw_plan_many_r2r___dfftw_plan_guru_r2r___dfftw_execute_r2r___dfftw_execute__dfftw_destroy_plan__dfftw_cleanup__dfftw_forget_wisdom__dfftw_export_wisdom__dfftw_import_wisdom__dfftw_import_system_wisdom__dfftw_print_plan__dfftw_flops__dfftw_plan_dft__dfftw_plan_dft_1d__dfftw_plan_dft_2d__dfftw_plan_dft_3d__dfftw_plan_many_dft__dfftw_plan_guru_dft__dfftw_plan_guru_split_dft__dfftw_execute_dft__dfftw_execute_split_dft__dfftw_plan_dft_r2c__dfftw_plan_dft_r2c_1d__dfftw_plan_dft_r2c_2d__dfftw_plan_dft_r2c_3d__dfftw_plan_many_dft_r2c__dfftw_plan_guru_dft_r2c__dfftw_plan_guru_split_dft_r2c__dfftw_execute_dft_r2c__dfftw_execute_split_dft_r2c__dfftw_plan_dft_c2r__dfftw_plan_dft_c2r_1d__dfftw_plan_dft_c2r_2d__dfftw_plan_dft_c2r_3d__dfftw_plan_many_dft_c2r__dfftw_plan_guru_dft_c2r__dfftw_plan_guru_split_dft_c2r__dfftw_execute_dft_c2r__dfftw_execute_split_dft_c2r__dfftw_plan_r2r__dfftw_plan_r2r_1d__dfftw_plan_r2r_2d__dfftw_plan_r2r_3d__dfftw_plan_many_r2r__dfftw_plan_guru_r2r__dfftw_execute_r2r__DFFTW_EXECUTE@4_DFFTW_DESTROY_PLAN@4_DFFTW_CLEANUP@0_DFFTW_FORGET_WISDOM@0_DFFTW_EXPORT_WISDOM@8_DFFTW_IMPORT_WISDOM@12_DFFTW_IMPORT_SYSTEM_WISDOM@4_DFFTW_PRINT_PLAN@4_DFFTW_FLOPS@16_DFFTW_PLAN_DFT@28_DFFTW_PLAN_DFT_1D@24_DFFTW_PLAN_DFT_2D@28_DFFTW_PLAN_DFT_3D@32_DFFTW_PLAN_MANY_DFT@56_DFFTW_PLAN_GURU_DFT@52_DFFTW_PLAN_GURU_SPLIT_DFT@56_DFFTW_EXECUTE_DFT@12_DFFTW_EXECUTE_SPLIT_DFT@20_DFFTW_PLAN_DFT_R2C@24_DFFTW_PLAN_DFT_R2C_1D@20_DFFTW_PLAN_DFT_R2C_2D@24_DFFTW_PLAN_DFT_R2C_3D@28_DFFTW_PLAN_MANY_DFT_R2C@52_DFFTW_PLAN_GURU_DFT_R2C@48_DFFTW_PLAN_GURU_SPLIT_DFT_R2C@52_DFFTW_EXECUTE_DFT_R2C@12_DFFTW_EXECUTE_SPLIT_DFT_R2C@16_DFFTW_PLAN_DFT_C2R@24_DFFTW_PLAN_DFT_C2R_1D@20_DFFTW_PLAN_DFT_C2R_2D@24_DFFTW_PLAN_DFT_C2R_3D@28_DFFTW_PLAN_MANY_DFT_C2R@52_DFFTW_PLAN_GURU_DFT_C2R@48_DFFTW_PLAN_GURU_SPLIT_DFT_C2R@52_DFFTW_EXECUTE_DFT_C2R@12_DFFTW_EXECUTE_SPLIT_DFT_C2R@16_DFFTW_PLAN_R2R@28_DFFTW_PLAN_R2R_1D@24_DFFTW_PLAN_R2R_2D@32_DFFTW_PLAN_R2R_3D@40_DFFTW_PLAN_MANY_R2R@56_DFFTW_PLAN_GURU_R2R@52_DFFTW_EXECUTE_R2R@12_fftw_flops_fftw_estimate_cost_fftw_forget_wisdom_fftw_import_system_wisdomimport-system-wisdom.c_getchr_file_fftw_import_wisdom_from_fileimport-wisdom-from-file.c_getchr_str_fftw_import_wisdom_from_stringimport-wisdom-from-string.c_getchr_generic_fftw_import_wisdom_fftw_malloc_fftw_free_fftw_map_r2r_kind_fftw_mapflags_myputchr_mycleanup_fftw_mkprinter_file_fftw_mktensor_iodims_fftw_guru_kosherp_fftw_mktensor_rowmajor_fftw_many_kosherpmktensor-rowmajor.c_fftw_plan_dft_1d_fftw_plan_dft_2d_fftw_plan_dft_3d_fftw_plan_dft_c2r_1d_fftw_plan_dft_c2r_2d_fftw_plan_dft_c2r_3d_fftw_plan_dft_c2r_fftw_plan_dft_r2c_1d_fftw_plan_dft_r2c_2d_fftw_plan_dft_r2c_3d_fftw_plan_dft_r2c_fftw_plan_dft_fftw_plan_guru_dft_c2rplan-guru-dft-c2r.c_fftw_plan_guru_dft_r2cplan-guru-dft-r2c.c_fftw_plan_guru_dft_fftw_plan_guru_r2r_fftw_plan_guru_split_dft_c2rplan-guru-split-dft-c2r.c_fftw_plan_guru_split_dft_r2cplan-guru-split-dft-r2c.c_fftw_plan_guru_split_dftplan-guru-split-dft.c_fftw_plan_many_dft_c2rplan-many-dft-c2r.c_fftw_plan_many_dft_r2cplan-many-dft-r2c.c_fftw_plan_many_dft_fftw_plan_many_r2r_fftw_plan_r2r_1d_fftw_plan_r2r_2d_fftw_plan_r2r_3d_fftw_plan_r2r_fftw_fprint_plan_fftw_print_plan_fftw_rdft2_pad_fftw_the_planner_fftw_cleanup_fftw_set_timelimit_fftw_plan_guru64_dft_c2rplan-guru64-dft-c2r.c_fftw_plan_guru64_dft_r2cplan-guru64-dft-r2c.c_fftw_plan_guru64_dft_fftw_plan_guru64_r2r_fftw_plan_guru64_split_dft_c2rplan-guru64-split-dft-c2r.c_fftw_plan_guru64_split_dft_r2cplan-guru64-split-dft-r2c.c_fftw_plan_guru64_split_dftplan-guru64-split-dft.c_fftw_mktensor_iodims64_fftw_guru64_kosherpmktensor-iodims64.c_fftw_check_alignment_of_sse2_pm_okp_t1fu_okp_t1bu_fftw_codelet_n1fv_2_fftw_codelet_n1fv_3_fftw_codelet_n1fv_4_fftw_codelet_n1fv_5_fftw_codelet_n1fv_6_fftw_codelet_n1fv_7_fftw_codelet_n1fv_8_fftw_codelet_n1fv_9_fftw_codelet_n1fv_10_fftw_codelet_n1fv_11_fftw_codelet_n1fv_12_fftw_codelet_n1fv_13_fftw_codelet_n1fv_14_fftw_codelet_n1fv_15_fftw_codelet_n1fv_16_fftw_codelet_n1fv_32_fftw_codelet_n1fv_64_n1fv_128_fftw_codelet_n1fv_128_fftw_codelet_n1fv_20_fftw_codelet_n1fv_25_fftw_codelet_n1bv_2_fftw_codelet_n1bv_3_fftw_codelet_n1bv_4_fftw_codelet_n1bv_5_fftw_codelet_n1bv_6_fftw_codelet_n1bv_7_fftw_codelet_n1bv_8_fftw_codelet_n1bv_9_fftw_codelet_n1bv_10_fftw_codelet_n1bv_11_fftw_codelet_n1bv_12_fftw_codelet_n1bv_13_fftw_codelet_n1bv_14_fftw_codelet_n1bv_15_fftw_codelet_n1bv_16_fftw_codelet_n1bv_32_fftw_codelet_n1bv_64_n1bv_128_fftw_codelet_n1bv_128_fftw_codelet_n1bv_20_fftw_codelet_n1bv_25_fftw_codelet_n2fv_2_fftw_codelet_n2fv_4_fftw_codelet_n2fv_6_fftw_codelet_n2fv_8_fftw_codelet_n2fv_10_fftw_codelet_n2fv_12_fftw_codelet_n2fv_14_fftw_codelet_n2fv_16_fftw_codelet_n2fv_32_fftw_codelet_n2fv_64_fftw_codelet_n2fv_20_fftw_codelet_n2bv_2_fftw_codelet_n2bv_4_fftw_codelet_n2bv_6_fftw_codelet_n2bv_8_fftw_codelet_n2bv_10_fftw_codelet_n2bv_12_fftw_codelet_n2bv_14_fftw_codelet_n2bv_16_fftw_codelet_n2bv_32_fftw_codelet_n2bv_64_fftw_codelet_n2bv_20_fftw_codelet_n2sv_4_fftw_codelet_n2sv_8_fftw_codelet_n2sv_16_fftw_codelet_n2sv_32_fftw_codelet_n2sv_64_fftw_codelet_t1fuv_2_fftw_codelet_t1fuv_3_fftw_codelet_t1fuv_4_fftw_codelet_t1fuv_5_fftw_codelet_t1fuv_6_fftw_codelet_t1fuv_7_fftw_codelet_t1fuv_8_fftw_codelet_t1fuv_9_t1fuv_10_fftw_codelet_t1fuv_10_fftw_codelet_t1fv_2_fftw_codelet_t1fv_3_fftw_codelet_t1fv_4_fftw_codelet_t1fv_5_fftw_codelet_t1fv_6_fftw_codelet_t1fv_7_fftw_codelet_t1fv_8_fftw_codelet_t1fv_9_fftw_codelet_t1fv_10_fftw_codelet_t1fv_12_fftw_codelet_t1fv_15_fftw_codelet_t1fv_16_fftw_codelet_t1fv_32_fftw_codelet_t1fv_64_fftw_codelet_t1fv_20_fftw_codelet_t1fv_25_fftw_codelet_t2fv_2_fftw_codelet_t2fv_4_fftw_codelet_t2fv_8_fftw_codelet_t2fv_16_fftw_codelet_t2fv_32_fftw_codelet_t2fv_64_fftw_codelet_t2fv_5_fftw_codelet_t2fv_10_fftw_codelet_t2fv_20_fftw_codelet_t2fv_25_fftw_codelet_t3fv_4_fftw_codelet_t3fv_8_fftw_codelet_t3fv_16_fftw_codelet_t3fv_32_fftw_codelet_t3fv_5_fftw_codelet_t3fv_10_fftw_codelet_t3fv_20_fftw_codelet_t3fv_25_fftw_codelet_t1buv_2_fftw_codelet_t1buv_3_fftw_codelet_t1buv_4_fftw_codelet_t1buv_5_fftw_codelet_t1buv_6_fftw_codelet_t1buv_7_fftw_codelet_t1buv_8_fftw_codelet_t1buv_9_t1buv_10_fftw_codelet_t1buv_10_fftw_codelet_t1bv_2_fftw_codelet_t1bv_3_fftw_codelet_t1bv_4_fftw_codelet_t1bv_5_fftw_codelet_t1bv_6_fftw_codelet_t1bv_7_fftw_codelet_t1bv_8_fftw_codelet_t1bv_9_fftw_codelet_t1bv_10_fftw_codelet_t1bv_12_fftw_codelet_t1bv_15_fftw_codelet_t1bv_16_fftw_codelet_t1bv_32_fftw_codelet_t1bv_64_fftw_codelet_t1bv_20_fftw_codelet_t1bv_25_fftw_codelet_t2bv_2_fftw_codelet_t2bv_4_fftw_codelet_t2bv_8_fftw_codelet_t2bv_16_fftw_codelet_t2bv_32_fftw_codelet_t2bv_64_fftw_codelet_t2bv_5_fftw_codelet_t2bv_10_fftw_codelet_t2bv_20_fftw_codelet_t2bv_25_fftw_codelet_t3bv_4_fftw_codelet_t3bv_8_fftw_codelet_t3bv_16_fftw_codelet_t3bv_32_fftw_codelet_t3bv_5_fftw_codelet_t3bv_10_fftw_codelet_t3bv_20_fftw_codelet_t3bv_25_fftw_codelet_t1sv_2_fftw_codelet_t1sv_4_fftw_codelet_t1sv_8_fftw_codelet_t1sv_16_fftw_codelet_t1sv_32_fftw_codelet_t2sv_4_fftw_codelet_t2sv_8_fftw_codelet_t2sv_16_fftw_codelet_t2sv_32_fftw_codelet_q1fv_2_fftw_codelet_q1fv_4_fftw_codelet_q1fv_5_fftw_codelet_q1fv_8_fftw_codelet_q1bv_2_fftw_codelet_q1bv_4_fftw_codelet_q1bv_5_fftw_codelet_q1bv_8_hc2cfdftv_2_fftw_codelet_hc2cfdftv_2_hc2cfdftv_4_fftw_codelet_hc2cfdftv_4_hc2cfdftv_6_fftw_codelet_hc2cfdftv_6_hc2cfdftv_8_fftw_codelet_hc2cfdftv_8_hc2cfdftv_10_fftw_codelet_hc2cfdftv_10_hc2cfdftv_12_fftw_codelet_hc2cfdftv_12_hc2cfdftv_16_fftw_codelet_hc2cfdftv_16_hc2cfdftv_32_fftw_codelet_hc2cfdftv_32_hc2cfdftv_20_fftw_codelet_hc2cfdftv_20_hc2cbdftv_2_fftw_codelet_hc2cbdftv_2_hc2cbdftv_4_fftw_codelet_hc2cbdftv_4_hc2cbdftv_6_fftw_codelet_hc2cbdftv_6_hc2cbdftv_8_fftw_codelet_hc2cbdftv_8_hc2cbdftv_10_fftw_codelet_hc2cbdftv_10_hc2cbdftv_12_fftw_codelet_hc2cbdftv_12_hc2cbdftv_16_fftw_codelet_hc2cbdftv_16_hc2cbdftv_32_fftw_codelet_hc2cbdftv_32_hc2cbdftv_20_fftw_codelet_hc2cbdftv_20_sighandler_sse2_works_fftw_have_sse2_fftw_taint_fftw_join_taint_threads_inited_fftw_init_threads_fftw_cleanup_threads_fftw_plan_with_nthreads_fftw_threads_conf_standard_worker@4_termination_semaphore_fftw_ithreads_init_queue_lock_worker_queue_fftw_spawn_loop_fftw_threads_cleanup_spawn_apply_fftw_dft_thr_vrank_geq1_register_fftw_mksolver_ct_threads_fftw_rdft_thr_vrank_geq1_register_fftw_mksolver_hc2hc_threads_fftw_rdft2_thr_vrank_geq1_register_dfftw_plan_with_nthreads___dfftw_init_threads___dfftw_cleanup_threads___dfftw_plan_with_nthreads__dfftw_init_threads__dfftw_cleanup_threads__DFFTW_PLAN_WITH_NTHREADS@4_DFFTW_INIT_THREADS@4_DFFTW_CLEANUP_THREADS@0_DllMain@12__pei386_runtime_relocator___do_global_dtors___do_global_ctors_initialized_w32_atom_suffix___w32_sharedptr_default_unexpected___w32_sharedptr_getdw2_object_mutex.0dw2_once.1sjl_fc_key.2sjl_once.3eh_globals_static.4eh_globals_key.5eh_globals_once.6___w32_sharedptr_initialize_gettimeofday___udivdi3___umoddi3___sjlj_init_ctor_fftw_dft_t1busimd_genus___RUNTIME_PSEUDO_RELOC_LIST___fftw_rdft_r2cbIII_genus__imp__CloseHandle@4__data_start_____DTOR_LIST___fftw_dft_t_genus_fftw_dft_n1bsimd_genus_fftw_solvtab_dft_standard_fftw_rdft_hc2cb_genus___w32_sharedptr_terminate_CreateMutexA@12_fftw_dft_n_genus_fftw_rdft_r2cb_genus___tls_start___fftw_rdft_hc2cbv_genus__libmsvcrt_a_iname__imp__FindAtomA@4__imp__abort__size_of_stack_commit____size_of_stack_reserve____major_subsystem_version_____crt_xl_start___AddAtomA@4_fftw_solvtab_rdft_r2cf___crt_xi_start_____chkstk_fftw_rdft_r2cf_genus___crt_xi_end____imp__CreateSemaphoreA@16_fftw_dft_q1bsimd_genus_CreateSemaphoreA@16__imp___iob_fftw_rdft_hb_genus_fftw_rdft_r2r_genus__bss_start_____RUNTIME_PSEUDO_RELOC_LIST_END____size_of_heap_commit___fftw_dft_t1fusimd_genus__imp___errno_fftw_dft_n2fsimd_genus___crt_xp_start___fftw_an_INT_guaranteed_to_be_zero_fftw_solvtab_dft_simd__beginthreadex___crt_xp_end____imp__signal__minor_os_version____imp__CreateMutexA@12__head_libmsvcrt_a__image_base___fftw_dft_n2ssimd_genus__section_alignment____imp__memmove__imp___endthreadex_fftw_codelet_optim__RUNTIME_PSEUDO_RELOC_LIST____imp___beginthreadex__endthreadex_fftw_solvtab_rdft_r2cb__imp__qsort__data_end_____w32_sharedptr__CTOR_LIST____bss_end____imp__ReleaseSemaphore@12__imp__WaitForSingleObject@8___crt_xc_end___fftw_rdft_hf_genus___crt_xc_start_____CTOR_LIST____imp__GetAtomNameA@12_fftw_dft_t2bsimd_genus__imp__fread_WaitForSingleObject@8__imp____dllonexit__imp__memcpy__imp__strcmp__file_alignment____imp__malloc__major_os_version___ReleaseMutex@4_CloseHandle@4_fftw_dft_t2fsimd_genus__imp___assert___dllonexit__DTOR_LIST____imp__fprintf_ReleaseSemaphore@12__imp__memset_fftw_mksolver_hc2hc_hook_fftw_version_fftw_dft_t1fsimd_genus_fftw_rdft_hc2cfv_genus__size_of_heap_reserve_____crt_xt_start_____ImageBase__subsystem____imp__fflush__imp__GetSystemTimeAsFileTime@4___w32_sharedptr_unexpected_fftw_dft_n2bsimd_genus___tls_end___fftw_dft_tssimd_genus_GetSystemTimeAsFileTime@4__imp__free__major_image_version____loader_flags___fftw_rdft_hc2cf_genus__imp__AddAtomA@4_fftw_sse2_pm__head_libkernel32_a__minor_subsystem_version____minor_image_version___fftw_solvtab_rdft_r2r_fftw_solvtab_rdft_simd_FindAtomA@4__imp___setjmp_GetAtomNameA@12__RUNTIME_PSEUDO_RELOC_LIST_END___fftw_mksolver_ct_hook__libkernel32_a_iname__imp__ReleaseMutex@4__imp__longjmp_fftw_dft_t1bsimd_genus_fftw_rdft_r2cfII_genus_fftw_dft_n1fsimd_genus___crt_xt_end___fftw_dft_q1fsimd_genus__imp__fwritequisk-3.6.11/quisk_vna.py0000666000175000017500000012354312155345630014710 0ustar jimjim00000000000000#! /usr/bin/python # All QUISK software is Copyright (C) 2006-2011 by James C. Ahlstrom. # This free software is licensed for use under the GNU General Public # License (GPL), see http://www.opensource.org. # Note that there is NO WARRANTY AT ALL. USE AT YOUR OWN RISK!! """The main program for Quisk VNA, a vector network analyzer. Usage: python quisk_vns.py [-c | --config config_file_path] This can also be installed as a package and run as quisk_vna.main(). """ from __future__ import print_function import sys, os os.chdir(os.path.normpath(os.path.dirname(__file__))) if sys.path[0] != "'.'": # Make sure the current working directory is on path sys.path.insert(0, '.') import wx, wx.html, wx.lib.buttons, wx.lib.stattext, wx.lib.colourdb import math, cmath, time, traceback import threading, webbrowser import _quisk as QS from types import * from quisk_widgets import * DEBUG = 0 # Command line parsing: be able to specify the config file. from optparse import OptionParser parser = OptionParser() parser.add_option('-c', '--config', dest='config_file_path', help='Specify the configuration file path') argv_options = parser.parse_args()[0] ConfigPath = argv_options.config_file_path # Get config file path if not ConfigPath: # Use default path if sys.platform == 'win32': path = os.getenv('HOMEDRIVE', '') + os.getenv('HOMEPATH', '') for dir in ("Documents", "My Documents", "Eigene Dateien", "Documenti"): ConfigPath = os.path.join(path, dir) if os.path.isdir(ConfigPath): break else: ConfigPath = os.path.join(path, "My Documents") ConfigPath = os.path.join(ConfigPath, "quisk_conf.py") if not os.path.isfile(ConfigPath): # See if the user has a config file try: import shutil # Try to create an initial default config file shutil.copyfile('quisk_conf_win.py', ConfigPath) except: pass else: ConfigPath = os.path.expanduser('~/.quisk_conf.py') class SoundThread(threading.Thread): """Create a second (non-GUI) thread to read samples.""" def __init__(self): self.do_init = 1 threading.Thread.__init__(self) self.doQuit = threading.Event() self.doQuit.clear() def run(self): """Read, process, play sound; then notify the GUI thread to check for FFT data.""" if self.do_init: # Open sound using this thread self.do_init = 0 QS.start_sound() wx.CallAfter(application.PostStartup) while not self.doQuit.isSet(): QS.read_sound() wx.CallAfter(application.OnReadSound) QS.close_sound() def stop(self): """Set a flag to indicate that the sound thread should end.""" self.doQuit.set() class GraphDisplay(wx.Window): """Display the graph within the graph screen.""" def __init__(self, parent, x, y, graph_width, height, chary): wx.Window.__init__(self, parent, pos = (x, y), size = (graph_width, height), style = wx.NO_BORDER) self.parent = parent self.chary = chary self.graph_width = graph_width self.line_mag = [] self.line_phase = [] self.line_swr = [] self.SetBackgroundColour(conf.color_graph) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, parent.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, parent.OnLeftUp) self.Bind(wx.EVT_MOTION, parent.OnMotion) self.Bind(wx.EVT_MOUSEWHEEL, parent.OnWheel) self.tune_tx = graph_width / 2 # Current X position of the Tx tuning line self.height = 10 self.y_min = 1000 self.y_max = 0 self.y_ticks = [] self.max_height = application.screen_height self.tuningPenTx = wx.Pen('Red', 1) self.magnPen = wx.Pen('Black', 1) self.phasePen = wx.Pen((0, 180, 0), 1) self.swrPen = wx.Pen('Blue', 1) self.backgroundPen = wx.Pen(self.GetBackgroundColour(), 1) self.horizPen = wx.Pen(conf.color_gl, 1, wx.SOLID) if sys.platform == 'win32': self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter) def OnEnter(self, event): self.SetFocus() # Set focus so we get mouse wheel events def OnPaint(self, event): dc = wx.PaintDC(self) x = self.tune_tx dc.SetPen(self.tuningPenTx) dc.DrawLine(x, 0, x, self.max_height) dc.SetPen(self.horizPen) for y in self.y_ticks: dc.DrawLine(0, y, self.graph_width, y) # Magnitude t = 'Magnitude, ' x = self.chary y = self.height - self.chary dc.SetTextForeground(self.magnPen.GetColour()) dc.DrawText(t, x, y) w, h = dc.GetTextExtent(t) x += w + self.chary # Phase t = 'Phase, ' dc.SetTextForeground(self.phasePen.GetColour()) dc.DrawText(t, x, y) w, h = dc.GetTextExtent(t) x += w + self.chary # SWR t = 'SWR' dc.SetTextForeground(self.swrPen.GetColour()) dc.DrawText(t, x, y) w, h = dc.GetTextExtent(t) x += w + self.chary # Draw graph if self.line_phase: # Phase line # Try to avoid drawing vertical lines when the phase goes from +180 to -180 dc.SetPen(self.phasePen) top = self.y_ticks[0] high = self.y_ticks[1] low = self.y_ticks[-2] bottom = self.y_ticks[-1] old_phase = self.line_phase[0] line = [(0, old_phase)] for x in range(1, self.graph_width): phase = self.line_phase[x] if phase < high and old_phase > low: line.append((x-1, bottom)) dc.DrawLines(line) line = [(x, top), (x, phase)] elif phase > low and old_phase < high: line.append((x-1, top)) dc.DrawLines(line) line = [(x, bottom), (x, phase)] else: line.append((x, phase)) old_phase = phase dc.DrawLines(line) if self.line_mag: # Magnitude line dc.SetPen(self.magnPen) dc.DrawLines(self.line_mag) if self.line_swr: # SWR line dc.SetPen(self.swrPen) dc.DrawLines(self.line_swr) def SetHeight(self, height): self.height = height self.SetSize((self.graph_width, height)) def SetTuningLine(self, tune_tx): dc = wx.ClientDC(self) dc.SetPen(self.backgroundPen) dc.DrawLine(self.tune_tx, 0, self.tune_tx, self.max_height) dc.SetPen(self.tuningPenTx) dc.DrawLine(tune_tx, 0, tune_tx, self.max_height) self.tune_tx = tune_tx self.Refresh() class GraphScreen(wx.Window): """Display the graph screen X and Y axis, and create a graph display.""" def __init__(self, parent, data_width, graph_width, correct_width, correct_delta, in_splitter=0): wx.Window.__init__(self, parent, pos = (0, 0)) self.in_splitter = in_splitter # Are we in the top of a splitter window? self.data_width = data_width self.graph_width = graph_width self.correct_width = correct_width self.correct_delta = correct_delta self.doResize = False self.pen_tick = wx.Pen("Black", 1, wx.SOLID) self.font = wx.Font(10, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) self.SetFont(self.font) w = self.GetCharWidth() * 14 / 10 h = self.GetCharHeight() self.freq_start = 1000000 self.freq_stop = 2000000 self.charx = w self.chary = h self.mode = '' self.calibrate_open = None self.calibrate_short = None self.calibrate_load = None self.data_mag = [] self.data_phase = [] self.data_impedance = [] self.data_reflect = [] self.data_freq = [0] * data_width self.tick = max(2, h * 3 / 10) self.originX = w * 5 self.offsetY = h + self.tick self.width = self.originX * 2 + self.graph_width + self.tick self.height = application.screen_height * 3 / 10 self.x0 = self.originX + self.graph_width / 2 # center of graph self.originY = 10 self.num_ticks = 8 # number of Y lines above the X axis self.dy_ticks = 10 # The pixel = slope * value + zero_pixel # The value = (pixel - zero_pixel) / slope self.leftZero = 10 # y location of left zero value self.rightZero = 10 # y location of right zero value self.leftSlope = 10 # slope of left scale times 360 self.rightSlope = 10 # slope of right scale times 360 self.SetSize((self.width, self.height)) self.SetSizeHints(self.width, 1, self.width) self.SetBackgroundColour(conf.color_graph) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMotion) self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel) self.display = GraphDisplay(self, self.originX, 0, self.graph_width, 5, self.chary) def OnPaint(self, event): dc = wx.PaintDC(self) if not self.in_splitter: dc.SetFont(self.font) self.MakeYTicks(dc) self.MakeXTicks(dc) def OnIdle(self, event): if self.doResize: self.ResizeGraph() def OnSize(self, event): self.doResize = True self.ClearGraph() event.Skip() def ResizeGraph(self): """Change the height of the graph. Changing the width interactively is not allowed. Call after changing the zero or scale to recalculate the X and Y axis marks. """ w, h = self.GetClientSize() if self.in_splitter: # Splitter window has no X axis scale self.height = h self.originY = h else: self.height = h - self.chary # Leave space for X scale self.originY = self.height - self.offsetY self.MakeYScale() self.display.SetHeight(self.originY) self.doResize = False self.Refresh() def MakeYScale(self): chary = self.chary dy = self.dy_ticks = (self.originY - chary * 2) / self.num_ticks # pixels per tick ytot = dy * self.num_ticks # Voltage dB scale dbs = 80 # Number of dB to display self.leftZero = self.originY - ytot - chary self.leftSlope = - ytot * 360 / dbs # pixels per dB times 360 # Phase scale self.rightSlope = - ytot # pixels per degree times 360 self.rightZero = self.originY - ytot / 2 - chary # SWR scale swrs = 9 # display range 1.0 to swrs self.swrSlope = - ytot * 360 / (swrs - 1) # pixels per SWR unit times 360 self.swrZero = self.originY - self.swrSlope / 360 - chary def MakeYTicks(self, dc): charx = self.charx chary = self.chary x1 = self.originX - self.tick * 3 # left of tick mark x2 = self.originX - 1 # x location of left y axis x3 = self.originX + self.graph_width # end of graph data x4 = x3 + 1 # right y axis x5 = x3 + self.tick * 3 # right tick mark dc.SetPen(self.pen_tick) dc.DrawLine(x2, 0, x2, self.originY + 1) # y axis dc.DrawLine(x4, 0, x4, self.originY + 1) # y axis y = self.leftZero del self.display.y_ticks[:] for i in range(self.num_ticks + 1): # Create the dB scale val = (y - self.leftZero) * 360 / self.leftSlope t = str(val) dc.DrawLine(x1, y, x2, y) self.display.y_ticks.append(y) w, h = dc.GetTextExtent(t) dc.DrawText(t, x1 - w, y - h / 2) # Create the scale on the right val = (y - self.rightZero) * 360 / self.rightSlope t = str(val) dc.DrawLine(x4, y, x5, y) w, h = dc.GetTextExtent(t) dc.DrawText(t, self.width - w - charx, y - h / 2 + 3) # right text y += self.dy_ticks # Create the SWR scale if self.mode == 'Refl': y = self.leftZero dc.SetTextForeground(self.display.swrPen.GetColour()) for i in range(self.num_ticks + 1): val = (y - self.swrZero) * 360 / self.swrSlope t = str(val) w, h = dc.GetTextExtent(t) dc.DrawText(t, w/2, y - h / 2) y += self.dy_ticks def MakeXTicks(self, dc): originY = self.originY x3 = self.originX + self.graph_width # end of fft data charx , z = dc.GetTextExtent('-30000XX') tick0 = self.tick tick1 = tick0 * 2 tick2 = tick0 * 3 # Draw the X axis dc.SetPen(self.pen_tick) dc.DrawLine(self.originX, originY, x3, originY) sample_rate = int(self.freq_stop - self.freq_start) if sample_rate < 12000: return VFO = int((self.freq_start + self.freq_stop) / 2) # Draw the band plan colors below the X axis x = self.originX f = float(x - self.x0) * sample_rate / self.data_width c = None y = originY + 1 for freq, color in conf.BandPlan: freq -= VFO if f < freq: xend = int(self.x0 + float(freq) * self.data_width / sample_rate + 0.5) if c is not None: dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(wx.Brush(c)) dc.DrawRectangle(x, y, min(x3, xend) - x, tick0) # x axis if xend >= x3: break x = xend f = freq c = color stick = 1000 # small tick in Hertz mtick = 5000 # medium tick ltick = 10000 # large tick # check the width of the frequency label versus frequency span df = float(charx) * sample_rate / self.data_width # max label freq in Hertz df *= 2.0 df = math.log10(df) expn = int(df) mant = df - expn if mant < 0.3: # label every 10 tfreq = 10 ** expn ltick = tfreq mtick = ltick / 2 stick = ltick / 10 elif mant < 0.69: # label every 20 tfreq = 2 * 10 ** expn ltick = tfreq / 2 mtick = ltick / 2 stick = ltick / 10 else: # label every 50 tfreq = 5 * 10 ** expn ltick = tfreq mtick = ltick / 5 stick = ltick / 10 # Draw the X axis ticks and frequency in kHz dc.SetPen(self.pen_tick) freq1 = VFO - sample_rate / 2 freq1 = (freq1 / stick) * stick freq2 = freq1 + sample_rate + stick + 1 y_end = 0 for f in range (freq1, freq2, stick): x = self.x0 + int(float(f - VFO) / sample_rate * self.data_width) if self.originX <= x <= x3: if f % ltick is 0: # large tick dc.DrawLine(x, originY, x, originY + tick2) elif f % mtick is 0: # medium tick dc.DrawLine(x, originY, x, originY + tick1) else: # small tick dc.DrawLine(x, originY, x, originY + tick0) if f % tfreq is 0: # place frequency label t = str(f/1000) w, h = dc.GetTextExtent(t) dc.DrawText(t, x - w / 2, originY + tick2) y_end = originY + tick2 + h if y_end: # mark the center of the display dc.DrawLine(self.x0, y_end, self.x0, application.screen_height) def ClearGraph(self): del self.display.line_mag[:] del self.display.line_phase[:] del self.display.line_swr[:] del self.data_mag[:] del self.data_phase[:] del self.data_impedance[:] del self.data_reflect[:] self.display.Refresh() def SetMode(self, mode): self.mode = mode if mode == 'Cal Remove': self.calibrate_open = None self.calibrate_short = None self.calibrate_load = None self.ClearGraph() def SetCorrections(self): if self.calibrate_short is not None and self.calibrate_open is not None: v8 = [] for i in range(self.correct_width): v8.append((self.calibrate_short[i] - self.calibrate_open[i]) / 2) openn = self.calibrate_open[:] short = self.calibrate_short[:] elif self.calibrate_short is not None: v8 = self.calibrate_short[:] short = v8 openn = [0] * self.correct_width elif self.calibrate_open is not None: v8 = [] for i in range(self.correct_width): v8.append( - self.calibrate_open[i]) openn = self.calibrate_open[:] short = [1] * self.correct_width else: return v8.append(v8[-1]) openn.append(openn[-1]) short.append(short[-1]) delta = self.correct_delta self.correct_v8 = [] self.correct_open = [] self.correct_short = [] for x in range(self.data_width): # Find the frequency for this pixel freq = self.data_freq[x] # Find the corresponding index into the correction array i = int(freq / delta) if i >= self.correct_width: i = self.correct_width - 1 # linear interpolation dd = float(freq - i * delta) / delta c = v8[i] + (v8[i+1] - v8[i]) * dd self.correct_v8.append(c) c = openn[i] + (openn[i+1] - openn[i]) * dd self.correct_open.append(c) c = short[i] + (short[i+1] - short[i]) * dd self.correct_short.append(c) if DEBUG and self.calibrate_short is not None and self.calibrate_open is not None and self.calibrate_load is not None: for index in range(500, 3500, 500): freq = delta * index Vs = self.calibrate_short[index] Vo = self.calibrate_open[index] Vl = self.calibrate_load[index] Zs = 25 * (Vs - Vl) / Vl Zd = 50.0 * ( -5 * Vo * Zs - 55 * Vo + 150 * Vs - 3 * Vs * Zs) / ( 250 * Vo + 3 * Zs * Vo - 250 * Vs + 5 * Vs * Zs) #Zx = 250.0 * Zs * (Zd + 30) * (Vs - Vx) / ( # 5 * Vs * (Zd + 30) * (Zs - 50) + Vx * (250 * (Zs + Zd + 30) + 3 * Zs * Zd)) print('freq', freq * 1E-6) print('Zs', Zs) print('Zd', Zd) #print 'Zx', Zx def OnGraphData(self, volts): # Z = 50 * (V8 - v) / (V8 + v) # v = V8 * (50 - z) / (50 + z) # SWR = (1 + rho) / (1 - rho) # Create graph lines mode = self.mode del self.display.line_mag[:] del self.display.line_phase[:] del self.display.line_swr[:] del self.data_mag[:] del self.data_phase[:] del self.data_impedance[:] del self.data_reflect[:] if mode == 'Cal Open': self.calibrate_open = volts[:] elif mode == 'Cal Short': self.calibrate_short = volts[:] elif mode == 'Cal Load': self.calibrate_load = volts[:] use_load = self.calibrate_short is not None and self.calibrate_open is not None and self.calibrate_load is not None if mode[0:4] == 'Cal ': for x in range(self.graph_width): self.data_impedance.append(50) self.data_reflect.append(0) i = x * self.correct_width / self.data_width magn = abs(volts[i]) phase = cmath.phase(volts[i]) * 360. / (2.0 * math.pi) if magn < 1e-6: db = -120.0 else: db = 20.0 * math.log10(magn) self.data_mag.append(db) y = self.leftZero - int( - db * self.leftSlope / 360.0 + 0.5) self.display.line_mag.append((x, y)) self.data_phase.append(phase) y = self.rightZero - int( - phase * self.rightSlope / 360.0 + 0.5) y = int(y) self.display.line_phase.append(y) elif mode == 'Refl': for x in range(self.graph_width): if use_load: # Use a fancy correction baed on the load calibration delta = self.correct_delta # Find the frequency for this pixel freq = self.data_freq[x] # Find the corresponding index into the correction array i = int(freq / delta) if i >= self.correct_width: i = self.correct_width - 1 Vx = volts[x] # linear interpolation dd = float(freq - i * delta) / delta Vs = self.calibrate_short[i] + (self.calibrate_short[i+1] - self.calibrate_short[i]) * dd Vo = self.calibrate_open[i] + (self.calibrate_open[i+1] - self.calibrate_open[i]) * dd Vl = self.calibrate_load[i] + (self.calibrate_load[i+1] - self.calibrate_load[i]) * dd try: Zs = 25 * (Vs - Vl) / Vl Zd = 50.0 * ( -5 * Vo * Zs - 55 * Vo + 150 * Vs - 3 * Vs * Zs) / ( 250 * Vo + 3 * Zs * Vo - 250 * Vs + 5 * Vs * Zs) Z = 250.0 * Zs * (Zd + 30) * (Vs - Vx) / ( 5 * Vs * (Zd + 30) * (Zs - 50) + Vx * (250 * (Zs + Zd + 30) + 3 * Zs * Zd)) reflect = (Z - 50) / (Z + 50) except: if DEBUG: traceback.print_exc() reflect = volts[x] / self.correct_v8[x] # reflection coefficient try: Z = 50.0 * (self.correct_v8[x] - volts[x]) / (self.correct_v8[x] + volts[x]) except ZeroDivisionError: Z = 50E3 else: reflect = volts[x] / self.correct_v8[x] # reflection coefficient try: Z = 50.0 * (self.correct_v8[x] - volts[x]) / (self.correct_v8[x] + volts[x]) except ZeroDivisionError: Z = 50E3 self.data_reflect.append(reflect) self.data_impedance.append(Z) magn = abs(reflect) swr = (1.0 + magn) / (1.0 - magn) if not 0.999 <= swr <= 99: swr = 99.0 if magn < 1e-6: db = -120.0 else: db = 20.0 * math.log10(magn) self.data_mag.append(db) y = self.leftZero - int( - db * self.leftSlope / 360.0 + 0.5) self.display.line_mag.append((x, y)) phase = cmath.phase(reflect) * 360. / (2.0 * math.pi) self.data_phase.append(phase) y = self.rightZero - int( - phase * self.rightSlope / 360.0 + 0.5) y = int(y) self.display.line_phase.append(y) y = self.swrZero - int( - swr * self.swrSlope / 360.0 + 0.5) self.display.line_swr.append((x,y)) else: for x in range(self.graph_width): self.data_impedance.append(50) reflect = (volts[x] - self.correct_open[x]) / self.correct_short[x] self.data_reflect.append(reflect) magn = abs(reflect) if magn < 1e-6: db = -120.0 else: db = 20.0 * math.log10(magn) self.data_mag.append(db) y = self.leftZero - int( - db * self.leftSlope / 360.0 + 0.5) self.display.line_mag.append((x, y)) phase = cmath.phase(reflect) * 360. / (2.0 * math.pi) self.data_phase.append(phase) y = self.rightZero - int( - phase * self.rightSlope / 360.0 + 0.5) y = int(y) self.display.line_phase.append(y) self.display.Refresh() def NewFreq(self, start, stop): if self.freq_start != start or self.freq_stop != stop: self.ClearGraph() self.freq_start = start self.freq_stop = stop for i in range(self.data_width): # The frequency in Hertz for every pixel self.data_freq[i] = int(start + float(stop - start) * i / (self.data_width - 1) + 0.5) self.SetCorrections() self.SetTxFreq(index=self.display.tune_tx) self.doResize = True def SetTxFreq(self, freq=None, index=None): if index is None: index = int(float(freq - self.freq_start) * (self.data_width - 1) / (self.freq_stop - self.freq_start) + 0.5) if index < 0: index = 0 elif index >= self.data_width: index = self.data_width - 1 if freq is None: freq = self.data_freq[index] self.display.SetTuningLine(index) application.ShowFreq(freq, index) def GetMousePosition(self, event): """For mouse clicks in our display, translate to our screen coordinates.""" mouse_x, mouse_y = event.GetPositionTuple() win = event.GetEventObject() if win is not self: x, y = win.GetPositionTuple() mouse_x += x mouse_y += y return mouse_x, mouse_y def OnLeftDown(self, event): mouse_x, mouse_y = self.GetMousePosition(event) self.SetTxFreq(index=mouse_x - self.originX) self.CaptureMouse() def OnLeftUp(self, event): if self.HasCapture(): self.ReleaseMouse() def OnMotion(self, event): if event.Dragging() and event.LeftIsDown(): mouse_x, mouse_y = self.GetMousePosition(event) self.SetTxFreq(index=mouse_x - self.originX) def OnWheel(self, event): tune = self.display.tune_tx + event.GetWheelRotation() / event.GetWheelDelta() self.SetTxFreq(index=tune) class HelpScreen(wx.html.HtmlWindow): """Create the screen for the Help button.""" def __init__(self, parent, width, height): wx.html.HtmlWindow.__init__(self, parent, -1, size=(width, height)) if "gtk2" in wx.PlatformInfo: self.SetStandardFonts() self.SetFonts("", "", [10, 12, 14, 16, 18, 20, 22]) # read in text from file help.html in the directory of this module self.LoadFile('help_vna.html') def OnLinkClicked(self, link): webbrowser.open(link.GetHref(), new=2) class QMainFrame(wx.Frame): """Create the main top-level window.""" def __init__(self, width, height): title = 'Quisk Vector Network Analyzer' wx.Frame.__init__(self, None, -1, title, wx.DefaultPosition, (width, height), wx.DEFAULT_FRAME_STYLE, 'MainFrame') self.SetBackgroundColour(conf.color_bg) self.Bind(wx.EVT_CLOSE, self.OnBtnClose) def OnBtnClose(self, event): application.OnBtnClose(event) self.Destroy() class Spacer(wx.Window): """Create a bar between the graph screen and the controls""" def __init__(self, parent): wx.Window.__init__(self, parent, pos = (0, 0), size=(-1, 6), style = wx.NO_BORDER) self.Bind(wx.EVT_PAINT, self.OnPaint) r, g, b = parent.GetBackgroundColour().Get() dark = (r * 7 / 10, g * 7 / 10, b * 7 / 10) light = (r + (255 - r) * 5 / 10, g + (255 - g) * 5 / 10, b + (255 - b) * 5 / 10) self.dark_pen = wx.Pen(dark, 1, wx.SOLID) self.light_pen = wx.Pen(light, 1, wx.SOLID) self.width = application.screen_width def OnPaint(self, event): dc = wx.PaintDC(self) w = self.width dc.SetPen(self.dark_pen) dc.DrawLine(0, 0, w, 0) dc.DrawLine(0, 1, w, 1) dc.DrawLine(0, 2, w, 2) dc.SetPen(self.light_pen) dc.DrawLine(0, 3, w, 3) dc.DrawLine(0, 4, w, 4) dc.DrawLine(0, 5, w, 5) class App(wx.App): """Class representing the application.""" StateNames =[] def __init__(self): global application application = self self.bottom_widgets = None self.is_vna_program = None if sys.stdout.isatty(): wx.App.__init__(self, redirect=False) else: wx.App.__init__(self, redirect=True) def OnInit(self): """Perform most initialization of the app here (called by wxPython on startup).""" wx.lib.colourdb.updateColourDB() # Add additional color names import quisk_widgets # quisk_widgets needs the application object quisk_widgets.application = self del quisk_widgets global conf # conf is the module for all configuration data import quisk_conf_defaults as conf setattr(conf, 'config_file_path', ConfigPath) if os.path.isfile(ConfigPath): # See if the user has a config file setattr(conf, 'config_file_exists', True) d = {} d.update(conf.__dict__) # make items from conf available exec(compile(open(ConfigPath).read(), ConfigPath, 'exec'), d) # execute the user's config file for k, v in d.items(): # add user's config items to conf if k[0] != '_': # omit items starting with '_' setattr(conf, k, v) else: setattr(conf, 'config_file_exists', False) self.graph_freq = 7e6 self.graph_index = 50 # Open hardware file self.firmware_version = None global Hardware if hasattr(conf, "Hardware"): # Hardware defined in config file Hardware = conf.Hardware(self, conf) else: Hardware = conf.quisk_hardware.Hardware(self, conf) # Initialization # get the screen size x, y, self.screen_width, self.screen_height = wx.Display().GetGeometry() self.Bind(wx.EVT_QUERY_END_SESSION, self.OnEndSession) self.sample_rate = 48000 self.timer = time.time() # A seconds clock self.time0 = 0 # timer to display fields self.clip_time0 = 0 # timer to display a CLIP message on ADC overflow self.heart_time0 = self.timer # timer to call HeartBeat at intervals self.status_text = 'Freq ' self.running = False self.save_data = [] # correct_delta is the spacing of correction points in Hertz self.correct_delta = 15000 self.max_freq = 60000000 # maximum calculation frequency self.correct_width = self.max_freq / self.correct_delta + 4 # number of data points in the correct arrays # Find the data width, the width of returned graph data. width = self.screen_width * conf.graph_width width = int(width) self.data_width = width self.main_frame = frame = QMainFrame(10, 10) self.SetTopWindow(frame) # Record the basic application parameters if sys.platform == 'win32': h = self.main_frame.GetHandle() else: h = 0 # FFT size must equal the data_width so that all data points are returned! QS.record_app(self, conf, self.data_width, self.data_width, 1, self.sample_rate, h) # Make all the screens and hide all but one self.graph = GraphScreen(frame, self.data_width, self.data_width, self.correct_width, self.correct_delta) self.screen = self.graph width = self.graph.width self.help_screen = HelpScreen(frame, width, self.screen_height / 10) self.help_screen.Hide() # Make a vertical box to hold all the screens and the bottom rows vertBox = self.vertBox = wx.BoxSizer(wx.VERTICAL) frame.SetSizer(vertBox) # Add the screens vertBox.Add(self.graph, 1) vertBox.Add(self.help_screen, 1) # Add the spacer vertBox.Add(Spacer(frame), 0, wx.EXPAND) # Add the sizers for the buttons szr1 = wx.BoxSizer(wx.HORIZONTAL) szr2 = wx.BoxSizer(wx.HORIZONTAL) vertBox.Add(szr1, 0, wx.EXPAND, 0) vertBox.Add(szr2, 0, wx.EXPAND, 0) # Make the buttons in row 1 buttons1 = [] self.group_screen = RadioButtonGroup(frame, self.OnBtnScreen, ('Trans', 'Refl', 'Help'), 'Refl') buttons1 += self.group_screen.buttons self.btn_run = b = QuiskCheckbutton(frame, self.OnBtnRun, 'Run') buttons1.append(b) b = QuiskCheckbutton(frame, self.OnBtnCal, 'Cal Open') buttons1.append(b) b = QuiskCheckbutton(frame, self.OnBtnCal, 'Cal Short') buttons1.append(b) b = self.btn_calload = QuiskCheckbutton(frame, self.OnBtnCal, 'Cal Load') buttons1.append(b) b = QuiskPushbutton(frame, self.OnBtnCal, 'Cal Remove') buttons1.append(b) width = 0 for b in buttons1[0:4]: w, height = b.GetMinSize() if width < w: width = w for i in range(24, 8, -2): font = wx.Font(i, wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL, face=conf.quisk_typeface) frame.SetFont(font) w, h = frame.GetTextExtent('Start ') if h < height * 9 / 10: break for b in buttons1[0:4]: b.SetMinSize((width, height)) # Text status style = wx.ST_NO_AUTORESIZE i = 0 for t in ('No hardware response ', 'Error in rates ', 'Mag -1100.12 dB ', 'Phase -1800.12 ', 'SWR 555.1 ', '0'): c = wx.lib.stattext.GenStaticText(frame, -1, t, style=style) setattr(self, "t_field%d" % i, c) c.SetBackgroundColour(conf.color_bg) w, h = c.GetSizeTuple() c.SetMinSize((w, -1)) if i == 5: szr2.Add(c, 1, wx.ALIGN_CENTER_VERTICAL) else: szr2.Add(c, 0, wx.ALIGN_CENTER_VERTICAL) i += 1 # Frequency entry start and stop t = wx.lib.stattext.GenStaticText(frame, -1, 'Start ') t.SetFont(font) t.SetBackgroundColour(conf.color_bg) gap = max(2, height/8) freq0 = t e = wx.TextCtrl(frame, -1, '1', style=wx.TE_PROCESS_ENTER) e.SetFont(font) w, h = e.GetSizeTuple() e.SetMinSize((-1, height)) e.SetBackgroundColour(conf.color_entry) self.freq_start_ctrl = e frame.Bind(wx.EVT_TEXT_ENTER, self.OnNewFreq, source=e) frame.Bind(wx.EVT_TEXT, self.OnNewFreq, source=e) t = wx.lib.stattext.GenStaticText(frame, -1, 'Stop ') t.SetFont(font) t.SetBackgroundColour(conf.color_bg) freq2 = t e = wx.TextCtrl(frame, -1, '30', style=wx.TE_PROCESS_ENTER) e.SetFont(font) e.SetMinSize((-1, height)) e.SetBackgroundColour(conf.color_entry) self.freq_stop_ctrl = e frame.Bind(wx.EVT_TEXT_ENTER, self.OnNewFreq, source=e) frame.Bind(wx.EVT_TEXT, self.OnNewFreq, source=e) # Band buttons ilst = [] slst = [] for l in conf.BandEdge.keys(): # Sort keys try: ilst.append((int(l), conf.BandEdge[l])) except ValueError: # item is a string, not an integer slst.append((l, conf.BandEdge[l])) ilst.sort() ilst.reverse() slst.sort() band = [] width = 0 for l in ilst + slst: b = QuiskPushbutton(frame, self.OnBtnBand, str(l[0])) b.bandEdge = l[1] band.append(b) w, h= b.GetMinSize() if width < w: width = w #for b in band: # b.SetMinSize((width, height)) # make a list of all buttons self.buttons = buttons1 + band # Add first button row to sizer gap = max(2, height / 8) gap2 = max(2, height / 4) szr1.Add(buttons1[0], 0, wx.RIGHT|wx.LEFT, gap) szr1.Add(buttons1[1], 0, wx.RIGHT, gap) szr1.Add(buttons1[2], 0, wx.RIGHT, gap) szr1.Add(buttons1[3], 0, wx.RIGHT|wx.LEFT, gap2) szr1.Add(buttons1[4], 0, wx.RIGHT|wx.LEFT, gap) szr1.Add(buttons1[5], 0, wx.RIGHT, gap) szr1.Add(buttons1[6], 0, wx.RIGHT, gap) szr1.Add(buttons1[7], 0, wx.RIGHT, gap) szr1.Add(freq0, 0, wx.ALIGN_CENTER_VERTICAL) szr1.Add(self.freq_start_ctrl, 1, wx.RIGHT, gap) szr1.Add(freq2, 0, wx.ALIGN_CENTER_VERTICAL) szr1.Add(self.freq_stop_ctrl, 1, wx.RIGHT, gap) for x in band: szr1.Add(x, 0, wx.RIGHT, gap) # Set top window size self.main_frame.SetClientSizeWH(self.graph.width, self.screen_height * 5 / 10) # Open the hardware. This must be called before open_sound(). self.config_text = Hardware.open() if not self.config_text: self.config_text = "Missing config_text" if hasattr(Hardware, 'SetVNA'): self.has_SetVNA = True else: self.has_SetVNA = False # Note: Subsequent calls to set channels must not name a higher channel number. # Normally, these calls are only used to reverse the channels. QS.open_sound(conf.name_of_sound_capt, '', self.sample_rate, conf.data_poll_usec, conf.latency_millisecs, '', conf.tx_ip, conf.tx_audio_port, 48000, 0, 0, 1.0, '', 48000) self.Bind(wx.EVT_IDLE, self.graph.OnIdle) frame.Show() self.Yield() if self.has_SetVNA: Hardware.SetVNA(key_down=0, vna_count=self.data_width) self.OnNewFreq() self.WriteFields() self.EnableButtons() QS.set_fdx(1) QS.set_rx_mode(0) self.sound_thread = SoundThread() self.sound_thread.start() return True def OnEndSession(self, event): event.Skip() self.OnBtnClose(event) def OnBtnClose(self, event): if self.sound_thread: self.sound_thread.stop() for i in range(0, 20): if threading.activeCount() == 1: break time.sleep(0.1) def OnBtnBand(self, event): btn = event.GetEventObject() start, stop = btn.bandEdge start = float(start) * 1e-6 stop = float(stop) * 1e-6 self.freq_start_ctrl.SetValue(str(start)) self.freq_stop_ctrl.SetValue(str(stop)) def OnBtnCal(self, event): btn = event.GetEventObject() mode = btn.GetLabel() self.btn_run.SetValue(0) self.graph.SetMode(mode) if mode == 'Cal Remove': self.running = False self.btn_run.Enable(0) self.graph.SetCorrections() self.SetField0() elif btn.GetValue(): for b in self.buttons: if b != btn: b.Enable(0) self.btn_run.Enable(0) self.NewFreq(0, self.max_freq) if self.has_SetVNA: count = self.correct_width max_freq = self.correct_delta * count Hardware.SetVNA(key_down=1, vna_start=0, vna_stop=max_freq, vna_count=count) self.running = True else: self.running = False for b in self.buttons: b.Enable(1) self.graph.SetCorrections() self.SetField0() if self.has_SetVNA: Hardware.SetVNA(key_down=0, vna_count=self.data_width) self.EnableButtons() def OnBtnScreen(self, event): btn = event.GetEventObject() screen = btn.GetLabel() if screen == 'Help': self.help_screen.Show() self.graph.Hide() else: self.help_screen.Hide() self.graph.Show() self.graph.SetMode(screen) self.vertBox.Layout() self.EnableButtons() def OnBtnRun(self, event): btn = event.GetEventObject() run = btn.GetValue() self.graph.SetMode(self.group_screen.GetLabel()) self.OnNewFreq() if self.has_SetVNA: if run: self.running = True Hardware.SetVNA(key_down=1) else: self.running = False Hardware.SetVNA(key_down=0) def EnableButtons(self): mode = self.group_screen.GetLabel() if mode == 'Trans': self.btn_calload.Enable(0) if self.graph.calibrate_short is not None: self.btn_run.Enable(1) else: self.btn_run.Enable(0) else: # Refl self.btn_calload.Enable(1) if self.graph.calibrate_short is not None or self.graph.calibrate_open is not None: self.btn_run.Enable(1) else: self.btn_run.Enable(0) def ShowFreq(self, freq, index): if hasattr(Hardware, 'ChangeFilterFrequency'): Hardware.ChangeFilterFrequency(freq) self.graph_freq = freq self.graph_index = index self.status_text = "Freq %9.6f" % (freq * 1.E-6) if self.t_field1.GetLabel()[0:5] == 'Freq ': self.t_field1.SetLabel(self.status_text) self.WriteFields() def OnNewFreq(self, event=None): try: start = self.freq_start_ctrl.GetValue() start = float(start) * 1e6 stop = self.freq_stop_ctrl.GetValue() stop = float(stop) * 1e6 except: self.t_field1.SetLabel("Error in rates") #traceback.print_exc() return start = int(start + 0.5) stop = int(stop + 0.5) if start > stop: self.t_field1.SetLabel("Error in rates") return if stop > self.max_freq: stop = self.max_freq self.freq_stop_ctrl.SetValue("%.6f" % (stop * 1.E-6)) self.NewFreq(start, stop) def NewFreq(self, start, stop): if application.has_SetVNA: start, stop = Hardware.SetVNA(vna_start=start, vna_stop=stop) self.freq_start = start self.freq_stop = stop self.t_field1.SetLabel(self.status_text) self.graph.NewFreq(start, stop) def SetField0(self): if self.firmware_version is None: text = "No hardware response" elif self.firmware_version < 3: text = "Need firmware ver 3 " else: text = '' if self.graph.calibrate_open is not None: text = text + 'Op' if self.graph.calibrate_short is not None: text = text + 'Sh' if self.graph.calibrate_load is not None: text = text + 'Lo' if text: text = 'Calibration ' + text else: text = 'Calibration None' self.t_field0.SetLabel(text) def WriteFields(self): if not self.graph.data_mag: self.t_field2.SetLabel('') self.t_field3.SetLabel('') self.t_field4.SetLabel('') self.t_field5.SetLabel('') return index = self.graph_index if index < 0: index = 0 elif index >= self.data_width: index = self.data_width - 1 mode = self.graph.mode if mode in ('Cal Open', 'Cal Short', ''): db = self.graph.data_mag[index] phase = self.graph.data_phase[index] self.t_field2.SetLabel('Mag %7.2f dB' % db) self.t_field3.SetLabel('Phase %6.1f' % phase) self.t_field4.SetLabel('') self.t_field5.SetLabel('') elif mode == 'Trans': db = self.graph.data_mag[index] phase = self.graph.data_phase[index] aref = abs(self.graph.data_reflect[index]) self.t_field2.SetLabel('Mag %8.2f dB' % db) self.t_field3.SetLabel('Phase %8.2f' % phase) self.t_field4.SetLabel('') self.t_field5.SetLabel('') elif mode == 'Refl': db = self.graph.data_mag[index] phase = self.graph.data_phase[index] aref = abs(self.graph.data_reflect[index]) swr = (1.0 + aref) / (1.0 - aref) if not 0.999 <= swr <= 99: swr = 99.0 self.t_field2.SetLabel('Mag %7.2f dB' % db) self.t_field3.SetLabel('Phase %6.1f' % phase) self.t_field4.SetLabel('SWR %6.1f' % swr) Z = self.graph.data_impedance[index] mag = abs(Z) phase = cmath.phase(Z) * 360. / (2.0 * math.pi) freq = self.graph.data_freq[index] im = Z.imag text = ' Imped %8.1f %8.1f J Mag %7.2f Phase %6.1f' % (Z.real, im, mag, phase) if im >= 0.5: L = im / (2.0 * math.pi * freq) * 1e9 text += ' L %10.0f nH' % L elif im < -0.5: C = -1.0 / (2.0 * math.pi * freq * im) * 1e9 text += ' C %10.3f nF' % C self.t_field5.SetLabel(text) def OnExit(self): if self.has_SetVNA: Hardware.SetVNA(key_down=0, do_tx=True) time.sleep(0.5) QS.close_rx_udp() Hardware.close() def PostStartup(self): # called once after sound attempts to start pass def OnReadSound(self): # called at frequent intervals self.timer = time.time() dat = QS.get_graph(0, 1.0, 0) if dat and self.running: dat = list(dat) try: start = dat.index(0) except ValueError: self.save_data += dat return data = self.save_data + dat[0:start] self.save_data = dat[start+1:] if self.graph.mode[0:3] == 'Cal': if len(data) != self.correct_width: if DEBUG: print(' bad data array', len(data), self.correct_width) return else: if len(data) != self.data_width: if DEBUG: print(' bad data array', len(data), self.data_width) return #print "%10.2f %12.8f %10.2f %10.2f %10.2f" % (cmath.phase(data[0]) * 360. / (2.0 * math.pi), abs(data[0]) / 2147483647.0, # cmath.phase(data[0]) * 360. / (2.0 * math.pi), cmath.phase(data[0]) * 360. / (2.0 * math.pi), cmath.phase(data[0]) * 360. / (2.0 * math.pi)) for i in range(len(data)): data[i] /= 2147483647.0 self.graph.OnGraphData(data) if QS.get_overrange(): self.clip_time0 = self.timer self.t_field1.SetLabel("CLIP") if self.clip_time0: if self.timer - self.clip_time0 > 1.0: self.clip_time0 = 0 self.t_field1.SetLabel(self.status_text) if self.timer - self.heart_time0 > 0.10: # call hardware to perform background tasks self.heart_time0 = self.timer Hardware.HeartBeat() if self.firmware_version is None and conf.use_rx_udp: self.firmware_version = Hardware.GetFirmwareVersion() self.SetField0() # Set text fields if self.timer - self.time0 > 0.5: self.time0 = self.timer #print "len %5d re %9.6f im %9.6f mag %9.6f phase %7.2f" % (len(data), # volts.real, volts.imag, abs(volts), phase) #print "Z re %12.2f im %12.2f mag %12.2f phase %7.2f" % (zzz.real, zzz.imag, # abs(zzz), cmath.phase(zzz) * 360. / (2.0 * math.pi)) self.WriteFields() def main(): """If quisk is installed as a package, you can run it with quisk.main().""" App() application.MainLoop() if __name__ == '__main__': main() quisk-3.6.11/help.html0000644000175000017500000005130612160374114014140 0ustar jimjim00000000000000 QUISK Help File

QUISK Help (April 2012)

The The documentation is here.

This is the Help file for Quisk, a Software Defined Radio (SDR). This Help appears in Quisk when you press the Help button. Quisk is written by Jim Ahlstrom, N2ADR, www.james.ahlstrom.name. Mail to jahlstr at gmail.com. Quisk has been greatly improved and extended by Leigh L. Klotz Jr. WA5ZNU, and by Andrew Nilsson VK6JBL. Thanks to Terry Fox WB4JFI for code improvements, and for adding support for the Charleston hardware. Thanks to Sid Boyce, G3VBV, for sending me SoftRock hardware to work with.  Thanks to Christof, DJ4CM, for many improvements to the GUI and for Dx cluster display.

What Quisk Can Do

Depending on how you have configured it, Quisk can be used as a radio receiver, a transceiver, or a panadapter. When you use Quisk as a receiver or panadapter, you supply an antenna, a complex (I/Q) mixer to convert radio spectrum to a low IF, and send that IF to the left and right inputs of the sound card in your computer. The Quisk software will read the sound card data, tune it, filter it, demodulate it, and send the audio to the same sound card for output to external headphones or speakers. For most efficient use, you may wish to configure some form of rig control in the your configuration file and hardware file.

Quisk can also accept I/Q data from the SDR-IQ from RfSpace. The selection of SDR-IQ or soundcard is made in your configuration file.

Quisk rhymes with "brisk", and is QSK plus a few letters to make it easier to pronounce. QSK is a Q signal meaning full break in CW operation, and Quisk has been designed for low latency. Quisk includes an input keying signal that can mute the audio and substitute a side tone. To install and configure Quisk, please see the docs.html file in the Quisk directory.

Quisk is designed for QSK CW operation. It is written in Python, an easy to learn but powerful language; see www.python.org. Source is provided because your own hardware is probably different from mine, and you will need to change something. Changing Python is easy.

There are lots of other SDR projects; see the list at http://f4dan.free.fr/sdr_eng.html. I particularly recommend Linrad by SM5BSZ, PowerSDR, and SDRadio by I2PHD. Reading the Linrad pages is a great introduction to SDR.

Configuration File

Quisk first imports all its configuration information from the file quisk_conf_defaults.py. Then it reads your configuration file.  To change your configuration, do NOT change quisk_conf_defaults.py, because installing the next version will cause your changes to be lost. Instead copy one of the sample quisk_conf_*.py to your config file. For a standard soundcard, copy quisk_conf_model.py. Make any changes you want to your config file. To see what kinds of changes are available, read the file quisk_conf_defaults.py. Please do NOT copy quisk_conf_defaults.py to your config file. Your config file should consist of only the lines that are different from quisk_conf_defaults.py, and it should be a small file.

The configuration file also imports your hardware control file. This is quisk_hardware_model by default. To use a different hardware file add "import quisk_hardware_fixed as quisk_hardware" (for SoftRock, or another quisk_hardware_* file) to your configuration file. You can control your own hardware either by writing a custom hardware file, or by defining a "class Hardware" in your config file. See docs.html for details, and read the various hardware files.

If you need to add custom controls to Quisk, add "import quisk_widgets_mywidgets as quisk_widgets" to your configuration file, and see quisk_widgets_n2adr.py. This is an advanced feature, and you will need to understand wxPython.

Testing QUISK

Look at the bottom row of buttons to the right. I guess you found the Help button, since this is the help screen. Press the Config (configuration) button, have a look, and then return to Help. If sound is running you should see the Interrupts count increasing steadily. Some sound card information is shown, and some error counts. If anything prints in red, something is wrong. You must edit the configuration file to change the soundcard name or rate. There will be different sound card parameters for each name. See docs.html for more information, or if you can't get sound to run. If Interrupts are increasing, the Graph and Waterfall screen should work too.

Next press Graph to look at the graph screen, and then Help to return. You may need to run the "Ys" (Y scale) slide control on the right up or down to see the graph line. You should see a noise trace that changes randomly (without sound input). Then press Test1. This generates a test signal at 10 kHz, and you should see the spike on the graph. To tune to that signal, click the mouse on the graph near the spike. Hold the mouse button down and drag the red tuning line back and forth across the test signal. You should head a pure audio tone in your speakers. Use the "Vol" (Volume) slider on the left to change the volume.

If you press Graph again, you will activate the peak hold functions labeled "GraphP1" and "GraphP2".  These will cause the graph to follow the peak signal, and decay back down at a slow rate.  To control the rate, use the graph_peak_hold item in the config file.

Next press WFall to see the Waterfall screen, then Help to return. You can resize the Quisk window to get see more waterfall history. You will need to adjust "Ys" (Y scale) and "Yz" (Y zero) to get a colored display. You should see a strong 10 kHz signal. Press Test1 to turn the signal on and off. Watch it appear and disappear from the waterfall.

The top of the waterfall shows a small graph screen. You can grab the bar between the screens with your mouse and move it up and down to adjust the relative sizes. To adjust the scale and zero of this graph, hold down the Shift key while using the "Ys" and "Yz" sliders.

Next press Scope to see an oscilloscope screen. This is mainly useful for debugging.

Last press Filter and wait a few seconds. The response of the current filter is shown. Try changing filters by using the middle row of buttons on the right.

Tuning

On the Graph or Waterfall screens, you tune in a CW signal by clicking above the X axis directly on the signal. You tune in an SSB signal by clicking on the upper edge (lower sideband) or the lower edge (upper sideband). That is, you always click where the carrier goes. Make sure the proper mode is selected with the first row of buttons on the right. You can also click, hold down the mouse button and drag the tuning line. The speed of tuning is lowest close to the X axis, and increases as you move up. Try it.

If you click below the X axis, tuning will not jump to that frequency, but you can still hold the button and drag. That is useful for small adjustments. The mouse wheel will move the frequency up and down and round the frequency to multiples of 50 Hertz.

If you right-click a signal, Quisk tunes to the signal as before, and also changes the VFO (if that is possible with your hardware) to move the signal to the center of the screen.

You can type a frequency into the entry box to the right of the frequency display, and hit Enter to jump to it. The frequency is in Hertz unless it has a decimal point, and then it is megahertz.  The band Up and Down buttons do not change the tuning, but will move the display up and down the band. Hold these buttons down to keep moving.

You can left-click the digits in the frequency display to increase (click the top) or decrease (click the bottom) the digit and round the frequency.  Try it.

To really perform tuning, you need a VFO controlled by Quisk. I use a DDS VFO controlled by Ethernet. This DDS has a transmit and receive frequency, and a key signal to choose which to generate. Quisk (currently) assumes a single conversion to audio, as in the SoftRock-40 and FlexRadio 1000 receivers. If you have a fixed (crystal controlled) first conversion, use quisk_hardware_fixed.py and change self.vfo to the frequency in Hertz.

The frequency shown by the red tuning line and the frequency display window is always the transmit frequency.  This equals the receive frequency unless Split is used (see below).  The frequency display window will turn red to indicate sound capture (input ADC) overrun (clipping).

The RIT (receiver incremental tuning) button and slider can add a small offset to the receive frequency.   Leave RIT off for SSB unless a station is off frequency a bit; then use RIT to tune him in while leaving your transmit frequency unchanged.  When you select CW, the RIT must be turned on to provide an audio output, so Quisk automatically turns on RIT and sets it to plus or minus cwTone.  The audio side tone (if a hardware key line is used) is set to the same.  Just click CWL or CWU, tune the frequency by clicking exactly on the signal, and everything will work. The value of cwTone can be changed in your configuration file.

If the Split button is pressed, a second green tuning line is shown to indicate the receive frequency, and the receive frequency can be independently adjusted.  The mouse controls the closest tuning line.  To receive on the transmit frequency again, just turn Split off.  The Split feature is used to work a DX station operating split, or it can be used to easily switch between two arbitrary receive frequencies.

Top Row

The top row contains the frequency display, a window to enter a frequency, two buttons to move up and down the band, three memory buttons, two favorite buttons, the RIT control and the window for the S-meter or frequency measurement display.

Quisk can remember and return to stations.  When you have tuned in a signal of interest, press the "Save" button Ⓜ↑ to save the frequency, band and mode.  Repeat for more signals.  Now press "Next" Ⓜ ➲, to switch to the next saved signal, and press "Next" repeatedly to cycle through the list.  To delete a saved signal, first tune to it with "Next" and then press "Delete" Ⓜ ☓ . If you save a large number of signals, right click the "Next" button Ⓜ ➲, and you will get a popup menu so you can jump directly to a station.  The saved stations will appear in the station window below the frequency X axis.

Quisk can save a list of favorite stations.  Press Config/Favorites to access the screen, and right-click the left label to insert and delete stations, and to tune to them.  The two favorites buttons provide direct access to this screen.  The ★ ↑ button enters the current station into the screen; just provide a name.  The ★ ↓ button jumps to the screen; right click the left label and choose "Tune to".  Favorite stations will appear in the station window with a Star symbol ★ .

The S-meter displays the signal strength in S units and in dB. Zero dB is clipping, the same as on the graph screen. The S-meter uses the specified filter bandwidth to choose the exact number of FFT bins to square and average. That is, it displays true RMS based on the FFT bins, not on the post-filter audio. Note that for a noise floor on the graph of -110 dB the S-meter will read -93 dB (depending on some details). That is because the bandwith specified is much greater than the FFT bin width, and more noise is getting through. Find a flat noise frequency, change the filter bandwidth, and watch your S-meter measure the noise. The conversion from S-units to dB depends on your hardware. There are 6 dB per S-unit, and you can change self.correct_smeter in your configuration file (in S-units) to adjust to 50 microvolts for S9. If the correction depends on the band, you can make a band-dependent correction in your hardware file.  See below to change the S-meter to a frequency measurement window.

Station Window and Dx Cluster

There is a station window below the frequency axis (X axis) to display stations of interest.  This feature was added by Christof, DJ4CM.  It consists of zero or more lines containing an M-Circle symbol Ⓜ for memory stations, a Star symbol ★ for favorite stations and a Dx symbol for Dx Cluster stations (see below).  You control this feature by adding lines to your config file; read the file quisk_conf_defaults.py (as usual) to see what lines to add.  The default number of lines is one, but you can add more lines if the display becomes too crowded.  If you move your mouse near the marked frequency, a popup window will appear with station details.  Left-click the symbol to tune to it.

There are Dx Cluster telnet servers available that provide real time information on Dx station activity.  Set dxClHost to an available server in your config file, add your call sign and check the port.  This feature will run continuously unless dxClHost is the null string.  The Dx stations will appear in the station window as they become avaliable from the server.

Screen Sliders

There are three sliders on the right of the Quisk screen.  The first two are labeled Ys and Yz, and they control the scale and zero of the screen in view.  For the Graph screen and the Rx Filter screen they control the scale and zero of the Y axis.  For the Waterfall screen they control the Waterfall color scale; and if the Shift key is down, they control the upper graph Y axis.  For the Scope screen the Ys slider controls the Y axis scale, and the Yz slider does nothing.  The sliders have no effect on other screens.

The Zo (zoom) slider expands the frequency scale (X axis) of the Graph and Waterfall screens so that narrow signals can be examined.  Quisk operates normally when this slider is all the way down.  As it is raised, the frequency is expanded around the tuning frequency.  That is, the tuning frequency is moved to the center, and the frequency scale is expanded.  It is still possible to tune Quisk as usual while this control is in use.  For small frequency shifts, remember to use the right mouse button.

Other Controls

The sliders on the left control the main volume (Vol) and side tone volume (STo). Side tone is only active if you configure Quisk to operate as a transceiver, and change is_key_down.c to provide a key signal.

The first row of buttons on the left selects the band. The "Audio" band is meant to set the VFO frequency to zero for use with a sound card and no hardware control. The "Time" band selects standard time signals. Pressing this button repeatedly selects different frequencies. The remaining buttons select the amateur bands. The 60 meter button can be pressed repeatedly to select the channels. Adding bands requires more band plans in your configuration file.

The second and third row of buttons on the left select audio mute, AGC (automatic gain control), noise blanker and other features depending on your hardware.  Right click the AGC button to adjust the threshold.  Right click the Spot button (if present) to adjust the level.  The AGC button becomes the Squelch button for FM.

The first row of buttons on the right selects the receive mode. The next row selects the filter to use. The filter bandwidths can be set in your config file.  The right-most filter button bandwidth is adjustable; right-click it to adjust.  The third row selects the screen to display: Graph, Waterfall, Scope, Config, Filter, or Help.

If you use the sound card for input, you may need to correct for small errors in the I and Q amplitude and phase. First change to the correct band, because corrections are saved for each band. Press the button on the config screen to bring up a correction screen. Then feed a test signal to your hardware (or use a strong available signal) and look at the signal image. Adjust the slider controls to reduce the image. The upper slider is the fine adjustment, and the lower is the coarse. You will need to adjust both amplitude and phase and they will interact.  The amount of available adjustment range is controlled by your config file.  When you have a final correction, it is a good idea to write it down.  The correction point is saved based on the VFO frequency, and you will probably need two or three correction points per band.

Configuration Button

The Config button takes you to a number of screens that display status, and provide for limited control of Quisk parameters.  The Favorites screen allows you to enter frequencies and modes for stations, nets, etc.  To add a line, right-click the left label and select Insert or Append.  To tune to a station, select Tune.

Digital Modes DGT-*

These modes are for digital signals, and require an  external program such as Fldigi to decode the signals.  Press the "DGT-" button repeatedly to select a digital mode.  To use Fldigi, first start Quisk; then start Fldigi and change "Rig Control" to "Use XML-RPC".  Now changing the frequency in either program should change the other.  Now you need to connect the audio.  Read the file quisk_conf_defaults.py (as usual) and look for items starting with "digital_" that are available for controlling digital modes.  Quisk has an additional audio input and output that you connect to Fldigi (or other program).  Quisk sends its audio to Fldigi to decode signals, and Fldigi sends audio to Quisk for transmission.  See the documentation for more information.

Hamlib Control

Most digital mode decoders and logging programs use Hamlib to connect to a rig.  To connect Hamlib to Quisk, configure your client program to use rig 2 and device localhost:4575.  Rig 2 specifies a TCP connection, and Quisk is listening on localhost port 4575.  If your program does not offer rig 2, please update your Hamlib files for that program.  If your program can not set the TCP port to localhost:4575, then change the port Quisk uses by adding "hamlib_port = 4532" to your config file.  See the documentation for more information.

Sound Recording

There is a Record and Playback button in the third row.  Push Record to start recording radio sound.  The maximum time to record is set in the config file (default 15 seconds) and after this limit older sound is discarded.  That is, the most recent 15 seconds is retained.  Push Playback to play the sound.  If you are transmitting, the recorded sound is transmitted in place of mic input.  This sound is not speech processed, so it can be used to give another station an accurate indication of how they sound.

Sound Recording to a File

Quisk can record the speaker audio and the digital samples to WAV files.  Set the file names in the Config screen.  Then Press the "FileRec" button to begin recording, and release it to stop.  If you press it again, it starts a new recording to replace the previous one.  The speaker audio is stored as 16-bit monophonic samples at the audio play rate.  The samples are stored as two I/Q IEEE floating point samples at the sample rate.  Note that a WAV file has a maximum size of 4.3 gigabytes, and that will limit the time of the recording.

Frequency Measurement

Quisk can measure and display the frequency of a continuous tone RF signal.  To use this feature, right click the S-meter window, and select one of the Frequency items.  The numbers are the averaging times in seconds.  Then find a signal of interest and put the tuning line exactly on it.  Quisk will search 500 Hertz up and down from the tuning line and will display the frequency of the largest signal.  This feature works on AM signals and continuous signals from oscillators, etc.  It does not work for SSB as there is no continuous signal.  To calibrate your hardware, measure the carrier from WWV or other frequency standard, and change your clock rate until the indicated frequency is correct.  If you are using my QEX2010 hardware or the HiQSDR, you can trim the resistors at the crystal to bring the oscillator to exactly 122.88 megahertz.

Have fun with Quisk.

quisk-3.6.11/CHANGELOG.txt0000666000175000017500000006477512164330404014372 0ustar jimjim00000000000000Quisk Version 3.6.11 July 2013 ============================== I increased the size of the SoftRock status line. You can now change frequency by left clicking on the digits in the frequency display. Click on the upper part of a digit to increase it, and the lower part to decrease it. I added some GREAT features from Christof, DJ4CM: Symbols for buttons. But you can change back to text with use_unicode_symbols = False. Two new buttons for direct entry and recall of items on the favorites screen. A new window to display saved stations, favorites and dx cluster data below the frequency axis. A feature to query a dx cluster using telnet, and display the stations. The symbols use Unicode, and were tested on Linux and Windows, and on computers in Germany and the USA. But if your Windows does not support Unicode, you will need to add use_unicode_symbols = False. Read quisk_conf_defaults.py (as usual), and look for quisk_typeface, btn_text_, use_unicode_symbols, sym_stat_, station_display_lines, and dxClHost to see how to use these features by Christof. Quisk Version 3.6.10 May 2013 ============================= I made some changes to my n2adr hardware and widget files. I increased the timeout for select() in the UDP code. I added a patch from David Turnbull, AE9RB, to make Quisk USB control work with the Peaberry. The problem was discovered and solved by ON7VQ. Windows changes the Documents folder name for different languages, and has no standard way to find it. I added "Mine Dokumenter" to the list. The AGC release time and mic gain control are now parameters in the config file. I added some features from Christof, DJ4CM: additional color control, double click tune on favorites screen, and format changes. Quisk Version 3.6.9 April 2013 ============================== The new config file parameter digital_output_level controls the sound level to Fldigi, etc. I fixed some small bugs in the Windows DirectX sound system. When using the Split feature, Quisk can now receive on both the Rx and the Tx frequencies, and play them in stereo. When working DX, you can now hear the DX in one ear and the pileup in the other. I like the lower frequency signal to be left, and the higher one right. This is controlled by the new config file option split_rxtx that can be 1, 2, 3 or 4. See the file quisk_conf_defaults.py (as usual). This version of Quisk supports the new features in my HiQSDR FPGA firmware version 1.4. If you are using Quisk to set your hardware IP to rx_udp_ip, please be sure that rx_udp_ip_netmask is correct. The default is 255.255.255.0. Quisk Version 3.6.8 March 2013 ============================== The new config file parameter button_font_size can be changed to reduce the size of the button font. This is useful for a netbook when the lower screen resolution results in crowded buttons. There is a new button "Notch" for an automatic notch filter to get rid of carriers in SSB signals. It works in CW too, but is less useful because the sharp filters can get rid of unwanted signals. The "Notch" is an advanced feature based on the FFT and not the LMS algorithm. Quisk Version 3.6.7 February 2013 ================================= I added a check for the correct wx version. Thanks to Mario, DH5YM. Selecting "Config/Favorites/TuneTo" now changes to the configured default_screen instead of the waterfall screen. Thanks to Detlef, DL7IY. The mute button and volume now controls only the radio sound, and not the digital output. Thanks to Mario, DH5YM. Previously, Fldigi XML-RPC control only worked if a digital mode was selected and a digital audio device was specified. Now it is always active unless you turn it off in the config file. The transmit power level and the digital transmit power level can now be adjusted on the config screen. The levels are a percentage of tx_level as set in the config file. The meaning of digital_tx_level was changed. It is now the maximum percentage value for the slider. Thanks to Hubert, DG7MGY. There is a new feature to save frequencies and return to them. When you have tuned in a signal of interest, press the "Save" button to save the frequency, band and mode. Repeat for more signals. Now press "Next", to switch to the next saved signal, and press "Next" repeatedly to cycle through the list. To delete a saved signal, first tune to it with "Next" and then press "Delete". If you save a large number of signals, right click the "Next" button, and you will get a popup menu so you can jump directly to a station. Thanks to Detlef, DL7IY. I had to renumber the columns for the Quisk buttons. That won't matter to you unless you add your own widgets to the bottom of the screen by importing your own quisk_widgets. Then you will need to renumber your columns. See n2adr/quisk_widgets.py for an example. Quisk Version 3.6.6 January 2013 ================================ I corrected the frequency measurement feature so it works with RIT. This feature was successfully verified in the November 2012 ARRL Frequency Measurement Test. I fixed a bug in Fldigi frequency control thanks to Hubert, DG7MGY. The config file has a new parameter mouse_wheelmod to control the mouse wheel sensitivity. Thanks to DG7MGY for the patch. I changed the digital filters so they have a bandwidth up to 20 ksps. This accommodates more digital modes. There are now three digital modes: DGT-U and DGT-L decode the audio as upper or lower sideband. The old DGTL mode is now DGT-U. The mode DGT-IQ does not decode. It sends the I/Q samples directly to the sound card device. It is interesting to listen to the DGT-IQ signal, as it provides binaural reception. Also, the PTT can be controlled by either Quisk or Fldigi, not just by Quisk. There is a new tab on the Config screen where you can enter the frequencies and modes for favorite stations. This can be used to list and tune to repeaters or nets. The page works like a spreadsheet. Fill in the rows with an arbitrary name, the frequency as integer Hertz or decimal megahertz, the mode and an arbitrary description. Right click on the left row label for a popup menu that allows you tune to that row. Thanks to Brian KF7WPK for suggesting this feature. Quisk Version 3.6.5 November 2012 ================================= I added a waterfall method ChangeRfGain() that enables you to keep the waterfall colors constant for changes in the RF gain control. See my n2adr directory for an example of how to use it. I added the ability to connect Quisk to the hamlib rigctld daemon. This enables Quisk to work with any rig compatible with hamlib. For an example, see quisk_conf_kx3.py. Push the Help button for documentation. I added a feature to measure the frequency of a continuous RF signal. Right click the S-meter window to turn it on. Push the Help button for documentation. It is meant for precise frequency measurement such as would be needed to characterize crystals for a filter. Precision is 0.01 Hertz. Quisk Version 3.6.4 September 2012 ================================== I added Hamlib control to Quisk. Set your digital or logging program to rig2, device localhost:4575. See the Help and docs.html. This is used to control Quisk from other digital mode programs such as WSPR. I added the Y scale to the graph above the waterfall. Quisk can now record the speaker audio and the digital samples to a WAV file. Set the file names using the config screen, and then use the "FileRec" button to start recording. Press the Help button for more information. Quisk Version 3.6.3 July 2012 ============================= Thanks to Steve Murphy, KB8RWQ for the patch adding additional color control, and for his dark color design. I am using Quisk with my AR8600 receiver 10.7 MHz IF output as a general coverage receiver. My config file is n2adr/quisk_conf_8600.py. This covers the VHF and UHF bands, and so I needed to add some FM repeater and scanner features. I added a Squelch button for FM. Right-click the button to adjust the squelch level. The Squech and AGC buttons are combined to save space. The new configuration file items freq_spacing and freq_base are used to round frequencies to channel spacings on VHF. There is scanner logic in my config file. You should look at this if you use Quisk with a transverter for the higher bands. With my hardware it is able to scan known repeater frequencies jumping across bands as it scans. The 960 ksps rate of Quisk and HiQSDR is very useful at VHF and higher. I added tabs to the config screen, and cleaned it up. I added a record and playback button. Press Record to start a new recording of radio sound. The maximum recording length is set in the config file, and the default is 15 seconds. After this limit, the most recent 15 seconds of sound is retained. To play the recorded sound, press the Play button. If you are transmitting, the recorded sound is transmitted provided the microphone and playback sample rate are both 48000 sps. The transmitted recorded sound is not subjected to the usual audio processing. That means that you can play another ham's audio back and give him/her a good idea of how it sounds. Quisk Version 3.6.2 May 2012 ============================ I added a display of the filter bandwidth to the graph screen. This is based on code provided by Terry Fox, WB4JFI. Thanks Terry! See the file quisk_conf_defaults.py. I added detailed information on each sound device to the config screen. The Test button now generates AM and FM as well as CW and SSB. The receive filtering has been re-written to improve the shape of the filters and to reduce the CPU time. Quisk now runs on my fan-less Shuttle Atom machine at speeds up to 480 ksps. The CW filters are particularly nice. Quisk Version 3.6.1 April 2012 ============================== There is a new "DGTL" mode to send Quisk audio to an external digital mode program such as Fldigi. Read the file quisk_conf_defaults.py to see the new config file options available. Use the Help button for basic information, and see docs.html. I changed the 60 meter operation to agree with new FCC rules (for the USA). See the configuration file for items to control 60 meters. Quisk Version 3.6.0 March 2012 ============================== There are no new user features in this release, and no changes to the HiQSDR code. This version adds a new feature for those writing C-language extension modules that need to access C code from the _quisk extension module. Examples are the SDR-IQ and the Charleston extension modules. This feature was requested by Maitland Bottoms, AA4HS, and he also provided patches. Previously, symbols from the _quisk module were linked to sub-modules with the C linker. Now _quisk exports symbols using the Python CObject or Capsule interface. The documentation is in import_quisk_api.c. Only minimal changes to extension modules are required, as most changes are in _quisk. The linker method still works on Linux, but the new interface is highly recommended. Quisk Version 3.5.12 February 2012 ================================== There are no changes to Quisk, but this version includes the new Quisk VNA program that enables you to use my original transceiver hardware and the newer HiQSDR hardware as a vector network analyzer. Use "python quisk_vna.py" to run it. Quisk Version 3.5.11 December 2011 ================================== I fixed a bug that caused the microphone to freeze when sending the mic sound to the SoftRock for transmit. Quisk Version 3.5.10 December 2011 ================================== Lucian Langa contributed a patch to return the primary display size for dual displays. If you decreased graph_width for dual displays you will need to change it back to 0.80 (or similar). I improved the transmit audio filters to reduce spurs and decrease processing time. The mic sample rate can now be either 48000 (as before) or 8000 samples per second. The plan is to make Quisk run effectively on small laptops or even tablet computers. Remember to adjust mic_clip and mic_preemphasis in your config file. Quisk Version 3.5.9 November 2011 ================================= I fixed a bug in Windows that occurs only when using the mic for transmit. Quisk Version 3.5.8 October 2011 ================================ The Windows version is now equal to the Linux version, and transmits properly. I added a parameter agc_off_gain to the config file. It controls the audio gain when AGC is off. Reduce it if sound with AGC off is too loud. Note that even with AGC off, the output is limited to the clip level. I made some other improvements to AGC. I added FM transmit. The modulation index can be set in your config file. I made some improvements to demodulation, and to the SSB transmit filter. I fixed an array out of bounds bug in transmit. Quisk Version 3.5.7 September 2011 ================================== This is a quick release to fix two bugs in 3.5.6, the message "expected integer" and faint audio for FM. I also added a new parameter agc_max_gain to the default configuration file to control the scale of the AGC slider. Quisk Version 3.5.6 September 2011 ================================== The Spot button now has a level adjustment instead of fixed values. Right-click the button to adjust. There are now three buttons with a slider adjustment, namely AGC, Spot and the right-most filter button. I added a feature to measure and remove any DC component in the UDP samples. I fixed a problem with the waterfall display when zoomed and using band up-down. There is a new adjustable AGC control. Right click it to show the slider adjustment. The full up position corresponds to the old AGC 1. I removed the 1650 Hertz offset when transmitting SSB. It was not necessary and cluttered the code. Quisk Version 3.5.5 July 2011 ============================= These changes only affect the N2ADR 2010 transceiver and the improved version, the HiQSDR. I moved all the files into a new package directory hiqsdr. The old n2adr directory has only the special files I use at my shack. Please change your config file as follows: from hiqsdr import quisk_hardware # Special hardware file use_rx_udp = 1 # Use this for the N2ADR-2010 use_rx_udp = 2 # Use this for the HiQSDR The sample config file quisk_conf.py in hiqsdr can be used as is for the HiQSDR. There is a new dictionary tx_level in the config file to set the transmit level. See quisk_conf_defaults.py for other features that can be set for the HiQSDR. There is a new FPGA firmare version 1.1 available to support the new HiQSDR features. Note that your firmware version is shown on the Config screen. It is not necessary to update your firmware unless you use the HiQSDR and you want the new HiQSDR control lines to work. If you do update your firmware, you must run Quisk 3.5.5 or later. Quisk Version 3.5.4 June 2011 ============================= I added another slider labeled "Zo" to zoom (expand) the graph screen scale so that narrow signals can be examined. The center of the graph is changed to the tuning frequency when zoom is turned on. To cancel zoom, move the slider back to the bottom position. You can tune as usual even if zoom is on. I put the band buttons on one line so I could add more control buttons. Quisk Version 3.5.3 May 2011 ============================ I added "Documents" as a possible config file location (for Windows 7). These changes are specific to my 2009/2010 transceiver hardware: I now detect and display the firmware version. The files conf_transceiver.py and hardware_transceiver.py are now the basic config and hardware files for my transceiver. The spot button now appears without a special widgets file, so no widgets file is necessary. The file quisk_hardware.py is still the hardware file used in my station, but it is mostly useful as an example of what is possible, not as a starting point for use by others. Quisk Version 3.5.2 April 2011 ============================== I added code from Ethan Blanton, KB8OJH, to provide direct frequency control of the Si570 chip in many SoftRocks. I added AM transmit and improved AM receive. I added FM de-emphasis to receive. I added a noise blanker. It is now possible to delay samples (tx_channel_delay) and correct the amplitude and phase for the sound card play device (SoftRock transmit). Unfortunately receive sound card corrections will need to be re-entered. The filter bandwidths for each mode can now be set in the config file. And you can right-click the right-most filter button to adjust its bandwidth. Quisk Version 3.5.1 February 2011 ================================= The phase correction control has been improved to allow multiple correction points per band. Unfortunately this will require re-entering corrections. I added mic_preemphasis and mic_clip to the config file to control Tx audio processing. Quisk Version 3.5.0 January 2011 ================================ Starting with this version, a Windows version of Quisk is available (alpha code). I changed the amplitude/phase correction control, and added config file options (rx_max_phase_correct) to control the maximum available correction. Quisk Version 3.4.14 January 2011 ================================= The "alsa:" names can now be used for mixer settings. I added simplified config and hardware files for my 2010 transceiver hardware. I moved the one sample delay for some sound cards into the config file instead of using the #define FIX_H101 (which remains for backward compatibility). I added more buttons "GraphP2" to the Graph button to activate a peak hold function. There are config file options graph_peak_hold_1 and _2 to control the time constant. Quisk Version 3.4.13 December 2010 ================================== I decreased the microphone speech processing preemphasis and clipping. I added a config parameter key_poll_msec to control the SoftRock USB poll for key status. I improved the config screen. Alsa names can now be strings like "alsa:NVidia" that match the card/device info. Thanks to Joachim Schneider, DB6QS, I made some improvements to SoftRock USB control. Quisk Version 3.4.11 November 2010 =============================== Thanks to Sid Boyce, G3VBV, for sending me SoftRock hardware to work with. The "mic_play" logic was re-written so that transmit I/Q samples can be sent from a sound card to hardware that uses QSD up-conversion. I added USB access through pyusb to control recent SoftRock models. A new package "softrock" directly supports several SoftRock models. Change Spot Button to transmit at carrier frequency. Add a Split button to enable split receive and transmit frequencies. Fix band change data for pan adapter users. Try to make easy_install work better. Quisk Version 3.4.8 August 2010 =============================== A new config file option "playback_rate" can set the radio sound play rate. I added a button to the config screen to change the decimation rate for hardware that supports this. See the new "VarDecim" methods in quisk_hardware_model.py. I added this feature to the SDR-IQ hardware file sdriqpkg/quisk_hardware.py, and to n2adr/quisk_hardware.py. Thanks to John Nogatch AC6SL for a bug fix. Quisk Version 3.4.6 July 2010 ============================= I improved the mouse tuning by eliminating a tendency to tune backward. I made the sdriq extension and my n2adr code into packages in the directories "sdriqpkg" and "n2adr". The new package architecture will make it easier for authors to write Quisk extensions. See the example config files quisk_conf_sdriq.py and quisk_conf_n2adr.py to see how to change your imports: from sdriqpkg import sdriq from sdriqpkg import quisk_hardware from n2adr import quisk_hardware from n2adr import quisk_widgets Thanks to Terry Fox, WB4JFI, for improvements to Quisk: Code to support the Charleston hardware (libusb-dev required). Code to add a third FFT data block. Quisk Version 3.4.3 June 2010 ============================= The hardware open() method now returns a string for the config screen. If you have a custom hardware file, create a string or return the base class string. I made the SDR-IQ code into a separate Python extension module "sdriq". This module can serve as a model for other hardware extensions. It is the model for the Charleston hardware extension module. The sdriq.so file needs _quisk.so, so put both in the same directory. I corrected the decimation for sample rates greater than 240 ksps, and improved the filters for all decimations to reduce "images". The following changes are only relevant if you use the SDR-IQ for capture: You need to add these lines to your config file (see quisk_hardware_defaults.py): import quisk_hardware_sdriq as quisk_hardware display_fraction = 0.85 There is now a special hardware file for the SDR-IQ. If you have a custom hardware file that uses the SDR-IQ you need to use quisk_hardware_sdriq as its base class (instead of quisk_hardware_model). [See version 3.4.5 for further SDR-IQ changes] Quisk Version 3.4.2 May 2010 ============================ The config file has a new option to add an external demodulation module. I I added the ability to play in stereo, and corrected the sidetone logic. The config file has a new option to add a full duplex button. I added the ability to use PortAudio for sound card access. PortAudio can also be used to connect Quisk to other programs. I added a key up delay to the is_key_down() serial port code and fixed a sound card CW bug. A new config file entry can make amplitude/phase corrections independent of band. This is needed for a panadapter. I fixed the compressed graph labels at high sample rates. Quisk Version 3.3.7 April 2010 ================================= If you get samples from a UDP port, you can specify the decimation rate in the config file. If you send samples to a sound card for transmit, CW now works (as does SSB). Quisk Version 3.3.6 February 2010 ================================= I added BandEdge to the config file, and added code to Quisk to make the frequency and band changes more rational. I changed the config file attribute freqTime to bandTime (see changes). You can now define a class named "Hardware" in your config file, and then you don't need a separate hardware file. This is only recommended for simple hardware needs. See docs.html. If you use the microphone and send samples with UDP, the audio is now centered at 1650 Hertz, and you must add/subtract this offset when setting the transmit frequency. A number of valuable patches were submitted by Andrew Nilsson, VK6JBL, and these were incorporated into Quisk: The band buttons displayed can be changed in the config file (bandLabels). The 6 meter band was added (change bandLabels to show it). Turn on add_imd_button in the config file to generate 2-tone test signals. The two new functions QS.capt_channels(i, q) and QS.play_channels(i, q) will set the capture and playback channel numbers at any time. If you set the key method to "", the new function QS.set_key_down(1) will set the key state up or down. This enables you change the key state using either C or Python; for example, to add a "MOX" button. The microphone samples can now be output to a sound card for transmit. See the additional items in the config file. The new config file parameter mouse_tune_method causes mouse drag tuning to change the VFO frequency, not the Quisk tuning frequency. I moved microphone_name and tx_ip (for the microphone) to the config file from the hardware file so that all the mic parameters are together. Quisk Version 3.3.1 December 2009 ================================= For sound card input, I added controls to correct amplitude and phase balance. Press the new button on the config screen. A different correction is saved for each band. See the help file. I added the new band "Audio". It sets the VFO frequency to zero and is meant to be used with a sound card. I changed the WWV and CHU bands to a new Time band. The time frequencies are named freqTime and can be changed in your config file. In the file quisk_conf_defaults.py I changed the default for persistent_state to True, and added graph_width=0.8 to specify the graph width. A period "." in the frequency entry box means megahertz. Quisk Version 3.3.0 November 2009 ================================= I fixed a bug in the SDR-IQ decimation that produced slight audio distortion at decimations other than 500. If the play device is the null string "", Quisk no longer tunes and demodulates the signal. This saves CPU cycles when Quisk is used as a panadapter. I added decimation (reduction of sample rate) before the filters so that Quisk can handle higher sample rates or slower computers. I made the waterfall into a splitter window with a graph display at the top. There are new attributes in the config file to control this feature. The numeric value of Ys and Yz are now shown so that the values can be added to the config file more easily. There is a new config option to save the state (band, frequency, etc.) on exit, and restore it on startup. Only certain bits of state are saved; the others are still taken from the config file. The default config file sets fft_size_multiplier to zero, and this specifies that Quisk should calculate it for you. Quisk Version 3.2.3 September 2009 ================================== Fixed a bug that prevented tuning the SDR-IQ when using the default hardware file. Started adding code to capture sound from a UDP socket. Quisk Version 3.2.2 June 2009 ============================= The microphone access was re-written to make it work with more sound cards. The config file has a new parameter "mic_channel_I" to specify which sound card channel is used for the mic. Added Documentation.html. Fixed lack of poll to ReturnFrequency(). Quisk Version 3.2 May 2009 ========================== Quisk now uses wxPython instead of Tkinter for its graphical user interface. You must install the python-wxgtk2.8 package. Get the latest version available. If you still want to run the Tkinter version, it is quisk_tk.py. The wxPython version is much faster. Quisk now runs in two threads; a GUI thread and a sound thread. I moved the colors to the config file so you can change the colors more easily. Quisk Version 3.1 April 2009 ============================= New hardware file to control the AOR AD8600. I added filtering to FM audio to remove CTCSS tones and provide -6 dB / octave de-emphasis. I removed the tkdirect C-language module and replaced it with a pure Python equivalent. This reduces compilation problems. I improved the speed of the screen updates so that Quisk will run without clicks on slower computers. Quisk Version 3.0.0 April 2009 =============================== Thanks to Leigh L. Klotz, Jr. WA5ZNU, my special hardware control was removed to separate files so that Quisk now has a cleaner design that is more useful to others. quisk-3.6.11/__init__.py0000666000175000017500000000002612164330433014430 0ustar jimjim00000000000000#QUISK version 3.6.11 quisk-3.6.11/microphone.h0000666000175000017500000000004411670372610014637 0ustar jimjim00000000000000// Filters were moved to filter.c. quisk-3.6.11/quisk_conf_defaults.py0000666000175000017500000010234612160323316016727 0ustar jimjim00000000000000# Please do not change the configuration file quisk_conf_defaults.py. # Instead copy one of the other quisk_conf_*.py files to your own # .quisk_conf.py and make changes there. For a normal sound card # configuration, copy quisk_conf_model.py to your .quisk_conf.py. # # Quisk imports quisk_conf_defaults to set its configuration. # If you have a configuration file, it then overwrites the defaults # with your parameters. Your configuration file must be named # ~/.quisk_conf.py, where "~" means your home directory. Or # you may specify a different name with the -c or --config command # line option. Try --help. Check the config screen to make sure that # the correct configuration file is in use. # # The Quisk receiver can use a high quality sound card for capture and playback, # or it can use the SDR-IQ by RfSpace for capture and a lower quality # sound card for playback. Quisk can also be used as a panadapter. # Quisk can control some rigs. See quisk_hardware_*.py. If you have a rig # to control, copy one of the quisk_hardware_*.py files to your own file named # quisk_hardware.py, and edit that file. If there is no quisk_hardware.py, then # quisk_hardware_model.py is used instead. import sys # Import the default Hardware module. You can import a different module in # your .quisk_conf.py. import quisk_hardware_model as quisk_hardware # Module for additional widgets (advanced usage). See n2adr/quisk_widgets.py for an example. # import n2adr.quisk_widgets as quisk_widgets quisk_widgets = None # Select the default screen when Quisk starts: default_screen = 'Graph' #default_screen = 'WFall' #default_screen = 'Config' # The width of the graph data as a fraction of the total screen size. This # will be adjusted by Quisk to accommodate preferred FFT sizes. It can # not be changed once Quisk starts. It can not be made too small because # of the space needed for all the buttons. graph_width = 0.8 # The graph_width parameter controls the width of Quisk unless a larger width is forced. # If the Quisk screen is too wide or the buttons are too crowded, perhaps due to a low screen # resolution, you can reduce the font sizes. Thanks to Christof, DJ4CM. button_font_size = 10 # button_font_size = 9 # button_font_size = 8 default_font_size = 12 status_font_size = 14 config_font_size = 14 graph_font_size = 10 favorites_font_size = 14 # This controls the speed of the graph peak hold. Lower numbers give a longer time constant. graph_peak_hold_1 = 0.25 graph_peak_hold_2 = 0.10 # Select the default mode when Quisk starts (overruled by persistent_state): # default_mode = 'FM' default_mode = 'USB' # Select the way the waterfall screen scrolls: # waterfall_scroll_mode = 0 # scroll at a constant rate. waterfall_scroll_mode = 1 # scroll faster at the top so that a new signal appears sooner. # Select the initial size in pixels (minimum 1) of the graph at the top of the waterfall. waterfall_graph_size = 80 # These are the initial values for the Y-scale and Y-zero sliders for each screen. # The sliders go from zero to 160. graph_y_scale = 100 graph_y_zero = 0 waterfall_y_scale = 80 waterfall_y_zero = 40 waterfall_graph_y_scale = 100 waterfall_graph_y_zero = 60 scope_y_scale = 80 scope_y_zero = 0 # Currently doesn't do anything filter_y_scale = 90 filter_y_zero = 0 # Quisk can save its current state in a file on exit, and restore it when you restart. # State includes band, frequency and mode, but not every item of state (not screen). # The file is .quisk_init.pkl in the same directory as your config file. If this file # becomes corrupted, just delete it and it will be reconstructed. #persistent_state = False persistent_state = True # The quisk config screen has a "favorites" tab where you can enter the frequencies and modes of # stations. The data is stored in this file; default quisk_favorites.txt in the directory # where your config file is located. favorites_file_path = '' # These control the typeface used in fonts. The objective is to choose an available font that # offers good support for the Unicode characters used on buttons and windows. if sys.platform == "win32": quisk_typeface = 'Lucida Sans Unicode' # Typeface for quisk buttons and text #quisk_typeface = 'Arial Unicode MS' else: quisk_typeface = '' # Use a default typeface # This controls whether the "U" symbols or the "T" symbols are used on buttons and windows. # You can change the "U" and "T" symbols to anything you want; either Unicode or text. use_unicode_symbols = True # Use the symbols starting with "U" #use_unicode_symbols = False # Use the symbols starting with "T" # These are the Unicode symbols used in the station window. Thanks to Christof, DJ4CM. Usym_stat_fav = unichr(0x2605) # Symbol for favorites, a star Usym_stat_mem = unichr(0x24C2) # Symbol for memory stations, an "M" in a circle #Usym_stat_dx = unichr(0x2691) # Symbol for DX Cluster stations, a flag Usym_stat_dx = unichr(0x25B2) # Symbol for DX Cluster stations, a Delta # These are the text symbols used in the station window. Tsym_stat_fav = 'F' Tsym_stat_mem = 'M' Tsym_stat_dx = 'Dx' # These are the Unicode symbols to display on buttons. Thanks to Christof, DJ4CM. Ubtn_text_range_dn = unichr(0x2190) # Down band, left arrow Ubtn_text_range_up = unichr(0x2192) # Up band, right arrow Ubtn_text_play = unichr(0x25BA) # Play button Ubtn_text_rec = unichr(0x25CF) # Record button, a filled dot Ubtn_text_file_rec = "File " + unichr(0x25CF) # Record to file Ubtn_text_fav_add = unichr(0x2605) + unichr(0x2191) # Add to favorites Ubtn_text_fav_recall = unichr(0x2605) + unichr(0x2193) # Jump to favorites screen Ubtn_text_mem_add = unichr(0x24C2) + unichr(0x2191) # Add to memory Ubtn_text_mem_next = unichr(0x24C2) + unichr(0x27B2) # Next memory Ubtn_text_mem_del = unichr(0x24C2) + unichr(0x2613) # Delete from memory # These are the text symbols to display on buttons. Tbtn_text_range_dn = "Dn" Tbtn_text_range_up = "Up" Tbtn_text_play = "Play" Tbtn_text_rec = "Rec" Tbtn_text_file_rec = "File Rec" Tbtn_text_fav_add = ">Fav" Tbtn_text_fav_recall = "Fav" Tbtn_text_mem_add = "Save" Tbtn_text_mem_next = "Next" Tbtn_text_mem_del = "Del" # Station info display configuration, thanks to DJ4CM. This displays a window of station names # below the graph frequency (X axis). station_display_lines = 1 # number of station info display lines below the graph X axis #station_display_lines = 0 #station_display_lines = 3 # DX cluster telent login data, thanks to DJ4CM. Must have station_display_lines > 0. dxClHost = '' # host name for telnet server, null string to disable #dxClHost = 'example.host.net' dxClPort = 7373 # port number for telnet user_call_sign = 'CALL' # your radio station call sign; probably needed for telnet login dxClPassword = None # telnet password dxClExpireTime = 20 # Time in minutes until DX Cluster entries will be removed # This converts from dB to S-units for the S-meter (it is in S-units). correct_smeter = 15.5 # This is the fraction of spectrum to display from zero to one. It is needed if # the passband edges are not valid. Use 0.85 for the SDR-IQ. display_fraction = 1.00 # Quisk has record and playback buttons to save radio sound. If there is no more room for # sound, the old sound is discarded and the most recent sound is retained. This controls # the maximum length of sound storage in minutes. If you want to transmit recorded sound, # then mic_sample_rate must equal playback_rate and both must be 48000. max_record_minutes = 0.25 # Thanks to Steve Murphy, KB8RWQ for the patch adding additional color control. # Thanks to Christof, DJ4CM for the patch adding additional color control. # Define colors used by all widgets in wxPython colour format: color_bg = 'light steel blue' # Lower screen background color_graph = 'lemonchiffon1' # Graph background color_config2 = 'lemonchiffon3' # color in tab row of config screen color_gl = 'grey' # Lines on the graph color_graphticks = 'black' # Graph ticks color_graphline = '#005500' # graph data line color color_graphlabels = '#555555' # graph label color color_btn = 'steelblue2' # button color color_check_btn = 'yellow2' # color of a check button when it is checked color_cycle_btn = 'goldenrod3' # color of a cycle button when it is checked color_adjust_btn = 'orange3' # color of an adjustable button when it is checked color_test = 'hot pink' # color of a button used for test (turn off for tx) color_freq = 'lightcyan1' # background color of frequency and s-meter color_freq_txt = 'black' # text color of frequency display color_entry = color_freq # frequency entry box color_entry_txt = 'black' # text color of entry box color_enable = 'black' # text color for an enabled button color_disable = 'white' # text color for a disabled button color_bandwidth = 'lemonchiffon2' # color for bandwidth display; thanks to WB4JFI #color_bandwidth = 'lemonchiffon3' color_txline = 'red' # vertical line color for tx in graph color_rxline = 'green' # vertical line color for rx in graph color_notebook_txt = 'black' # text of notebook lables # This is a dark color scheme designed by Steve Murphy, KB8RWQ. #color_bg = '#111111' #color_graph = '#111111' #color_config2 = color_bg #color_gl = '#555555' #color_graphticks = '#DDDDDD' #color_graphline = '#00AA00' #color_graphlabels = '#FFFFFF' #color_btn = '#666666' #color_check_btn = '#996699' #color_cycle_btn = '#666699' #color_adjust_btn = '#669999' #color_test = 'hot pink' #color_freq = '#333333' #color_freq_txt = 'white' #color_entry = color_freq #color_entry_txt = color_freq_txt # text color of entry box #color_enable = 'white' #color_disable = 'black' #color_bandwidth = '#333333' #color_txline = 'red' #color_rxline = 'green' #color_notebook_txt = 'white' # text of notebook lables filter_display = 1 # Display the filter bandwidth on the graph screen; 0 or 1; thanks to WB4JFI # Quisk can operate in Split mode and can receive both the Tx and Rx frequency signals. This option # controls where the sound goes. You may need to try 1 or 2 depending on your wiring. #split_rxtx = 1 # Play both signals in stereo with the higher frequency on the real channel. split_rxtx = 2 # Play both signals in stereo with the lower frequency on the real channel. #split_rxtx = 3 # Play the receive signal on both channels. #split_rxtx = 4 # Play the transmit signal on both channels. # These are the palettes for the waterfall. The one used is named waterfallPallette, # so to use a different one, overwrite this name in your .quisk_conf.py. waterfallPalette = ( ( 0, 0, 0, 0), ( 36, 85, 0, 255), ( 73, 153, 0, 255), (109, 255, 0, 128), (146, 255, 119, 0), (182, 85, 255, 100), (219, 255, 255, 0), (255, 255, 255, 255) ) digipanWaterfallPalette = ( ( 0, 0, 0, 0), ( 32, 0, 0, 62), ( 64, 0, 0, 126), ( 96, 145, 142, 96), (128, 181, 184, 48), (160, 223, 226, 105), (192, 254, 254, 4), (255, 255, 58, 0) ) # Quisk can access your sound card through PortAudio or through ALSA drivers. # In PortAudio, soundcards have an index number 0, 1, 2, ... and a name. # The name can be something like "HDA NVidia: AD198x Analog (hw:0,0)" or # "surround41". In Quisk, all PortAudio device names start with "portaudio". # A device name like "portaudio#6" directly specifies the index. A name like # "portaudio:text" means to search for "text" in all available devices. And # there is a default device "portaudiodefault". So these portaudio names are useful: #name_of_sound_capt = "portaudio:(hw:0,0)" # First sound card #name_of_sound_capt = "portaudio:(hw:1,0)" # Second sound card, etc. #name_of_sound_capt = "portaudio#1" # Directly specified index #name_of_sound_capt = "portaudiodefault" # May give poor performance on capture # In ALSA, soundcards have these names. The "hw" devices are the raw # hardware devices, and should be used for soundcard capture. #name_of_sound_capt = "hw:0" # First sound card #name_of_sound_capt = "hw:1" # Second sound card, etc. #name_of_sound_capt = "plughw" #name_of_sound_capt = "plughw:1" #name_of_sound_capt = "default" # Normally you would capture and play on the same soundcard to avoid problems with the # two clocks running at slightly different rates. But you can define name_of_sound_play # to play back on a different device. Define this as the empty string "" to turn off # play (for a panadapter). # # For the SDR-IQ the soundcard is not used for capture; it only plays back audio. # Quisk has a custom decimation scheme for each sample rate. The allowable sample rates # are the four SDR-IQ rates plus 24, 48, 96, 192, 240, 384, 480, and 960 ksps. Other rates # can be added. # Configuration for soundcard capture and playback use_sdriq = 0 # Get ADC samples from SDR-IQ is not used use_rx_udp = 0 # Get ADC samples from UDP is not used sample_rate = 48000 # ADC hardware sample rate in Hertz if sys.platform == "win32": name_of_sound_capt = "Primary" else: name_of_sound_capt = "hw:0" # Name of soundcard capture hardware device. name_of_sound_play = name_of_sound_capt # Use the same device for play back #name_of_sound_play = "" # Panadapter: Do not play channel_i = 0 # Soundcard index of in-phase channel: 0, 1, 2, ... channel_q = 1 # Soundcard index of quadrature channel: 0, 1, 2, ... # Thanks to Franco Spinelli for this fix: # The H101 hardware using the PCM2904 chip has a one-sample delay between # channels, which must be fixed in software. If you have this problem, # change channel_delay to either channel_i or channel_q. Use -1 for no delay. channel_delay = -1 # This is for mic playback (SoftRock transmit): tx_channel_delay = -1 # If you use a soundcard with Ethernet control of the VFO, set these parameters: rx_ip = "" # Receiver IP address for VFO control # If you use an SDR-IQ for capture, see the sample config file quisk_conf_sdriq.py. # For the N2ADR 2010 transceiver described in QEX, and for the improved version HiQSDR, # see the sample config file in the hiqsdr package directory, and set these: # tx_level sets the transmit level 0 to 255 for each band. The None band is the default. # The config screen has a slider 0 to 100% so you can reduce the transmit power. The sliders # only appear if your hardware defines the method SetTxLevel(). The hardware only supports a # power adjustment range of 20 dB, so zero is still a small amount of power. tx_level = {None:120, '60':110} # Adjust your power for each band # Digital modes reduce power by the percentage on the config screen. # The maximum value of the slider is digital_tx_level. digital_tx_level = 20 # The slider on the config screen is 20% maximum. # # If you use the HiQSDR hardware, set these: # The HiQSDR_BandDict sets the preselect (4 bits) on the X1 connector. HiQSDR_BandDict = {'160':1, '80':2, '40':3, '30':4, '20':5, '15':6, '17':7, '12':8, '10':9, '6':10, '500k':11, '137k':12 } # For the original N2ADR hardware set this: # use_rx_udp = 1 # For the newer HiQSDR hardware set this: # use_rx_udp = 2 # For FPGA firmware version 1.4 and newer, the hardware is set to the rx_udp_ip you enter here. # For older firmware, the IP address is programmed into the FPGA, and you must enter that address as rx_udp_ip. rx_udp_ip = "192.168.2.196" # Sample source IP address rx_udp_ip_netmask = '255.255.255.0' # The netmask for the network of rx_udp_ip rx_udp_port = 0xBC77 # Sample source UDP port rx_udp_clock = 122880000 # ADC sample rate in Hertz sndp_active = True # Enable setting the hardware IP to rx_udp_ip # Thanks to Ethan Blanton, KB8OJH, for this patch for the Si570 (many SoftRock's): # If you are using a DG8SAQ interface to set a Si570 clock directly, set # this to True. Complex controllers which have their own internal # crystal calibration do not require this. si570_direct_control = False # This is the Si570 startup frequency in Hz. 114.285MHz is the typical # value from the data sheet; you can use 'usbsoftrock calibrate' to find # the value for your device. si570_xtal_freq = 114285000 # This is the received radio sound playback rate. The default will # be 48 kHz for the SDR-IQ and UDP port samples, and sample_rate for sound # card capture. Set it yourself for other rates or hardware. # The playback_rate must be 24000, 48000, 96000 or 192000. # The preferred rate is 48000 for use with digital modes and transmit of recorded audio. # playback_rate = 48000 # If you use quisk_hardware_fixed.py, this is the fixed VFO frequency in Hertz fixed_vfo_freq = 7056000 # Some hardware must be polled to get the key up/down state. This is the time # between polls in milliseconds. Use zero to turn off the poll. key_poll_msec = 0 # This determines what happens when you tune by dragging the mouse. The correct # choice depends on how your hardware performs tuning. You may want to use a # custom hardware file with a custom ChangeFrequency() method too. mouse_tune_method = 0 # The Quisk tune frequency changes and the VFO frequency is unchanged. #mouse_tune_method = 1 # The Quisk tune frequency is unchanged and the VFO changes. # configurable mouse wheel thanks to DG7MGY mouse_wheelmod = 50 # Round frequency when using mouse wheel (50 Hz) # If freq_spacing is not zero, frequencies are rounded to the freq_base plus the # freq_spacing; frequency = freq_base + N * freq_spacing. This is useful at # VHF and higher when Quisk is used with a transverter. freq_spacing = 0 freq_base = 0 # This is the CW tone frequency in Hertz cwTone = 600 # These options are used by the digital modes that send audio to an external # program, and receive audio to transmit. Set Fldigi to USB, XML-RPC control. digital_xmlrpc_url = "http://localhost:7362" # URL for control by XML-RPC #digital_xmlrpc_url = "" # Do not poll socket for XML-RPC control # Input audio from an external program for use with digital modes. The input must be # stereo at 48000 sps, and you must set mic_sample_rate to 48000 also. digital_input_name = "" # device name for transmit audio # digital_input_name = 'hw:Loopback,0' # Output audio to an external program for use with digital modes. The output is # stereo at the same sample rate as the radio sound playback. digital_output_name = "" # device name for received audio # digital_output_name = digital_input_name digital_output_level = 0.7 # This is the volume control 0.0 to 1.0 for digital playback to fldigi, etc. # You can control Quisk from Hamlib. Set the Hamlib rig to 2 and the device for rig 2 to # localhost:4575, or other hamlib_port as used by Quisk. hamlib_port = 4575 # Standard port for Quisk control. Set the port in Hamlib to 4575 too. #hamlib_port = 4532 # Default port for rig 2. Use this if you can not set the Hamlib port. #hamlib_port = 0 # Turn off Hamlib control. # If you use the microphone feature, the mic_channel_I and Q are the two capture # microphone channels. Quisk uses a monophonic mic, so audio is taken from the I # channel, and the Q channel is (currently) ignored. It is OK to set the same # channel number for both, and this is necessary for a USB mono mic. The mic sample rate # should be 48000 to enable digital modes and the sound recorder to work, but 8000 can be used. # Mic samples can be sent to an Ethernet device (use tx_ip and name_of_mic_play = "") # or to a sound card (use name_of_mic_play="hw:1" or other device). # If mic samples are sent to a sound card for Tx, the samples are tuned to the audio # transmit frequency, and are set to zero unless the key is down. # If there is no mic (microphone_name = ""), it is still possible to transmit CW, # and you should set mic_playback_rate to the I/Q receive capture rate. # Microphone capture: microphone_name = "" # Name of microphone capture device (or "hw:1") mic_sample_rate = 48000 # Microphone capture sample rate in Hertz, should be 48000, can be 8000 mic_channel_I = 0 # Soundcard index of mic capture audio channel mic_channel_Q = 0 # Soundcard index of ignored capture channel # Microphone samples sent to soundcard: name_of_mic_play = "" # Name of play device if mic I/Q is sent to a sound card mic_playback_rate = 48000 # Playback rate must be a multiple 1, 2, ... of mic_sample_rate mic_play_chan_I = 0 # Soundcard index of mic I play channel mic_play_chan_Q = 1 # Soundcard index of mic Q play channel mic_out_volume = 0.7 # Microphone output volume (after all processing) as a fraction 0.0 to 0.7 # Microphone samples sent to UDP: tx_ip = "" # Transmit IP address for mic sent to UDP (or "192.168.2.195") tx_audio_port = 0 # UDP port for mic samples (or 0x553B) # Microphone audio processing: # The original audio processing used mic_clip = 4.0; mic_preemphasis = -1.0 # For no mic audio processing, use mic_clip = 1.0; mic_preemphasis = 0.0 mic_clip = 3.0 # Mic amplitude clipping; larger numbers give more clipping mic_preemphasis = 0.6 # Mic pre-emphasis 0.0 (none) to 1.0; or -1.0 for a Butterworth filter # These parameters control the microphone gain adjustment. mic_avg_gain = 10.0 # Typical gain for the microphone in use mic_max_gain = 100.0 # Do not increase gain over this value # If your mixing scheme inverts the RF spectrum, set this option to un-invert it invertSpectrum = 0 # Use "amixer -c 1 contents" to get a list of mixer controls and their numid's for # card 1 (or "-c 0" for card 0). Then make a list of (device_name, numid, value) # for each control you need to set. The sample settings are for my USB microphone. #mixer_settings = [ # ("hw:1", 2, 0.80), # numid of microphone volume control, volume 0.0 to 1.0; # ("hw:1", 1, 1.0) # numid of capture on/off control, turn on with 1.0; # ] # If you want Quisk to add a button to generate a 2-tone IMD test signal, # set this to 1. This feature requires the microphone to work. add_imd_button = 0 # If you want Quisk to add a full duplex button (transmit and receive at the # same time), set this to 1. add_fdx_button = 0 # If you want to write your own I/Q filter and demodulation module, set # this to the name of the button to add, and change extdemod.c. # add_extern_demod = "WFM" add_extern_demod = "" # These are the suppressed carrier frequencies for 60 meters freq60 = (5330500, 5346500, 5357000, 5371500, 5403500) # These are the filter bandwidths for each mode. Quisk has built-in optimized filters # for these values, but you can change them if you want. FilterBwCW = (200, 400, 600, 1000, 1500, 3000) FilterBwSSB = (2000, 2200, 2500, 2800, 3000, 3300) FilterBwAM = (4000, 5000, 6000, 8000, 10000, 9000) FilterBwFM = (8000, 10000, 12000, 15000, 17000, 20000) FilterBwIMD = FilterBwSSB FilterBwDGT= (1600, 3200, 4800, 10000, 20000, 20000) FilterBwEXT = (8000, 10000, 12000, 15000, 17000, 20000) # This is the data used to draw colored lines on the frequency X axis to # indicate CW and Phone sub-bands. You can make it anything you want. # These are the colors used for sub-bands: CW = '#FF4444' # General class CW eCW = '#FF8888' # Extra class CW Phone = '#4444FF' # General class phone ePhone = '#8888FF' # Extra class phone # ARRL band plan special frequencies Data = '#FF9900' DxData = '#CC6600' RTTY = '#FF9900' SSTV = '#FFFF00' AM = '#00FF00' Packet = '#00FFFF' Beacons = '#66FF66' Satellite = '#22AA88' Repeater = '#AA00FF' # Repeater outputs RepInput = '#AA88FF' # Repeater inputs Simplex = '#00FF44' Special = 'hot pink' Other = '#888888' # Colors start at the indicated frequency and continue until the # next frequency. The special color "None" turns off color. # # To change BandPlan in your config file, first remove any frequencies in the range # you want to change; then add your frequencies; and then sort the list. Or you could just # replace the whole list. BandPlan = [ # Test display of colors #[ 0, CW], [ 50000, eCW], [ 100000, Phone], [ 150000, ePhone], [ 200000, Data], [ 250000, DxData], [ 300000, RTTY], [ 350000, SSTV], #[ 400000, AM], [ 450000, Packet], [ 500000, Beacons], [ 550000, Satellite], [ 600000, Repeater], [ 650000, RepInput], [ 700000, Simplex], #[ 750000, Other], [ 800000, Special], [ 850000, None], # 160 meters [ 1800000, Data], [ 1809000, Other], [ 1811000, CW], [ 1843000, Phone], [ 1908000, Other], [ 1912000, Phone], [ 1995000, Other], [ 2000000, None], # 80 meters [ 3500000, eCW], [ 3525000, CW], [ 3570000, Data], [ 3589000, DxData], [ 3591000, Data], [ 3600000, ePhone], [ 3790000, Other], [ 3800000, Phone], [ 3844000, SSTV], [ 3846000, Phone], [ 3880000, AM], [ 3890000, Phone], [ 4000000, None], # 60 meters [ freq60[0], Phone], [ freq60[0] + 2800, None], [ freq60[1], Phone], [ freq60[1] + 2800, None], [ freq60[2], Phone], [ freq60[2] + 2800, None], [ freq60[3], Phone], [ freq60[3] + 2800, None], [ freq60[4], Phone], [ freq60[4] + 2800, None], # 40 meters [ 7000000, eCW], [ 7025000, CW], [ 7039000, DxData], [ 7041000, CW], [ 7080000, Data], [ 7125000, ePhone], [ 7170000, SSTV], [ 7172000, ePhone], [ 7175000, Phone], [ 7285000, AM], [ 7295000, Phone], [ 7300000, None], # 30 meters [10100000, CW], [10130000, RTTY], [10140000, Packet], [10150000, None], # 20 meters [14000000, eCW], [14025000, CW], [14070000, RTTY], [14095000, Packet], [14099500, Other], [14100500, Packet], [14112000, CW], [14150000, ePhone], [14225000, Phone], [14229000, SSTV], [14231000, Phone], [14281000, AM], [14291000, Phone], [14350000, None], # 17 meters [18068000, CW], [18100000, RTTY], [18105000, Packet], [18110000, Phone], [18168000, None], # 15 meters [21000000, eCW], [21025000, CW], [21070000, RTTY], [21110000, CW], [21200000, ePhone], [21275000, Phone], [21339000, SSTV], [21341000, Phone], [21450000, None], # 12 meters [24890000, CW], [24920000, RTTY], [24925000, Packet], [24930000, Phone], [24990000, None], # 10 meters [28000000, CW], [28070000, RTTY], [28150000, CW], [28200000, Beacons], [28300000, Phone], [28679000, SSTV], [28681000, Phone], [29000000, AM], [29200000, Phone], [29300000, Satellite], [29520000, Repeater], [29590000, Simplex], [29610000, Repeater], [29700000, None], # 6 meters [50000000, Beacons], [50100000, Phone], [54000000, None], # 2 meters [144000000, CW], [144200000, Phone], [144275000, Beacons], [144300000, Satellite], [144380000, Special], [144400000, Satellite], [144500000, RepInput], [144900000, Other], [145100000, Repeater], [145500000, Other], [145800000, Satellite], [146010000, RepInput], [146400000, Simplex], [146510000, Special], # Simplex calling frequency [146530000, Simplex], [146610000, Repeater], [147420000, Simplex], [147600000, RepInput], [148000000, None], # 1.25 meters [222000000, Phone], [222250000, RepInput], [223400000, Simplex], [223520000, Data], [223640000, Repeater], [225000000, None], #70 centimeters [420000000, SSTV], [432000000, Satellite], [432070000, Phone], [432300000, Beacons], [432400000, Phone], [433000000, Repeater], [435000000, Satellite], [438000000, Repeater], [445900000, Simplex], [445990000, Special], # Simplex calling frequency [446010000, Simplex], [446100000, Repeater], [450000000, None], # 33 centimeters [902000000, Other], [928000000, None], # 23 centimeters [1240000000, Other], [1300000000, None], ] # For each band, this dictionary gives the lower and upper band edges. Frequencies # outside these limits will not be remembered as the last frequency in the band. BandEdge = { '160':( 1800000, 2000000), '80' :( 3500000, 4000000), '60' :( 5300000, 5430000), '40' :( 7000000, 7300000), '30' :(10100000, 10150000), '20' :(14000000, 14350000), '17' :(18068000, 18168000), '15' :(21000000, 21450000), '12' :(24890000, 24990000), '10' :(28000000, 29700000), '6' :(50000000, 54000000), '2' :(144000000, 148000000), } # For each band, this dictionary gives the initial center frequency, tuning # frequency as an offset from the center frequency, and the mode. This is # no longer too useful because the persistent_state feature saves and then # overwrites these values anyway. bandState = {'Audio':(0, 0, 'LSB'), '160':( 1890000, -10000, 'LSB'), '80' :( 3660000, -10000, 'LSB'), '60' :( 5370000, 1500, 'USB'), '40' :( 7180000, -5000, 'LSB'), '30':(10120000, -10000, 'CWL'), '20' :(14200000, -10000, 'USB'), '17' :(18120000, 10000, 'USB'), '15':(21250000, -10000, 'USB'), '12' :(24940000, 10000, 'USB'), '10' :(28400000, -10000, 'USB'), 'Time':( 5000000, 0, 'AM'), '6' :(50040000, 10000, 'USB'), } # For the Time band, this is the center frequency, tuning frequency and mode: bandTime = [ ( 2500000-10000, 10000, 'AM'), ( 3330000-10000, 10000, 'AM'), ( 5000000-10000, 10000, 'AM'), ( 7335000-10000, 10000, 'AM'), (10000000-10000, 10000, 'AM'), (14670000-10000, 10000, 'AM'), (15000000-10000, 10000, 'AM'), (20000000-10000, 10000, 'AM'), ] # This is the list of band buttons that Quisk displays, and it should have # a length of 14 or less. Empty buttons can have a null string "" label. # Note that the 60 meter band and the Time band have buttons that support # multiple presses. bandLabels = ['Audio', '160', '80', ('60',) * 5, '40', '30', '20', '17', '15', '12', '10', ('Time',) * len(bandTime)] # If you get your I/Q samples from a sound card, you will need to correct the # amplitude and phase for inaccuracies in the analog hardware. The data is # entered using the controls from the "Rx Phase" button on the config screen. # The corrections are saved by the persistent_state feature. # # The available range of the amplitude and phase controls for receive: rx_max_amplitude_correct = 0.2 # Correction relative to 1.000000 (ideally 0.0000) rx_max_phase_correct = 10.0 # Correction in degrees of phase (ideally 0.0000) # # The bandAmplPhase dictionary gives the amplitude and phase corrections for # sound card data. The format is a dictionary with key "band", giving a dictionary # with key "rx" or "tx", giving a list of tuples (VFO, tune, amplitude, phase). # # If you use Quisk as a panadapter, the corrections will not depend on the band. # In that case create a band "panadapter" in your config file, and all corrections # will be read/written to that band. bandAmplPhase = {} # Empty dictionary to start #bandAmplPhase = {'panadapter':{}} # Create "panadapter" band for all corrections # The program polls the soundcard or SDR-IQ for data every data_poll_usec microseconds. # A lower time reduces latency; a higher time is less taxing on the hardware. if sys.platform == "win32": data_poll_usec = 20000 # poll time in microseconds else: data_poll_usec = 5000 # poll time in microseconds # The fft_size is the width of the data on the screen (about 800 to # 1200 pixels) times the fft_size_multiplier. Multiple FFTs are averaged # together to achieve your graph refresh rate. If fft_size_multiplier is # too small you will get many fft errors. You can specify fft_size_multiplier, # or enter a large number (use 9999) to maximize it, or enter zero to let # quisk calculate it for you. Look for fft_size_multiplier in quisk.py. # If your hardware can change the decimation, there are further compilcations. # The FFT size is fixed, and only the average count can change to adjust the # refresh rate. fft_size_multiplier = 0 # The graph_refresh is the frequency at which the graph is updated, # and should be about 5 to 10 Hertz. Higher rates require more processor power. graph_refresh = 7 # update the graph at this rate in Hertz # latency_millisecs determines how many samples are in the soundcard play buffer. # A larger number makes it less likely that you will run out of samples to play, # but increases latency. It is OK to suffer a certain number of play buffer # underruns in order to get lower latency. latency_millisecs = 150 # latency time in milliseconds # Select the method to test the state of the key; see is_key_down.c key_method = "" # No keying, or internal method # key_method = "/dev/parport0" # Use the named parallel port # key_method = "/dev/ttyS0" # Use the named serial port # key_method = "192.168.1.44" # Use UDP from this address # If you are using keying, key-down throws away the current capture buffer # and starts a sidetone with a rise time of 5 milliseconds. For # key-up, the sidetone is ended with a fall time of 5 milliseconds, then # a silent period starts, then normal audio starts with a rise time of # 5 milliseconds. The length of the silent period is given by keyupDelay, # but will be at least the time necessary to collect enough samples to # refill the filters. A larger keyupDelay may be needed to accomodate # antenna switching or other requirement of your hardware. keyupDelay = 23 # extra milliseconds silence on key up # This is a tuning parameter for the AGC. It controls the maximum AGC gain and thus # the scale of the AGC slider control. It depends on your sample magnitudes. agc_max_gain = 15000.0 # This controls the audio gain when AGC is off. It depends on your sample magnitudes. # Reduce it if turning off the AGC makes the sound too loud. agc_off_gain = 1400.0 # This is the AGC release time. It must be greater than zero. agc_release_time = 0.3 # For FM transmit, this is the modulation index. modulation_index = 1.67 quisk-3.6.11/quisk.h0000666000175000017500000002044012132073651013627 0ustar jimjim00000000000000 #define DEBUG_IO 0 // Sound parameters // #define QUISK_SC_SIZE 128 #define QUISK_PATH_SIZE 256 // max file path length #define IP_SIZE 32 #define MAX_FILTER_SIZE 10001 #define BIG_VOLUME 2.2e9 #define CLOSED_TEXT "The sound device is closed." #define CLIP32 2147483647 #define CLIP16 32767 #define SAMP_BUFFER_SIZE 66000 // size of arrays used to capture samples #define IMD_TONE_1 1200 // frequency of IMD test tones #define IMD_TONE_2 1600 #define INTERP_FILTER_TAPS 85 // interpolation filter #define MIC_OUT_RATE 48000 // mic post-processing sample rate // Test the audio: 0 == No test; normal operation; // 1 == Copy real data to the output; 2 == copy imaginary data to the output; // 3 == Copy transmit audio to the output. #define TEST_AUDIO 0 struct sound_dev { // data for sound capture or playback device char name[QUISK_SC_SIZE]; // string name of device void * handle; // Handle of open device, or NULL void * buffer; // Handle of buffer for device int portaudio_index; // index of portaudio device, or -1 int doAmplPhase; // Amplitude and Phase corrections double AmPhAAAA; double AmPhCCCC; double AmPhDDDD; double portaudio_latency; // Suggested latency for portaudio device int sample_rate; // Sample rate such as 48000, 96000, 192000 int sample_bytes; // Size of one channel sample in bytes, either 2 or 3 or 4 int num_channels; // number of channels per frame: 1, 2, 3, ... int channel_I; // Index of I and Q channels: 0, 1, ... int channel_Q; int channel_Delay; // Delay this channel by one sample; -1 for no delay, else channel_I or _Q int overrange; // Count for ADC overrange (clip) for device int read_frames; // number of frames for read request int latency_frames; // desired latency in audio play samples int play_buf_size; // size of playback buffer in samples int use_float; // DirectX: Use IEEE floating point int dataPos; // DirectX: data position int oldPlayPos; // DirectX: previous value of playPos int play_delay; // DirectX: bytes of sound available to play int started; // DirectX: started flag or state int dev_error; // read or write error int dev_underrun; // lack of samples to play int dev_latency; // latency frames unsigned int rate_min; // min and max available sample rates unsigned int rate_max; unsigned int chan_min; // min and max available number of channels unsigned int chan_max; complex dc_remove; // filter to remove DC from samples double save_sample; // Used to delay the I or Q sample char msg1[QUISK_SC_SIZE]; // string for information message } ; struct sound_conf { char dev_capt_name[QUISK_SC_SIZE]; char dev_play_name[QUISK_SC_SIZE]; int sample_rate; // Input sample rate from the ADC int playback_rate; // Output play rate to sound card int data_poll_usec; int latency_millisecs; unsigned int rate_min; unsigned int rate_max; unsigned int chan_min; unsigned int chan_max; int read_error; int write_error; int underrun_error; int overrange; // count of ADC overrange (clip) for non-soundcard device int latencyCapt; int latencyPlay; int interupts; char msg1[QUISK_SC_SIZE]; char err_msg[QUISK_SC_SIZE]; // These parameters are for the microphone: char mic_dev_name[QUISK_SC_SIZE]; // capture device char name_of_mic_play[QUISK_SC_SIZE]; // playback device char mic_ip[IP_SIZE]; int mic_sample_rate; // capture sample rate int mic_playback_rate; // playback sample rate int tx_audio_port; int mic_read_error; int mic_channel_I; // channel number for microphone: 0, 1, ... int mic_channel_Q; double mic_out_volume; } ; enum quisk_rec_state { IDLE, RECORD, PLAYBACK } ; extern enum quisk_rec_state quisk_record_state; extern struct sound_conf quisk_sound_state, * pt_quisk_sound_state; extern int mic_max_display; // display value of maximum microphone signal level extern int data_width; extern int quisk_using_udp; // is a UDP port used for capture (0 or 1)? extern int rxMode; // mode CWL, USB, etc. extern int quisk_tx_tune_freq; // Transmit tuning frequency as +/- sample_rate / 2 extern PyObject * quisk_pyConfig; // Configuration module instance extern long quisk_mainwin_handle; // Handle of the main window extern double quisk_mic_preemphasis; // Mic preemphasis 0.0 to 1.0; or -1.0 extern double quisk_mic_clip; // Mic clipping; try 3.0 or 4.0 extern int quisk_noise_blanker; // Noise blanker level, 0 for off extern int quisk_sidetoneCtrl; // sidetone control value 0 to 1000 extern double quisk_audioVolume; // volume control for radio sound playback, 0.0 to 1.0 extern PyObject * quisk_set_spot_level(PyObject * , PyObject *); extern PyObject * quisk_get_tx_filter(PyObject * , PyObject *); extern PyObject * quisk_set_ampl_phase(PyObject * , PyObject *); extern PyObject * quisk_capt_channels(PyObject * , PyObject *); extern PyObject * quisk_play_channels(PyObject * , PyObject *); extern PyObject * quisk_micplay_channels(PyObject * , PyObject *); extern PyObject * quisk_sound_devices(PyObject * , PyObject *); extern PyObject * quisk_sound_errors(PyObject *, PyObject *); extern PyObject * quisk_set_file_record(PyObject *, PyObject *); // These function pointers are the Start/Stop/Read interface for // the SDR-IQ and any other C-language extension modules that return // radio data samples. typedef void (* ty_sample_start)(void); typedef void (* ty_sample_stop)(void); typedef int (* ty_sample_read)(complex *); void quisk_open_sound(void); void quisk_close_sound(void); int quisk_process_samples(complex *, int); void quisk_play_samples(double *, int); void quisk_play_zeros(int); void quisk_start_sound(void); int quisk_get_overrange(void); void quisk_mixer_set(char *, int, double, char *, int); int quisk_read_sound(void); int quisk_process_microphone(int, complex *, int); void quisk_open_mic(void); void quisk_close_mic(void); int quisk_open_key(const char *); void quisk_close_key(void); int quisk_is_key_down(void); void quisk_set_key_down(int); int quisk_read_rx_udp(complex *); void quisk_set_tx_mode(void); void ptimer(int); int quisk_extern_demod(complex *, int, double); void quisk_tmp_microphone(complex *, int); int quisk_read_alsa(struct sound_dev *, complex *); void quisk_play_alsa(struct sound_dev *, int, complex *, int, double); void quisk_start_sound_alsa(struct sound_dev **, struct sound_dev **); void quisk_close_sound_alsa(struct sound_dev **, struct sound_dev **); int quisk_read_portaudio(struct sound_dev *, complex *); void quisk_play_portaudio(struct sound_dev *, int, complex *, int, double); void quisk_start_sound_portaudio(struct sound_dev **, struct sound_dev **); void quisk_close_sound_portaudio(void); /* Functions defined below this point are available for export to other extension modules using the standard Python CObject or Capsule interface. See the documentation in import_quisk_api.c. Note that index zero is used for a structure pointer, not a function pointer. To add a function, declare it twice, use the next array index, and add it to QUISK_API_INIT. Be very careful; here be dragons! */ #ifdef IMPORT_QUISK_API // For use by modules that import the _quisk symbols extern void ** Quisk_API; // array of pointers to functions and variables from module _quisk int import_quisk_api(void); // used to initialize Quisk_API #define QuiskGetConfigInt (*( int (*) (const char *, int) )Quisk_API[1]) #define QuiskGetConfigDouble (*( double (*) (const char *, double) )Quisk_API[2]) #define QuiskGetConfigString (*( char * (*) (const char *, char *) )Quisk_API[3]) #define QuiskTimeSec (*( double (*) (void) )Quisk_API[4]) #define QuiskSleepMicrosec (*( void (*) (int) )Quisk_API[5]) #define QuiskPrintTime (*( void (*) (const char *, int) )Quisk_API[6]) #define quisk_sample_source (*( void (*) (ty_sample_start, ty_sample_stop, ty_sample_read) )Quisk_API[7]) #else // Used to export symbols from _quisk in quisk.c int QuiskGetConfigInt(const char *, int); double QuiskGetConfigDouble(const char *, double); char * QuiskGetConfigString(const char *, char *); double QuiskTimeSec(void); void QuiskSleepMicrosec(int); void QuiskPrintTime(const char *, int); void quisk_sample_source(ty_sample_start, ty_sample_stop, ty_sample_read); #define QUISK_API_INIT { \ &quisk_sound_state, &QuiskGetConfigInt, &QuiskGetConfigDouble, &QuiskGetConfigString, &QuiskTimeSec, \ &QuiskSleepMicrosec, &QuiskPrintTime, &quisk_sample_source \ } #endif quisk-3.6.11/WinEdit.pyw0000644000175000017500000000437411632372222014432 0ustar jimjim00000000000000#!/usr/bin/python import wx from wx import py from wx import stc import os, sys, webbrowser # Change to the directory of quisk.py. os.chdir(os.path.normpath(os.path.dirname(__file__))) # Command line parsing: be able to specify the config file. from optparse import OptionParser parser = OptionParser() parser.add_option('-c', '--config', dest='config_file_path', help='Specify the configuration file path') parser.add_option('-e', '--edit', action='store_true', dest='edit', help='Edit the config file') parser.add_option('-d', '--defaults', action='store_true', dest='defaults', help='Show a window with the configuration defaults') parser.add_option('-r', '--docs', action='store_true', dest='docs', help='Show a window with the docs.html file') argv_options = parser.parse_args()[0] ConfigPath = argv_options.config_file_path # Get config file path if not ConfigPath: # Use default path; Duplicated from quisk.py if sys.platform == 'win32': ConfigPath = os.getenv('HOMEDRIVE', '') + os.getenv('HOMEPATH', '') ConfigPath = os.path.join(ConfigPath, "My Documents") ConfigPath = os.path.join(ConfigPath, "quisk_conf.py") if not os.path.isfile(ConfigPath): # See if the user has a config file try: import shutil # Try to create an initial default config file shutil.copyfile('quisk_conf_win.py', ConfigPath) except: pass else: ConfigPath = os.path.expanduser('~/.quisk_conf.py') class EditApp(wx.App): def __init__(self): wx.App.__init__(self, redirect=False) def OnInit(self): wx.InitAllImageHandlers() frame = None if argv_options.defaults: frame = py.editor.EditorFrame(filename="quisk_conf_defaults.py") frame.editor.window.SetReadOnly(True) frame.SetTitle("Configuration defaults quisk_conf_defaults.py") frame.Show() if argv_options.edit: frame = py.editor.EditorFrame(filename=ConfigPath) frame.SetTitle(ConfigPath) frame.Show() if argv_options.docs: webbrowser.open("docs.html", new=2) if frame: self.SetTopWindow(frame) return True def main(): app = EditApp() app.MainLoop() if __name__ == '__main__': main() quisk-3.6.11/dxcluster.py0000664000175000017500000000707712152462067014727 0ustar jimjim00000000000000# This code was contributed by Christof, DJ4CM. Many Thanks!! import threading import time import telnetlib import quisk_conf_defaults as conf class DxEntry(): def __init__(self): self.info = [] def getFreq(self): return self.freq def getDX(self): return self.dx def getSpotter(self, index): return self.info[index][0] def getTime(self, index): return self.info[index][1] def getLocation(self, index): return self.info[index][2] def getComment(self, index): return self.info[index][3] def getLen(self): return len(self.info) def equal(self, element): if element.getDX() == self.dx: return True else: return False def join (self, element): for i in range (0, len(element.info)): self.info.insert(0, element.info[i]) length = len(self.info) # limit to max history if length > 3: del (self.info[length-1]) self.timestamp = max (self.timestamp, element.timestamp) def isExpired(self): return time.time()-self.timestamp > conf.dxClExpireTime * 60 def parseMessage(self, message): words = message.split() sTime = '' locator = '' comment = '' if len(words) > 3 and words[0].lower() == 'dx' and words[1].lower() == 'de': spotter = words[2].strip(':') self.freq = int(float(words[3])*1000) self.dx = words[4] for index in range (5, len(words)): word = words[index] try: if sTime != '': locator = word.strip('\07') #search time if word[0:3].isdigit() and word[4].isalpha(): sTime = word.strip('\07') sTime = sTime[0:2]+':'+sTime[2:4]+ ' UTC' if sTime == '': if comment != '': comment += ' ' comment += word except: pass self.info.insert(0, (spotter, sTime, locator, comment)) self.timestamp = time.time() #print(self.dx, self.freq, spotter, sTime, locator, comment) return True return False class DxCluster(threading.Thread): def __init__(self): self.do_init = 1 threading.Thread.__init__(self) self.doQuit = threading.Event() self.dxSpots = [] self.doQuit.clear() def run(self): self.telnetInit() self.telnetConnect() while not self.doQuit.isSet(): try: self.telnetRead() except: self.tn.close() time.sleep(20) if not self.doQuit.isSet(): self.telnetConnect() self.tn.close() def setListener (self, listener): self.listener = listener def telnetInit(self): self.tn = telnetlib.Telnet() def telnetConnect(self): self.tn.open(conf.dxClHost, conf.dxClPort, 10) self.tn.read_until('login:', 10) self.tn.write(conf.user_call_sign + "\n") if conf.dxClPassword: self.self.tn.read_until("Password: ") self.tn.write(conf.dxClPassword + "\n") def telnetRead(self): message = self.tn.read_until('\n', 60).decode(encoding='utf-8', errors='replace') if self.doQuit.isSet() == False: dxEntry = DxEntry(); if dxEntry.parseMessage(message): for i, listElement in enumerate(self.dxSpots): if (listElement.equal(dxEntry)): listElement.join (dxEntry) return if listElement.isExpired(): del (self.dxSpots[i]) self.dxSpots.append(dxEntry) if self.listener: self.listener() def getHost(self): return self.tn.host + ':' + str(self.tn.port) def stop(self): self.doQuit.set() quisk-3.6.11/help_vna.html0000666000175000017500000001556211715514574015027 0ustar jimjim00000000000000 QUISK Help File

Quisk VNA Help (February 2012)

This is the Help file for Quisk VNA, a program that turns the Quisk2010 and HiQSDR transceiver hardware into a Vector Networ Analyzer (VNA). This Help appears when you press the Help button. Quisk is written by Jim Ahlstrom, N2ADR, www.james.ahlstrom.name. Mail to jahlstr at gmail.com.  To run the Quisk VNA program, use "python quisk_vna.py" or set up a shortcut.  This program only works with my hardware that is based on UDP.  It does not work with SoftRock hardware.

You need to update your firmware to Version 1.3 or later.  The new firmware locks the phase of the RF output to the phase of the RF detector.  There is a time delay in the path, but this is removed by the calibration proceedure.  The calibration graphs will show a linear phase change with frequency due to this delay.

There are two ways to use your hardware.  You could connect the RF output through attenuators, through a device under test and then back to the RF input.  This is called transmission mode.  It is used to plot the response of filters and to measure the electrical length of cables.  Or you could connect the RF input and output to a resistive return loss bridge.  This is called reflection mode.  It is used to measure SWR and impedance.  You must choose a mode and calibrate for that mode and hardware before you take any data.

The hardware generates RF output only when one of the "Calibrate" buttons or the "Run" button is turned on.  When calibrating, press the calibration button and wait for the screen to show a steady trace.  Then press it again to turn the RF off before changing cables.  The calibration routines save data every 15 kHz from zero to sixty megahertz.  You can change the measurement frequency span at any time without recalibration.  Although you can set a frequency span up to sixty megahertz, my original hardware has a low pass filter cutoff of 35 megahertz, so the upper frequency range is smaller and will appear noisy.

Since the transmit and receive frequencies are equal, the data is at DC, and is averaged and effectively low pass filtered.  This provides immunity from interference when measuring an antenna.

Input Protection

Do not connect the RF output to the RF input without inserting attenuators.  The output will overload the input and result in clipping in the ADC and possible damage.  If your device under test is an amplifier be especially careful to add additional attenuation to avoid damage.  Add enough attenuation to avoid clipping, but not so much that you lose dynamic range.  The calibration screens show the ADC level.  These attenuators also help to stabilize the input and output impedance and increase accuracy.  I use the HAT series of attenuators from Mini-Circuits.

Thansmission Mode

You must perform a calibration before you can take data.  First set the mode to "Trans" and leave it there.  Connect attenuators and a cable between the RF input and output.  Press "Cal Remove" to remove any prior calibration data, then press "Cal Short".  The screeen will show the voltage and phase at the input.  You can remove the cable and press "Cal Open" to correct for signal leakage, but this is optional.  With the cable connected, press "Run" and you should see a flat line at zero dB level and zero phase.  Now insert your test device in series.  The test device could be a filter, an amplifier (be careful) or an additional length of cable.  You can press "Run" again to stop taking data, and the most recent data will be retained.

Reflection Mode

This mode is used with a resistive return loss bridge.  Connnect the RF output to the generator terminal, and the RF input to the detector terminal.  Use attenuators as required.   You must perform a calibration before you can take data.  First set the mode to "Refl" and leave it there.  Press "Cal Remove" to remove any prior calibration data.  Connect an open circuit (or nothing) to the impedance terminal of the bridge, and then press "Cal Open".  Connect a short circuit to the bridge, and then press "Cal Short".  Connect a 50 ohm termination to the bridge and then press "Cal Load".

If you do not have a set of Open/Short/Load standards, you can just leave the connector open and use "Cal Open" alone.  Using "Cal Load" will attempt a baseline correction, but this requires all three calibrations be used.  So your calibration options are: Open; both Open and Short; or all three.

Connect a 50 ohm termination to the bridge, and press "Run".  The graph will show the magnitude and phase of the reflection coefficient, and the return loss is the drop in magnitude below zero dB.  Ideally your bridge will have a directivity of 30 dB or more.  The phase may be noisy if the magnitude is very small.  Now connect an unknown impedance to the bridge; for example, an antenna.  The graph will plot the return loss, reflection coefficient and SWR.  The status line will display the impedance and the equivalant capacitance or inductance.

You can attach any impedance, such as an unknown capacitor or inductor, and read the value directly.  The value may seem to vary with frequeny due to stray inductance, variation of permeability with frequency, and bridge imperfections; so choose a reference frequency wisely.  Remember that the bridge measures the impedance relative to fifty ohms, so accuracy suffers if the impedance is outside the range of 5 to 500 ohms or so.

Fun

In transmission mode, add an extra length of cable and see the phase change.  When the phase change is ninety degrees, that is a quarter wave.  The effect of velocity factor is included, and can be measured.  Use a bare wire (with attenuators) as the test fixture, and then add a ferrite bead to the wire to measure its properties.  Insert a filter to see its response.

In reflection mode, measure your antenna from zero to sixty megahertz.  If it is a dipole, you will see the drop in SWR at its third harmonic.  Add a cable to the bridge to see its impedance at a quarter and half wave length.  Measure the length of your transmission line by replacing your antenna with a 100 ohm resister.  The bridge will read 100 ohms at multiples of a half wavelength.  If you short out your antenna at the far end of your transmission line, the bridge will read zero at half wavelengths, and infinity at quarter wavelengths.
quisk-3.6.11/quisk_conf_peaberry.py0000664000175000017500000000053112136751464016734 0ustar jimjim00000000000000from softrock import hardware_usb_new as quisk_hardware from softrock import widgets_tx as quisk_widgets si570_direct_control = True si570_xtal_freq = 114211833 sample_rate = 48000 playback_rate = 48000 name_of_sound_capt = "hw:1,0" name_of_sound_play = "plughw:0,0" channel_i = 0 channel_q = 1 usb_vendor_id = 0x16c0 usb_product_id = 0x05dc